本文转载是看了鸿洋大神的自定义view自己跟着写了一遍加上了一些注释。如果想更详细的了解请参考原文:http://blog.csdn.net/lmj623565791/article/details/24252901
1、自定义View的属性
2、在View的构造方法中获得我们自定义的属性
[ 3、重写onMesure ]
4、重写onDraw
我把3用[]标出了,所以说3不一定是必须的,当然了大部分情况下还是需要重写的。
1、自定义View的属性,首先在res/values/ 下建立一个attrs.xml , 在里面定义我们的属性和声明我们的整个样式。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomView">
<attr name="customText" format="string" />
<attr name="customTextColor" format="color" />
<attr name="customTextSize" format="dimension" />
</declare-styleable>
</resources>
我们定义了字体,字体颜色,字体大小3个属性,format是值该属性的取值类型:
一共有:string,color,demension,integer,enum,reference,float,boolean,fraction,flag;不清楚的可以google一把。
然后在布局中声明我们的自定义View
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<zdd.customview.hongyangview.CustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:padding="5dp"
app:customText="点我有惊喜"
app:customTextColor="#ff00ff"
app:customTextSize="40sp" />
</RelativeLayout>
一定要引入 xmlns:custom="http://schemas.android.com/apk/res/com.example.customview01"(这个我的不行。不知道原因)或者xmlns:app="http://schemas.android.com/apk/res-auto"
我们的命名空间,后面的包路径指的是项目的package
2、在View的构造方法中,获得我们的自定义的样式
package zdd.customview.hongyangview;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import zdd.customview.R;
/**
* Created by ZDD on 2016/7/28.
*/
public class CustomView extends View implements View.OnClickListener {
// 定义控件属性值
private String customText;
private int customTextColor;
private int customTextSize;
// 定义画笔
private Paint paint;
// 绘制矩形
private Rect rect;
public CustomView(Context context) {
this(context, null);
}
public CustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
// 获取到自定义属性的数量
int arrChild = array.getIndexCount();
for (int i = 0; i < arrChild; i++) {
// 获取到自定义属性的索引值
int child = array.getIndex(i);
switch (child) {
case R.styleable.CustomView_customText:
customText = array.getString(child);
break;
case R.styleable.CustomView_customTextColor:
customTextColor = array.getColor(child, 0);
break;
case R.styleable.CustomView_customTextSize:
customTextSize = (int) array.getDimension(child, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
break;
}
}
paint = new Paint();
// 设置文字大小
paint.setTextSize(customTextSize);
// 初始化矩形
rect = new Rect();
// 根据填充的数据返回rect的具体宽高 第一个参数是文字,第二个参数是从0开始绘制 第三个参数是到文字的结束停止绘制, 第四个是矩形
paint.getTextBounds(customText, 0, customText.length(), rect);
// 添加点击事件
setOnClickListener(this);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 获取到设置的宽度类型和大小
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
// 获取到设置的高度的类型和大小
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
// 定义宽高 记录宽高
int width = 0;
int height = 0;
// 重写之前先了解MeasureSpec的specMode,一共三种类型:
// EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
// AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
// UNSPECIFIED:表示子布局想要多大就多大,很少使用
if (widthMode == MeasureSpec.EXACTLY) {
// 如果设置的是match_parent
width = widthSize;
} else {
// 设置文字大小
paint.setTextSize(customTextSize);
// 将文字绘制到矩形上以便获取到宽高 第一个参数是文字,第二个参数是从0开始绘制 第三个参数是到文字的结束停止绘制, 第四个是矩形
paint.getTextBounds(customText, 0, customText.length(), rect);
// 获取到文字的宽度
float textWidth = rect.width();
// 将计算出的宽度告诉给屏幕
width = (int) (getPaddingLeft() + textWidth + getPaddingRight());
}
if (heightMode == MeasureSpec.EXACTLY) {
// 如果设置的是match_parent
height = heightSize;
} else {
// 设置文字大小
paint.setTextSize(customTextSize);
paint.getTextBounds(customText, 0, customText.length(), rect);
float textHeight = rect.height();
height = (int) (getPaddingTop() + textHeight + getPaddingBottom());
}
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
// 绘制背景色
paint.setColor(Color.YELLOW);
// 将背景色绘制到UI界面上 参数分别代表。左上右下的座标位置, 最后一个是画笔
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), paint);
// 绘制文字颜色
paint.setColor(customTextColor);
/**
* 将文字绘制到界面上
* 第一个参数是文字
* 第二个参数是x座标
* 第三个参数是y座标
* 第四个参数是画笔
*/
canvas.drawText(customText, getWidth() / 2 - rect.width() / 2, getHeight() / 2 + rect.height() / 2, paint);
}
@Override
public void onClick(View v) {
customText = getRandom();
invalidate();
}
// 获取长度为4的随机数
public String getRandom() {
Random random = new Random();
List<Integer> list = new ArrayList<>();
while (list.size() < 8) {
int ran = random.nextInt(10);
list.add(ran);
}
StringBuffer buffer = new StringBuffer();
for (Integer in : list) {
buffer.append("" + in);
}
return buffer.toString();
}
}