自定义安卓函数曲线图控件

效果图:

实现源码:

/**
 * 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;
	}

}
时间: 2024-10-02 16:29:40

自定义安卓函数曲线图控件的相关文章

使用VideoView自定义一个播放器控件

介绍 最近要使用播放器做一个简单的视频播放功能,开始学习VideoView,在横竖屏切换的时候碰到了点麻烦,不过在查阅资料后总算是解决了.在写VideoView播放视频时候定义控制的代码全写在Actvity里了,写完一看我靠代码好乱,于是就写了个自定义的播放器控件,支持指定大小,可以横竖屏切换,手动左右滑动快进快退.好了,下面开始. 效果图 效果图有点卡,我也不知道为啥..... VideoView介绍 这个是我们实现视频播放最主要的控件,详细的介绍大家百度就去看,这里介绍几个常用的方法. 用于

android - 自定义(组合)控件 + 自定义控件外观

转载:http://www.cnblogs.com/bill-joy/archive/2012/04/26/2471831.html android - 自定义(组合)控件 + 自定义控件外观 Android自定义View实现很简单 继承View,重写构造函数.onDraw,(onMeasure)等函数. 如果自定义的View需要有自定义的属性,需要在values下建立attrs.xml.在其中定义你的属性. 在使用到自定义View的xml布局文件中需要加入xmlns:前缀="http://sc

自定义下拉刷新控件

一.功能效果 1.在很多app中,在信息展示页面,当我们向下拖拽时,页面会加载最新的数据,并有一个短暂的提示控件出现,有些会有加载进度条,有些会记录加载日期.条目,有些还带有加载动画.其基本实现原理都相仿,本文中将探讨其实现原理,并封装出一个简单的下拉刷新控件 2.自定义刷新工具简单的示例 二.系统提供的下拉刷新工具 1.iOS6.0以后系统提供了自己的下拉刷新的控件:UIRefreshControl .例如,refreshControl,作为UITableViewController中的一个属

自定义快速查找字母控件

效果图如下: 首先看看布局文件,自定义的控件中包含一个 ListView,用于显示具体的数据内容: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="fill_parent"     a

获取 AlertDialog自定义的布局 的控件

AlertDialog自定义的布局 效果图: 创建dialog方法的代码如下: 1 LayoutInflater inflater = getLayoutInflater(); 2 View layout = inflater.inflate(R.layout.dialog, 3 (ViewGroup) findViewById(R.id.dialog)); 4 new AlertDialog.Builder(this).setTitle("自定义布局").setView(layout

关于UITableView选中效果以及自定义cell上的控件响应事件

tableView默认的点击效果是:点击cell:A,出现点击效果,点另一个cell:B的时候,A的点击效果才会消失. 1.对于tableView,比较常用的效果,是点击表格行,出现效果,点击完毕,效果消失 那么就要在代码里做一些设置.代码如下: -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath

安卓,网页控件,显示网页 Android, web controls, display web pages

安卓,网页控件,显示网页Android, web controls, display web pages 作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱:[email protected] E-mail: 313134555 @qq.com mWebView.loadUrl("https://zhuanlan.zhihu.com/p/28275732"); mWebView.getSettings().setJavaScriptEnabled(true); mWe

自定义数字加减控件

1_自定义数字加减控件的要求 创建Module -NumberAddSubView A_输入的只能是数字,而且不能通过键盘输入 B_通过加减按钮操作数字 C_监听加减按钮 D_数组有最小值和最大值的限制 E_自定义属性 2.提供接口,让外界监听到数字的变化 1_设置接口 @Override public void onClick(View v) { if (v.getId() == R.id.btn_sub) { //Toast.makeText(mContext,"减",Toast.

Android自定义View之组合控件 ---- LED数字时钟

先上图 LEDView效果如图所示. 之前看到一篇博客使用两个TextView实现了该效果,于是我想用自定义控件的方式实现一个LEDView,使用时即可直接使用该控件. 采用组合控件的方式,将两个TextView叠放在一起,再使用digital-7.ttf字体来显示数据,从而达到LED的效果.代码如下: LEDView.class package ione.zy.demo; import java.io.File; import java.util.Calendar; import java.u