在后边的文章中发现在说Android自定义时,有时候要重复解释很多东西,所以想想返回来增加一篇“基础原理篇”,直接进入正题吧——
我们在日常开发中,可能会想到很好的项目方案(那么恭喜你,你很有产品经理的素养和潜质),或者是遇到很好的设计方案(也恭喜你,你遇到一个很有品味和审美的美工和产品经理),看到很多美观、舒适的界面,但是当你真正要实现它的时候,往往会发现搜遍Android系统控件的各个角落,也没有找到这样一个可用的控件来达到这样的显示效果或者是响应方式。那么我要再次恭喜你,你即将在这款设计中开创自己的天地了!换句话说,这个时候就需要自定义控件了。
Android自定义控件的三种主要方式为:
1、继承现有控件——重写或者覆盖其中的某些方法,来实现自定义的显示方式或者自定义响应——适用于这种情况:有某个单个的系统控件和你心目中需要的控件很是相似。最最简单的比如你需要一个带有点击特效的按钮;
2、组合现有的控件——利用已有的系统控件来组合出自己的特有控件,完成自己业务需求——适用于这种情况:系统中没有那个控件可以完成我们的需求,但是有两个或几个系统控件组合起来就能达到我们的目的,但是如果每次需要这样的控件就得把多个系统控件组合一次显然浪费太多时间也增加很多重复代码。比如我需要一个带清除按钮的输入框(可以参考自定义控件开发—带清除按钮的输入框)、需要一个带标题栏的图片显示控件... ...等等;
3、全新开发——继承View类开发自己的全新控件——这是最高阶的自定义控件开发方式,适用于这种情况:系统中压根没有类似的控件、或者我们有特殊需求特地不用系统的控件。比如我需要一个显示饼状统计图(我在学习的时候完善了一个自定义饼状图,提供源码下载,工程是用AndroidStudio创建的)、需要一个圆形的带数字的进度条、需要一个随机数安全键盘... ...等等。
知道了我要使用哪种自定义控件以后,怎么动手操作呢?
现在就动手还有点着急了,在动手之前我们还要熟悉至少了解一下知识:
1、什么是View、ViewGroup,以及两者之间的区别和联系。其实这个问题相当有深度,如果你真的清除了,那么你差不多已经理解了Android视图设计者当初的设计思路;
2、最好学习一下系统控件的子父类继承关系,比如TextView、ImageView是简单类,直接继承自View;EditText、Button继承自TextView,ImageButton继承自ImageView等(可以把下图保存下来好好看看):
3、了解Android中Touch事件的分发和消费机制(这个比较复杂,在复杂的控件开发中可能用到,题大家推荐两个牛人的博客touch事件的分发和消费机制和sunzn'Blog的Android 编程下 Touch 事件的分发和消费机制,还有Andriod 从源码的角度详解View,ViewGroup的Touch事件的分发机制);这个马上看不清楚没有关系,可以在以后慢慢琢磨和体会,这个不是看几遍就能看懂的,共勉啊!
4、会用Android画图工具Canvas,可以不用太熟,在用的时候再查也可以;
onFinishInflate() 回调方法,当应用从XML加载该组件并用它构建界面之后调用的方法
onMeasure() 检测View组件及其子组件的大小
onLayout() 当该组件需要分配其子组件的位置、大小时
onSizeChange() 当该组件的大小被改变时
onDraw() 当组件将要绘制它的内容时
onKeyDown 当按下某个键盘时
onKeyUp 当松开某个键盘时
onTrackballEvent 当发生轨迹球事件时
onTouchEvent 当发生触屏事件时
onWindowFocusChanged(boolean) 当该组件得到、失去焦点时
onAtrrachedToWindow() 当把该组件放入到某个窗口时
onDetachedFromWindow() 当把该组件从某个窗口上分离时触发的方法
onWindowVisibilityChanged(int): 当包含该组件的窗口的可见性发生改变时触发的方法
6、View类以及View子类的三个构造方法的不同作用:
<span style="font-size:14px;"> public CircleView(Context context) { this(context, null); } public CircleView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CircleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); }</span>
在代码里用new动态创建对象的话一般用一个参数的;写在xml里的调用2个参数的attr里边传过来的是 xml里边对应的height width等参数,包括自己定义的参数,如果在xml里边写入自定义控件的话 必须要重写2个参数的构造函数;第3个参数不熟,传style的吧貌似。
7、会添加自定义回调函数,以便为自己的控件添加一些自定义事件的响应。
看到这么多前置条件是不是已经把你吓回去了呢?别怕,我的基础和你差不多,也是边学边做边记录。遇到不懂的多看多问,慢慢的都不是问题了。让我们一起加油吧,希望我的笔记能带给你一些些帮助,以避免对不起我酸痛的手指,如果这篇文章对你有所帮助,希望你传递下去,让它能帮助更多的人!
(1) 在res/values目录下建立一个attrs.xml的文件,在这个文件中增加对控件的自定义属性字段和属性数据类型的定义;
(2) 写一个自定义控件类,继承合适的父类,这个类就是你的自定义控件的实现;
(3) 使用带AttributeSet参数的类的构造函数,并在构造函数中将自定义控件类中变量与attrs.xml中的属性连接起来;
(4) 在自定义控件类中使用这些已经连接的属性变量;
(5) 将自定义的控件类声明到布局用的xml文件中去;
(6) 在界面中生成此自定义控件类对象,就完成了自定义控件的创建和使用了。
详细的过程可以参照我的Android自定义控件开发系列(一),这是入门的一篇,里边有详细的步骤和解释,例子简单但比较粗糙,但是反而对你的学习自定义控件更有利,因为你不必花多少时间在例子的理解上,而是专注于自定义控件的开发过程,如果要好点的效果,可以看Android自定义控件开发系列(二)。
可能有人问道,o(︶︿︶)o 唉?怎么给自定义控件添加自定义属性呢,我在别的文章中这个是重点啊!我说一下,这个其实并不是重点,更不是难点,他只是Android使用属性字段的一个机制,只是一个步骤顺序化的东西而已,使用过一遍以后就不是问题了!相对于以上知识性的东西就显得渺小了!