文档章节

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

lanfogz
 lanfogz
发布于 2015/06/26 09:34
字数 720
阅读 119
收藏 1
点赞 0
评论 0


效果图:



实现源码:

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



© 著作权归作者所有

共有 人打赏支持
lanfogz
粉丝 2
博文 18
码字总数 29273
作品 0
南京
程序员
android--------自定义控件 之 方法篇

前面简单的讲述了Android中自定义控件的理论和流程图,今天通过代码来详细的讲解一下其中的方法 首先先创建一个类 CircularView 继承于 View,之后实现构造方法(初始化步骤) View的构造函数...

切切歆语 ⋅ 05/01 ⋅ 0

android--------自定义控件 之 基本实现篇

前面简单的讲述了Android中自定义控件中的几个方法,今天通过代码来实现一个简单的案例 自定义一个扇形图 自定义控件示例: 这里先介绍继承View的方式为例 在布局中如何使用 我用了两种模式,...

切切歆语 ⋅ 05/02 ⋅ 0

Android自定义View全解

目录 1. 自定义View基础 1.1 分类 自定义View的实现方式有以下几种 1.2 View绘制流程 View的绘制基本由measure()、layout()、draw()这个三个函数完成 1.3 坐标系 在Android坐标系中,以屏幕左...

銀灬楓 ⋅ 05/10 ⋅ 0

安卓开发之基于AccessibilityService实现聊天机器人对其他应用的调起

前言 前几天看到一个很有趣的应用视频“小不点”交互机器人,其中有一段是用户给它发一段文字/语音,譬如“我想在美团点一份鸡排”,然后“小不点”自动将美团应用弹出,并进行“鸡排”搜索等...

cxmscb ⋅ 2016/10/27 ⋅ 0

Android开发权威指南(第2版)新书发布

《Android开发权威指南(第二版)》是畅销书《Android开发权威指南》的升级版,内容更新超过80%,是一本全面介绍Android应用开发的专著,拥有45章精彩内容供读者学习。  《Android开发权威指...

androidguy ⋅ 2013/09/05 ⋅ 0

android--------自定义控件 之 基本流程篇

在我们平常的Android开发中经常和控件打交道,有时Android提供的控件未必能满足业务的需求,这个时候就需要我们实现自定义一些控件 自定义控件可以设计出很多你想要的功能和模块,在开发中是...

切切歆语 ⋅ 04/30 ⋅ 0

android悬浮窗、收款二维码、相机处理、事件通知库、NFC读取等源码

Android精选源码 一个漂亮而强大的自定义view SeekBar(http://www.apkbus.com/thread-598080-1-1.html) 适用于Android的简单NFC读取源码(http://www.apkbus.com/thread-598082-1-1.html) 安卓......

逆鳞龙 ⋅ 04/24 ⋅ 0

android--------自定义控件 之 属性篇

上篇介绍了自定义控件的一个简单案例,本篇文章主要介绍如何给自定义控件自定义一些属性。 Android 中使用自定义属性的一般步骤: 定义declare-styleable,添加attr 使用TypedArray获取自定义...

切切歆语 ⋅ 05/03 ⋅ 0

Android项目实战(三十八):2017最新 将AndroidLibrary提交到JCenter仓库(图文教程)

我们经常使用github上的开源项目,使用步骤也很简单 比如: compile 'acffo.xqx.xwaveviewlib:maven:1.0.0' 这里就学习一下如何将自己的类库做出这种可以供他人使用的开源项目。 一、Android...

听着music睡 ⋅ 2017/11/15 ⋅ 0

Android性能优化:那些不可忽略的绘制优化

前言 在 开发中,性能优化策略十分重要 本文主要讲解性能优化中的绘制优化,希望你们会喜欢。 目录 // 方式2:在 BaseActivity 的 onCreate() 方法中使用下面的代码移除 优化方案2:移除 控件...

Carson_Ho ⋅ 05/21 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Mahout推荐算法之SlopOne

一、 算法原理 有别于基于用户的协同过滤和基于item的协同过滤,SlopeOne采用简单的线性模型估计用户对item的评分。如下图,估计UserB对ItemJ的偏好 图(1) 在真实情况下,该方法有如下几个...

xiaomin0322 ⋅ 29分钟前 ⋅ 0

LVM讲解

LVM是什么 LVM是 Logical Volume Manager(逻辑卷管理)的简写,它是Linux环境下对磁盘分区进行管理的一种机制,Linux用户安装Linux操作系统时遇到的一个常见的难以决定的问题就是如何正确地...

李超小牛子 ⋅ 38分钟前 ⋅ 0

mysql更改密码、连接mysql、mysql常用命令

1. 更改mysql的root账户密码: mysql中root账户和系统root不是一个账户 1.1 更改环境变量PATH,增加mysql绝对路径 由于mysql安装目录为/usr/local/mysql/,所以系统不能直接使用mysql,需把/...

laoba ⋅ 40分钟前 ⋅ 0

阿里云发布企业数字化及上云外包平台服务:阿里云众包平台

摘要: 阿里云正式发布旗下众包平台业务(网址:https://zhongbao.aliyun.com/),支持包括:网站定制开发,APP、电商系统等软件开发,商标、商品LOGO、VI、产品包装设计、营销推广、大数据人...

猫耳m ⋅ 40分钟前 ⋅ 0

阿里云发布企业数字化及上云外包平台服务:阿里云众包平台

摘要: 阿里云正式发布旗下众包平台业务(网址:https://zhongbao.aliyun.com/),支持包括:网站定制开发,APP、电商系统等软件开发,商标、商品LOGO、VI、产品包装设计、营销推广、大数据人...

阿里云云栖社区 ⋅ 43分钟前 ⋅ 0

1.03-Maven中使用ueditor富文本编辑器

起因:在maven仓库未找到百度的ueditor的jar包 操作: 1.下载百度的ueditor的jar包 2.打开命令行,切换到ueditor的下载位置,运行一下命令: mvn install:install-file -Dfile=ueditor-1.1....

静以修身2025 ⋅ 49分钟前 ⋅ 0

几道Spring 面试题

1、BeanFactory 接口和 ApplicationContext 接口有什么区别? ApplicationContext 接口继承BeanFactory接口 Spring核心工厂是BeanFactory BeanFactory采取延迟加载,第一次getBean时才会初始...

职业搬砖20年 ⋅ 58分钟前 ⋅ 0

包饺子

http://storage.slide.news.sina.com.cn/slidenews/77_ori/2018_24/74766_826131_625489.gif

霜叶情 ⋅ 59分钟前 ⋅ 0

xml解析

方法一: String s_xml1 = "<xml>" + "<head>lalalalal</head>" + "<body>1234</body>" + "</xml>"; try { DocumentBuilderFactory documentBuilderFactory......

GithubXD ⋅ 今天 ⋅ 0

reuse stream

Although Java streams were designed to be operated only once, programmers still ask how to reuse a stream. From a simple web search, we can find many posts with this same issue ......

idoz ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部