自定义一个圆圈View
2016-04-14 16:37
399 查看
这篇博客的目的是如何开发一个继承自View的自定义控件。最后的效果是能够得到一个任何页面都能使用的圆圈控件。代码很简单,也很粗陋。但是高楼平地起。
先贴代码,可以先不看,看完后面的解释再看代码:
布局
形成一个View有三个过程。
1. onMeasure:测量控件的高和宽,并通过setMeasuredDimension(int measuredWidth, int measuredHeight)方法设置控件的高宽。
2. onLayout:计算控件在视图中的坐标。控件会按照这里设置的坐标决定自己在屏幕上的位置。
3. onDraw:画图,位置确定后,控件通过这个方法画出控件的图形。像上面的例子就是自己在控件的位置上话一个红色的圆。
知道了上面三个方法后就能解决继承View自定义控件所产生的两个问题:
问题1:wrap_content失效。给控件的布局中设置wrap_content将不会再有效果,解决方法参考上面的onMeasure代码。
问题2:padding失效。设置的padding将不会再有效。解决方法参考上面的onDraw方法。
如何给控件创建自定义属性
1. 在values文件夹下创建一个用于创建自定义属性的xml文件,这里就写成attrs.xml
declare-styleable元素指的是一个属性集合,里面可以有多个属性,在本例中只有一个颜色属性。还可以定义其他格式的属性,比如reference是id属性等等。
2. 在构造方法中解析这个xml文件,获取属性值,获得了属性的值,当然可以根据值来设置控件的样子了。
最后,在布局文件中使用自定义属性。很简单,只有一个地方需要注意,需要指定一个命名空间xmlns,就是下面的 xmlns:app=”http://schemas.android.com/apk/res-auto”,app这个名字可以随便取,报错的原因是,xml必须按照命名空间中的约定编写。这是为了规范xml的格式。
注意的点:自定义view有三个构造函数
在代码中直接new一个Custom View实例的时候,会调用第一个构造函数。这个没有任何争议。
在xml布局文件中调用Custom View的时候,会调用第二个构造函数。这个也没有争议。
在xml布局文件中调用Custom View,并且Custom View标签中还有自定义属性时,这里调用的还是第二个构造函数。
所以,在第三个构造函数如果不在第二个函数里用this()调用的化,自定义的属性将不会有效。
先贴代码,可以先不看,看完后面的解释再看代码:
package com.example.administrator.myfirstandroidstudioproject.customView; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.view.View; /** * Created by Administrator on 2016/4/13. */ public class CustomView extends View { //园的默认颜色 private int mColor = Color.RED; //一个画笔,用于在onDraw函数中画圆 private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private void init() { mPaint.setColor(mColor); } public CustomView(Context context) { this(context,null); init(); } public CustomView(Context context, AttributeSet attrs) { this(context, attrs,0); init(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //让warp生效,核心思想就是: // 当设置成warp时,就用控件自己本身的长度 // (这个本身的长度不是说你在xml中配置的长度,而是比如一个字的长度是10px,那么有两个字的textView的长度就应该是20px) // 否则就是用控件测量的长度。之前一直以为测量的长度就是控件本身的长度,原来不是。 // 测量的长度是通过父容器的MeasureSpec和自己的LayoutParams和本身的长度共同决定的结果。(这个就得看Android源码了) super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthSpaceMode = MeasureSpec.getMode(widthMeasureSpec); int widthSpaceSize = MeasureSpec.getSize(widthMeasureSpec); int heightSpaceMode = MeasureSpec.getMode(heightMeasureSpec); int heightSpaceSize = MeasureSpec.getSize(heightMeasureSpec); if (widthSpaceMode == MeasureSpec.AT_MOST && heightSpaceMode == MeasureSpec.AT_MOST) { setMeasuredDimension(100, 100); } else if (widthSpaceMode == MeasureSpec.AT_MOST) { setMeasuredDimension(100, heightSpaceSize); } else if (heightSpaceSize == MeasureSpec.AT_MOST) { setMeasuredDimension(widthSpaceSize, 100); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //让padding生效,核心思想就是自己计算让padding之后的宽度和高度,最后画出来。 final int paddingLeft = getPaddingLeft(); final int paddingRight = getPaddingRight(); final int paddingTop = getPaddingTop(); final int paddingBottom = getPaddingBottom(); int width = getWidth() - paddingLeft - paddingRight; int height = getHeight() - paddingTop - paddingBottom; int radius = Math.min(width, height) / 2; canvas.drawCircle(width / 2, height / 2, radius, mPaint); } public CustomView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } }
布局
<com.example.administrator.myfirstandroidstudioproject.customView.CustomView android:id="@+id/circleView1" android:layout_width="wrap_content" android:layout_height="100px" android:background="#000000" />
形成一个View有三个过程。
1. onMeasure:测量控件的高和宽,并通过setMeasuredDimension(int measuredWidth, int measuredHeight)方法设置控件的高宽。
2. onLayout:计算控件在视图中的坐标。控件会按照这里设置的坐标决定自己在屏幕上的位置。
3. onDraw:画图,位置确定后,控件通过这个方法画出控件的图形。像上面的例子就是自己在控件的位置上话一个红色的圆。
知道了上面三个方法后就能解决继承View自定义控件所产生的两个问题:
问题1:wrap_content失效。给控件的布局中设置wrap_content将不会再有效果,解决方法参考上面的onMeasure代码。
问题2:padding失效。设置的padding将不会再有效。解决方法参考上面的onDraw方法。
如何给控件创建自定义属性
1. 在values文件夹下创建一个用于创建自定义属性的xml文件,这里就写成attrs.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="CustomView"> <attr name="circle_color" format="color"> </attr> </declare-styleable> </resources>
declare-styleable元素指的是一个属性集合,里面可以有多个属性,在本例中只有一个颜色属性。还可以定义其他格式的属性,比如reference是id属性等等。
2. 在构造方法中解析这个xml文件,获取属性值,获得了属性的值,当然可以根据值来设置控件的样子了。
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); /* 获取属性集合 */ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView); /* 从属性集合中获取单个属性 第一个参数里的是获取的属性 第二个参数是如果没有获取到属性的默认属性 */ mColor=a.getColor(R.styleable.CustomView_circle_color,Color.RED); /* 释放资源 */ a.recycle(); init(); }
最后,在布局文件中使用自定义属性。很简单,只有一个地方需要注意,需要指定一个命名空间xmlns,就是下面的 xmlns:app=”http://schemas.android.com/apk/res-auto”,app这个名字可以随便取,报错的原因是,xml必须按照命名空间中的约定编写。这是为了规范xml的格式。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" tools:context="com.example.administrator.myfirstandroidstudioproject.MainActivity"> <com.example.administrator.myfirstandroidstudioproject.customView.CustomView android:id="@+id/circleView1" android:layout_width="wrap_content" android:layout_height="100px" android:padding="20px" app:circle_color="@color/colorAccent" android:background="#000000" /> </LinearLayout>
注意的点:自定义view有三个构造函数
在代码中直接new一个Custom View实例的时候,会调用第一个构造函数。这个没有任何争议。
在xml布局文件中调用Custom View的时候,会调用第二个构造函数。这个也没有争议。
在xml布局文件中调用Custom View,并且Custom View标签中还有自定义属性时,这里调用的还是第二个构造函数。
所以,在第三个构造函数如果不在第二个函数里用this()调用的化,自定义的属性将不会有效。
相关文章推荐
- 循环(5 )
- 欢迎您在新浪博客安家
- JS 获取样式属性
- Springmvc注解优化
- JavaWeb中的Filter
- Android SDK Manager国内无法更新的解决方案(亲测有效)
- 问题:UIButton 添加倒计时功能后会一闪一闪
- Android学习路线指南
- 定时器开启
- Hibernate学习(2)
- iOS抽屉效果
- Request对象
- 淘宝天猫网站停止支持IE6、IE7浏览器,你还在用xp吗?
- spring 事务控制
- vs2010操作office2010
- LeetCode:Convert Sorted List to Binary Search Tree
- UIAlertView' is deprecated: first deprecated in iOS 9.0 - UIAlertView is deprecated. Use UIAlert
- Springmvc注解启用
- Java内部类:概览(一)
- Java transient关键字