初始:
最近在看《Android群英传》一书,代码自己敲了一遍,想想之前敲了又忘记的惨痛经历,决定在博客上记录自己敲的代码,有几个写几篇,放在一个系列里边,就这样,以后看就能一下子找到了。
自定义View
自定义View我们大致可以从是三个方面着手:
(1)对现有的控件进行扩展
(2)通过组合实现全新的控件
(3)重写View来实现全新的
没怎么汇总,用到什么知识就注解解释了。
对现有的控件进行扩展
基于TextView,绘制边框和背景颜色
关于Paint和Canvas,他们就相当于画画时候的画笔和画板,没有他们我们就不能改变任何东西。
/**
* 基于已有空间上进行修改
* 写一个TextView 绘制边框 绘制背景颜色
* @author fanshenxia
* 一个自定义类继承TextView 重写构造方法
*/
public class MyTextView extends TextView{
private Paint mPaint,mPaint2;
//这个不太清楚,重写了就重写了
public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
//这个构造用于xml文件中的构造
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
//这个构造方法用于在代码中定义控件
public MyTextView(Context context) {
super(context);
init();
}
/**
* 初始化画笔
*/
private void init() {
//实例化画笔
mPaint = new Paint();
//设置画笔颜色
mPaint.setColor(Color.CYAN);
//设置它的填充方法,用的多的是FILL 和 STORKE
mPaint.setStyle(Paint.Style.FILL);
mPaint2 = new Paint();
mPaint2.setColor(Color.LTGRAY);
mPaint2.setStyle(Style.FILL);
}
/**
* 重写onDraw方法 可以在绘制文字前后进行一些自己的操作
* super.onDraw(canvas);调用父类方法绘制文字
* 如果绘制矩形的代码写在它的后边,文字就会被覆盖
*/
@Override
protected void onDraw(Canvas canvas) {
//在回调父类方法之前,对TextView来说是绘制文本内容之前
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
//绘制里层矩形 参数:左、上、右、下、画笔
//除了绘制矩形,用的多的还可以绘制线,圆,扇形,Path等
canvas.drawRect(10, 10, getMeasuredWidth()-10, getMeasuredHeight()-10, mPaint2);
super.onDraw(canvas);
//绘制文本之后
}
}
XML中MyTextView内容:
<custom.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:padding="10dp"
android:text="我是自定义的控件哦~"
android:textSize="20sp"
android:visibility="visible" >
custom.MyTextView>
总结:可以看到,上述xml中TextView的相关属性保留着,我们没有自定义其他的任何属性,只是添加了边框和背景。 自定义属性在下边呢~
通过组合来实现新的控件
这个应该用过吧,平时如果UI给我们的原型图有好多地方搜索框都是一样的,我们会自定义一个控件,将它的大体布局写好,到用的地方就不用一次一次的写了。
这个简单,我没写代码,以后把它补上。
自定义全新的View
这里实现了三个自定义View,一个条形图,一个钟表绘制,一个百分比图。先说条形图。
/**
* 自定义条形图
*
* @author fanshenxia
*
*/
public class MyBarChartView extends View {
private Context mContext;
// 柱状的数值
private int mNum = 15;
private Paint mPaint;
public MyBarChartView(Context context) {
super(context);
this.mContext = context;
init();
}
public MyBarChartView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
init();
}
public MyBarChartView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
init();
}
private void init() {
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(2);
mPaint.setAntiAlias(true);
mPaint.setStyle(Style.FILL);
}
/**
重写onMeasure()方法重新测量控件的宽高
测量方式有三种
MeasureSpec.EXACTLY:相当xml中控件layout_width="match_parent/固定XXdp"
MeasureSpec.AT_MOST:想当wrap_content,它不能大于父控件的宽/高
MeasureSpec.UNSPECIFIED:不指定其大小测量模式,View想多大就多大,一般用于自定义View
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
}
private int measureWidth(int measureSpec) {
int result = 300;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// 指定数值或者match_parent
result = specSize;
} else if (specMode == MeasureSpec.AT_MOST) {
// 为warp_content时
result = Math.min(result, specSize);
} else {
// view想多大就多大
result = 300;
}
return result;
}
private int measureHeight(int measureSpec) {
int result = 400;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// 指定数值或者match_parent
result = specSize;
} else if (specMode == MeasureSpec.AT_MOST) {
// 为warp_content时
result = Math.min(result, specSize);
} else {
// view想多大就多大
result = 400;
}
return result;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
int rectWidth = (width - 60) / mNum - 20;
// 绘制坐标线
canvas.drawLine(20, 20, 20, height - 20, mPaint);
canvas.drawLine(getWidth() - 20, getHeight() - 20, 20, getHeight() - 20, mPaint);
int min = 50;
int max = getHeight()-50;
Random random = new Random();
int num = random.nextInt(max) % (max - min + 1) + min;
// 绘制柱体 这里给的值不是很逻辑的,用的时候需要自己计算后给出相应的值。
for (int i = 0; i < mNum; i++) {
canvas.drawRect(20 + rectWidth * i + 20 * (i + 1), num, 20 + rectWidth * (i + 1) + 20 * (i + 1),
getHeight() - 20, mPaint);
num = random.nextInt(max) % (max - min + 1) + min;
}
//延时重绘,让条形图每1s刷新一次,它走这个方法时 ,只会执行onDraw方法 init那些不执行,Paint的颜色值等都会保留
postInvalidateDelayed(1*1000);
}
}
xml布局:
<custom.MyBarChartView
android:id="@+id/myBarChartView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
效果: