一、Android自定义view属性
1.在res/values/styles.xml
文件里面声明一个我们自定义的属性:
<resources> <!--name为声明的"属性集合"名,可以随便取,但是最好是设置为跟我们的View一样的名称--> <declare-styleable name="CircleView"> <!--声明我们的属性,名称为default_size,取值类型为尺寸类型(dp,px等)--> <attr name="radius" format="dimension"></attr> <attr name="circle_color" format="color"></attr> </declare-styleable> </resources>
2.在自定义View中获取对应设置的属性值
public CircleView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); //即属性集合的标签,在R文件中名称为R.styleable+name TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleView); //第一个参数为属性集合里面的属性,R文件名称:R.styleable+属性集合名称+下划线+属性名称 //第二个参数为,如果没有设置这个属性,则设置的默认的值 radius = typedArray.getDimensionPixelOffset(R.styleable.CircleView_radius, 20); color = typedArray.getColor(R.styleable.CircleView_circle_color, 000000); //最后记得将TypedArray对象回收 typedArray.recycle(); }
3.在xml文件中设置属性值
(1)首先需要定义命名空间 xmlns:rc="http://schemas.android.com/apk/res-auto"
(2)设置属性值 rc:radius rc:circle_color
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:rc="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.ruanchao.todaynews.UserViewActivity"> <com.ruanchao.todaynews.view.CircleView android:layout_width="wrap_content" android:layout_height="wrap_content" rc:radius="50dp" rc:circle_color="#FF69B4"/> </LinearLayout>
二、Android自定义View
1.onMeasure
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
参数中的widthMeasureSpec
和heightMeasureSpec包含了两层信息:测量模式和测量尺寸
(1)测量模式:
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
测量模式 | 表示意思 |
---|---|
UNSPECIFIED | 父容器没有对当前View有任何限制,当前View可以任意取尺寸(match_parent) |
EXACTLY | 当前的尺寸就是当前View应该取的尺寸(xml配置固定值) |
AT_MOST | 当前尺寸是当前View能取的最大尺寸(wrap_content) |
(2)尺寸大小:
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
示例代码:
private int getMySize(int defaultSize, int measureSpec) { int mySize = defaultSize; int mode = MeasureSpec.getMode(measureSpec); int size = MeasureSpec.getSize(measureSpec); switch (mode) { case MeasureSpec.UNSPECIFIED: {//如果没有指定大小,就设置为默认大小 mySize = defaultSize; break; } case MeasureSpec.AT_MOST: {//如果测量模式是最大取值为size //我们将大小取最大值,你也可以取其他值 mySize = size; break; } case MeasureSpec.EXACTLY: {//如果是固定的大小,那就不要去改变它 mySize = size; break; } } return mySize; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = getMySize(100, widthMeasureSpec); int height = getMySize(100, heightMeasureSpec); if (width < height) { height = width; } else { width = height; } setMeasuredDimension(width, height); }
<com.hc.studyview.MyView android:layout_width="match_parent" android:layout_height="100dp" android:background="#ff0000" />
2.onDraw 直接在画板Canvas对象上绘制
(1)invalidate方法会执行onDraw过程,只能在UI线程调用
(2)postInvalidate 可以在非UI线程调用,省去了Handler消息调用
(3)RequestLayout 会执行onMeasure,onLayout ,onDraw
三、Android自定义ViewGroup
自定义ViewGruup要经历以下几步:
1、根据各个子View的大小,确定ViewGroup大小(重写onMeasure()方法)
2、在ViewGroup中进行View的摆放(重写onLayout()方法)
示例代码:自定义ViewGroup实现LinearLayout布局
第一步:确定ViewGroup大小
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int with = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int withMode = MeasureSpec.getMode(widthMeasureSpec); int heigthMode = MeasureSpec.getMode(heightMeasureSpec); if (getChildCount() == 0) {//如果没有子View,当前ViewGroup没有存在的意义,不用占用空间 setMeasuredDimension(0, 0); return; } if (withMode == MeasureSpec.AT_MOST && heigthMode == MeasureSpec.AT_MOST){ //高度累加,宽度取最大 setMeasuredDimension(getMaxChildWidth(),getTotleHeight()); }else if (heigthMode == MeasureSpec.AT_MOST){ setMeasuredDimension(with,getTotleHeight()); }else if (withMode == MeasureSpec.AT_MOST){ setMeasuredDimension(getMaxChildWidth(),height); } } /*** * 获取子View中宽度最大的值 */ private int getMaxChildWidth() { int childCount = getChildCount(); int maxWidth = 0; for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); if (childView.getMeasuredWidth() > maxWidth) { maxWidth = childView.getMeasuredWidth(); } } return maxWidth; } /*** * 将所有子View的高度相加 **/ private int getTotleHeight() { int childCount = getChildCount(); int height = 0; for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); height += childView.getMeasuredHeight(); } return height; }
第二步:在ViewGroup中进行子View的摆放
@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { int count = getChildCount(); int currentHeigth = 0; //将子View逐个摆放 for (int i = 0; i < count; i++) { View child = getChildAt(i); int childHeigth = child.getMeasuredHeight(); child.layout(left, currentHeigth, right + child.getMeasuredWidth(), currentHeigth + childHeigth); currentHeigth += childHeigth; } }
测试xml
<com.rc.studyview.MyViewGroup android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#ff9900"> <Button android:layout_width="100dp" android:layout_height="wrap_content" android:text="btn" /> <Button android:layout_width="200dp" android:layout_height="wrap_content" android:text="btn" /> <Button android:layout_width="50dp" android:layout_height="wrap_content" android:text="btn" /> </com.rc.studyview.MyViewGroup>
时间: 2024-10-04 04:04:41