刚开始接触Android时,看别人写的一个个自定义view感觉好牛逼,不甘落后的我自然也要学习下了,看到算法就头痛的我也只要硬着头皮上了,废话不说了,先来总结下自定义控件的基本步骤吧:
- 继承View完全自定义或继承View的派生子类
- 重写view的三个构造方法,在View的构造方法中获得我们自定义的属性
- 重写onDraw()进行绘图
一个最基本的自定义控件肯定是离不来以上三个步骤的,至于还有其他的需求就需要重写其他的方法了,下面我来介绍下几个常用的方法
onMeasure() :
这个方法是用在测量出view 的大小,根据测量view及其内容来确定view的宽度和高度。这个方法在measure(int, int)中被调用,必须被重写来精确和有效的测量view的内容,常用场景如测量listView的高度:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
这句话是什么意思呢,makeMeasureSpec(size,mode),size不用我多说意思就是最大值啦,AT_MOST模式指的就是最大值模式,但是不会超过父控件允许的范围
onMeasure() :
调用场景:在view给其孩子设置尺寸和位置时被调用。子view,包括孩子在内,必须重写onLayout(boolean, int, int, int, int)方法,并且调用各自的layout(int, int, int, int)方法。
参数说明:参数changed表示view有新的尺寸或位置;参数l表示相对于父view的Left位置;参数t表示相对于父view的Top位置;参数r表示相对于父view的Right位置;参数b表示相对于父view的Bottom位置。
onFinishInflate():
从xml加载主键后回调。意思就是说加载完xml就调用,可以初始化一些属性
onSizeChanged():
组件大小改变时调用,通常是在onMeasure()后面调用
onTouchEvent:
监听到触摸事件时回调
onDraw():
运行顺序如图:
对整个view的绘制方法全部在这个里面进行,这里就需要引入画布canvas以及paint画笔了,就好比画画,需要笔和纸是一样的。
canvas有很多好用的方法我就不一一说了,有兴趣的可以自己看,主要说说canvas的save(),restore():
save()顾名思义,有保存的意思,他的意思是保存前面代码的绘制,重新开一个画布
restore():合并画布的意思,就是把前面的画布合并到一块
还要说下:
incalidate():它代表手动调用onDraw();
下面上一个简单的自定义view,模仿音频条形图:
RectView:
package com.example.administrator.xclcharts;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import java.util.Timer;
import java.util.TimerTask;
/**
* Created by Administrator on 2016/1/19.
*/
public class RectView extends View {
private Paint paint;//画笔
private float textHeight;//字体高度
private float fontSize = getResources().getDimensionPixelSize(R.dimen.default_font_size);//字体大小
private float rectHeight;//矩形高度
private Double mRandom;//随机数
public RectView(Context context) {
super(context);
init();
}
private void init() {
paint = new Paint();
paint.setFlags(Paint.ANTI_ALIAS_FLAG);//设置为抗锯齿
paint.setTextSize(fontSize);//设置字体大小
//初始化textHeight
textHeight = fontSize;
}
public RectView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RectView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = canvas.getWidth();//画布的宽高
int height = canvas.getHeight();
// paint.setColor(Color.BLUE);
// canvas.drawText("11111111111", 100, 100, paint);
// canvas.save(); //左上角 右下角
// canvas.drawRect(100,100,200,200,paint);
// 画坐标y轴
canvas.drawLine(10, height-50, 10, 10, paint);
//画x轴
canvas.drawLine(10,height-50,width-10,height-50,paint);
canvas.save();
paint.setColor(Color.BLUE);
//画刻度
for (int i = 0; i<5;i++){
canvas.drawLine(10, height-50,40,height-50,paint);
//像y轴平移
canvas.translate(0,-(height-50)/5);
}
canvas.restore();
canvas.save();
paint.setColor(Color.BLUE);
//画刻度
for (int i = 0; i<5;i++){
canvas.drawLine(10,height-50,10,height-80,paint);
//像x轴平移
canvas.translate((width-10)/5,0);
}
canvas.restore();
canvas.save();
// // 画一个全白的矩形
// paint.setColor(Color.WHITE);
// canvas.drawRect(0,0,width,height,paint);
// canvas.save();
paint.setColor(Color.RED);
//单个矩形的宽度
int rectWidth =50;
//矩形间间距
int rectSpacing = 10;
//
// canvas.drawRect(20,50,20+rectWidth,height-50,paint);
// canvas.drawRect(20+rectWidth+rectSpacing,50,20+rectWidth+(rectWidth+rectSpacing),height-50,paint);
// canvas.drawRect(20+rectWidth+rectSpacing+(rectWidth+rectSpacing),50,20+rectWidth+(rectWidth+rectSpacing)+(rectWidth+rectSpacing),height-50,paint);
//随机比例
rectHeight = width;
Log.e("RcetView", "onDraw---------rectHeight:"+rectHeight);
for (int i =0;i<10;i++){
mRandom = Math.random();
Log.e("RectView", "width:" + width + "height:" + height+"mRandom"+mRandom);
rectHeight = (float) (rectHeight * mRandom);
canvas.drawRect(20 + (rectWidth + rectSpacing) * i, rectHeight, 20 + rectWidth + (rectWidth + rectSpacing) * i, height - 50, paint);
}
//postInvalidateDelayed(300);
// canvas.restore();
}
//测量
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Log.e("RectView","onMeasure--------");
}
//设置布局
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
Log.e("RectView", "onLayout--------");
}
//初始化大小,
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
Log.e("RcetView", "onSizeChanged---------"+"w:"+w+"h:"+h+"oldw:"+oldw+"oldh:"+oldh);
}
//xml加载完后执行
Timer timer;
@Override
protected void onFinishInflate() {
super.onFinishInflate();
Log.e("RcetView", "onFinishInflate---------");
timer=new Timer();
timer.schedule(task, 0, 1000);
}
TimerTask task=new TimerTask() {
@Override
public void run() {
mHandler.sendEmptyMessage(0);
}
};
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
invalidate();
}
};
}
代码比较乱。但是很简单,保留下,权当自学!自定义view水比较深,路漫漫其修远兮,只能慢慢来!
http://download.csdn.net/detail/wei8023hzp/9411885 下载地址