3.16自定义控件
1.自定义VIEW组件
创建CustomizeView,继承View。重写onDraw方法,通过onDraw方法绘制我们自定义的图像、位图、路径等。
示例:
//自定义绘制View
public class CutomizeView extends View {
//构造方法
public CutomizeView(Context context) {
super(context);
}
//构造方法,这个构造必须有
public CutomizeView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
//重新onDraw方法
@Override
protected void onDraw(Canvas canvas) {
//矩形位置坐标
RectF rectF=new RectF(100,100,400,400);
//画笔
Paint paint=new Paint();
//设置画笔
//设置反锯齿
paint.setAntiAlias(true);
//设置绘制颜色
paint.setColor(0xFF20FF22);
//设置绘制样式
paint.setStyle(Paint.Style.STROKE);
//设置绘制文本大小
paint.setTextSize(100);
//绘制矩形
canvas.drawRect(rectF,paint);
//绘制椭圆
canvas.drawOval(rectF,paint);
//绘制圆
canvas.drawCircle(300,300,200,paint);
//绘制线段
canvas.drawLine(0,0,100,100,paint);
//绘制文本
canvas.drawText("hello",200,900,paint);
//绘制圆弧
canvas.drawArc(rectF,0,100,true,paint);
//绘制点
canvas.drawPoint(800,800,paint);
//绘制图片
//bitmap位图,1、将项目已有图片转为bitmap
Bitmap bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
canvas.drawBitmap(bitmap,200,1000,paint);
//2.创建一个bitmap
//Bitmap bitmap1=Bitmap.createBitmap(100,100, Bitmap.Config.ARGB_8888);
//绘制路径
drawPath(canvas);
}
//绘制路径
public void drawPath(Canvas canvas){
Paint paint=new Paint();
paint.setColor(0xFF0022FF);
paint.setStyle(Paint.Style.STROKE);
//绘制路径
Path path=new Path();
//起点
path.moveTo(300,400);
//直线
path.lineTo(500,200);
path.lineTo(550,350);
path.lineTo(800,700);
//曲线
path.quadTo(500,300,300,800);
canvas.drawPath(path,paint);
}
}
创建对应layout文件,l_customize1.xml文件
示例:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.pro_customizeview.view.CutomizeView
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</com.example.pro_customizeview.view.CutomizeView>
</LinearLayout>
补充:Canvas对象坐标变换方法
translate(100,100):平移变化;
rotate(90):旋转变化;
scale():缩放变化;
save():保存当前坐标系;
restore():销毁当前坐标系,返回上一次坐标系;
自定义属性:
在res/values/attrs.xml中创建我们自定义组件属性。
示例:
定义属性名和属性需要数据格式类型
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CutomizeView">
<attr name="fontColor" format="color"></attr>
<attr name="fontSize" format="dimension"></attr>
</declare-styleable>
</resources>
修改l_customize1.xml文件,设置自定义属性。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:zdy="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.pro_customizeview.view.CutomizeView
zdy:fontSize="20dp"
zdy:fontColor="@color/colorPrimary"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
在自定义组件CutomizeView中构造函数中获取到我们自定义的属性,然后可以在onDraw,onMeasure,onLayout方法中使用。
//构造方法,这个构造必须有
public CutomizeView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
//所有的属性存放在AttributeSet中
int count = attrs.getAttributeCount();
//1、遍历获取
for(int i=0;i<count;i++){
//获取属性名
String attrName=attrs.getAttributeName(i);
//获取属性值
String attrValue=attrs.getAttributeValue(i);
}
//2、直接获取到自定义属性
//在R文件中会自动生成
TypedArray typedArray= context.obtainStyledAttributes(attrs,R.styleable.CutomizeView);
//将获取到的属性可以在onDraw,onMesure,onLayout中使用。
int fontColor=typedArray.getColor(R.styleable.CutomizeView_fontColor,0xFF0022FF);
float fontSize=typedArray.getDimension(R.styleable.CutomizeView_fontSize,20);
//注意使用完释放资源
typedArray.recycle();
}
onMeasure方法和onLayout方法。
示例:
//测量方法,获取控件宽高,模式
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//调用父类onMeasure方法,实际注释掉
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//1、获取mode和size
int widthMode=MeasureSpec.getMode(widthMeasureSpec);
int widthSize=MeasureSpec.getSize(widthMeasureSpec);
int heightMode=MeasureSpec.getMode(heightMeasureSpec);
int heightSize=MeasureSpec.getSize(heightMeasureSpec);
//当父控件为viewgroup时,要获取子控件宽高,必须先测量一次,强制测量
//否则childView的getMeasuredWidth拿不到宽度
measureChildren(widthMeasureSpec,heightMeasureSpec);
//2、通过mode设置合理size
switch (widthMode){
//父控件对子控件限制最大值,wrap_content
case MeasureSpec.AT_MOST:
//宽度设置,
widthSize = 100dp ;
break;
//控件大小是个确定值,100dp,match_parent(父控件大小确定)等
case MeasureSpec.EXACTLY:
break;
//父控件对子控件大小不做限定
case MeasureSpec.UNSPECIFIED:
break;
}
switch (heightMode){
//父控件对控件限制最大值,wrap_content
case MeasureSpec.AT_MOST:
//宽度设置,
break;
//控件大小是个确定值,layout中设置为具体20dp等或者match_parent,父控件大小确定
case MeasureSpec.EXACTLY:
break;
//父控件对控件大小不做限定,例如:ListView中子item数量不定
case MeasureSpec.UNSPECIFIED:
break;