自定义安卓函数曲线图控件
博客专区 > lanfogz 的博客 > 博客详情
自定义安卓函数曲线图控件
lanfogz 发表于2年前
自定义安卓函数曲线图控件
  • 发表于 2年前
  • 阅读 109
  • 收藏 1
  • 点赞 0
  • 评论 0

腾讯云 技术升级10大核心产品年终让利>>>   

摘要: 实现一个用于绘制函数曲线图的控件


效果图:



实现源码:

/**
 * FunctionCurveView.java
 * @author Lanfog
 * @datetime a01b-6-ab下午b:38:01
 */
package me.lanfog.myandroid.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

/**
 * 函数曲线图
 */
public class CurveView extends View {

	private Paint mPaint;
	private CurveUnit mCurveUnit = new CurveUnit() {
		
		@Override
		public int getCenterY() {
			// TODO Auto-generated method stub
			return getHeight()/2;
		}
		
		@Override
		public int getCenterX() {
			// TODO Auto-generated method stub
			return getWidth()/2;
		}
		
		@Override
		public float function(float x) {
			// TODO Auto-generated method stub
			return (float) Math.sin(x);
		}
	};
	
	public CurveView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		// TODO Auto-generated constructor stub
		init();
	}

	public CurveView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
		init();
	}

	public CurveView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
		init();
	}
	
	private void init(){
		
		mPaint = new Paint();
		mPaint.setAntiAlias(true);
		mPaint.setStyle(Paint.Style.STROKE);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

		int measuredWidth = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
		int measuredHeight = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
		setMeasuredDimension(measuredWidth, measuredHeight);
	}

	@Override
	protected void onDraw(Canvas canvas) {

		int w = getWidth(); // 控件宽度
		int h = getHeight(); // 控件高度
		int p = mCurveUnit.getPadding(); // 控件内部填充
		
		int cx = mCurveUnit.getCenterX(); // 中心横坐标
		int cy = mCurveUnit.getCenterY(); // 中心纵坐标
		
		mPaint.setStrokeWidth(2);
		canvas.drawLine(p, cy, w - p, cy, mPaint);
		canvas.drawLine(cx, p, cx, h - p, mPaint);
		
		float pr = mCurveUnit.getPrecision(); // 刻度精度
		float sp = mCurveUnit.getSpacing(); // 刻度间隔
		float x, y;
		
		mPaint.setStrokeWidth(1);
		mPaint.setTextSize(12);
		
		int a = 3; // 短线刻度长度
		int b = 8; // 长线刻度长度
		
		// 中
		canvas.drawText("0", cx + 15, cy + 15, mPaint);
		
		// 左
		for(int i=-1;;i--){
			x = cx + i * sp;
			if(x < p) break;
			if(i % 5 == 0){ // 每5个刻度绘制一个数字
				canvas.drawLine(x, cy, x, cy - b, mPaint);
				canvas.drawText("" + i * pr, x, cy + 15, mPaint);
			}else
				canvas.drawLine(x, cy, x, cy - a, mPaint);
		}
		
		// 上
		for(int i=1;;i++){
			y = cy - i * sp;
			if(y < p) break;
			if(i % 5 == 0){
				canvas.drawLine(cx, y, cx + b, y, mPaint);
				canvas.drawText("" + i * pr, cx + 10, y, mPaint);
			}else
				canvas.drawLine(cx, y, cx + a, y, mPaint);
		}
		
		// 右
		for(int i=1;;i++){
			x = cx + i * sp;
			if(x > w - p) break;
			if(i % 5 == 0){
				canvas.drawLine(x, cy, x, cy - b, mPaint);
				canvas.drawText("" + i * pr, x, cy - 10, mPaint);
			}else
				canvas.drawLine(x, cy, x, cy - a, mPaint);
		}
		
		// 下
		for(int i=-1;;i--){
			y = cy - i * sp;
			if(y > h - p) break;
			if(i % 5 == 0){
				canvas.drawLine(cx, y, cx + b, y, mPaint);
				canvas.drawText("" + i * pr, cx + 10, y, mPaint);
			}else
				canvas.drawLine(cx, y, cx + a, y, mPaint);
		}
		
		mPaint.setColor(Color.RED);
		
		boolean s = false; // 是否为起始点
		float tx, ty; // 临时保存坐标点
		float lx = 0f, ly = 0f; // 上一次保存坐标点
		
		// 负
		for(int i=0;;i--){
			if(cx + i * sp < p) break;
			
			tx = x = i * pr;
			ty = y = mCurveUnit.function(x);
			x = cx + i * sp;
			y = cy - y / pr * sp;
			
			if(i % 10 == 0) // 每10个刻度绘制一个(x,y)值
				canvas.drawText("(" + String.format("%.2f", tx) + "," + String.format("%.2f", ty) + ")", x, y, mPaint);
			if(s)
				canvas.drawLine(lx, ly, x, y, mPaint);
			else 
				s = true;
			
			lx = x;
			ly = y;
		}
		
		s = false;
		
		// 正
		for(int i=0;;i++){
			if(cx + i * sp > w - p) break;
			
			tx = x = i * pr;
			ty = y = mCurveUnit.function(x);
			x = cx + i * sp;
			y = cy - y / pr * sp;
			
			if(i % 10 == 0)
				canvas.drawText("(" + String.format("%.2f", tx) + "," + String.format("%.2f", ty) + ")", x, y, mPaint);
			if(s)
				canvas.drawLine(lx, ly, x, y, mPaint);
			else 
				s = true;
			
			lx = x;
			ly = y;
		}
	}
	
	public static abstract class CurveUnit {
		
		/**
		 * 函数实现
		 */
		public abstract float function(float x);

		/**
		 * 获取中心的水平位置
		 */
		public abstract int getCenterX();

		/**
		 * 获取中心的垂直位置
		 */
		public abstract int getCenterY();

		/**
		 * 获取刻度精度
		 */
		public float getPrecision(){
			return 0.2f;
		}

		/**
		 * 获取刻度间隔
		 */
		public float getSpacing(){
			return 10f;
		}
		
		/**
		 * 获取内部填充
		 */
		public int getPadding(){
			return 5;
		}
	}

	public CurveUnit getCurveUnit() {
		return mCurveUnit;
	}

	public void setCurveUnit(CurveUnit mCurveUnit) {
		this.mCurveUnit = mCurveUnit;
	}
	
}



共有 人打赏支持
粉丝 3
博文 18
码字总数 29273
×
lanfogz
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: