android自定义控件组合
1. 如何系统的学习android自定义各种酷炫控件
首先,为什么需要自定义View?
1. 现有的View满足不了你的需求,也没有办法从已有控件派生一个出来;界面元素需要自己绘制。
2. 现有View可以满足要求,把它做成自定义View只是为了抽象:为这个自定义View提供若干方法,方便调用着操纵View。通常做法是派生一个已有View,或者结合xml文件直接inflate。
目前常用的基本上是第二种方式,这种方式非常简单,与通常的View使用方法基本相同,但是作用却异常强大,拥有了这一层抽象,代码更加整洁也更容易维护,通过抽取自定义View的公共操作方法也减少了冗余代码,虽然简单,但不可忽视。
大多数人感觉神秘的应该是第一种,自绘控件,完全自定义;但其实这两种方式归根结底全部都是自绘;不信你去看看TextView的源码。只不过通常情况下系统帮我们绘制好了一些控件给开发者使用;OK,接下来就是一个问题。
在讲述之前我还是啰嗦地重申一下,复用已有View是最最常用也最有效的自定义View方式,必须熟练使用。
其次,如何自定义View?
想一下,一个View给用户最直观的感知是什么?静止的形态和动态的操作。静止的形态意思就是一个View呈现到用户眼里长成啥样子?动态操作指的是,用户与View之间可以有哪些交互?点击滑动View的不同地方会有什么反应?
1. 静态
如果一个自定义View的样式都没有办法绘制出来,那么后续的交互就是空谈了;我们一步步分解这个问题。
1.1 你的自定义View分为哪几个部分?是所有的部分都需要手动绘制还是只有一部分——找出需要完全自定义的部分,其他的部分用已有View实现。
1.2 你的自定义View的每个部分长成什么样,占用多大空间——结合理论知识View的measure过程,比如match_parent, wrap_content结合父View的laout_params参数最终测量大小是多少?
1.3 你的自定义View每个部分摆放在哪?相对位置如何?——View的layout过程。
1.4 你的自定义View那些完全需要手动绘制的部分是什么样,如何绘制?
你得学会操纵Canvas,学会2D绘图,什么?你跟我说3D,OpenGL?学会这些再说。
2. Android 自定义控件 layout
Android 绘制流程
View :View主要执行layout方法,使用 serFrame 方法来设置本身 View 的四个顶点的位置,确定View本身的位置。
ViewGroup :ViewGroup主要执行onLayout方法,递归遍历所有子View,确定子View的位置。
我们来看ViewRootImpl中的 performLayout() 方法
看到这里,那host.getMeasuredWidth() / host.getMeasuredHeight()是什么?它是直接调用View中的方法,其实就是经过measure后的DecorView的测量宽度和高度。在 Android 自定义控件 measure 中有说明。
2.3.2.1 我们先来看ViewGroup中的 layout() 方法
ViewGroup里面的layout最终会调入到父类View中的layout,View的layout后面讲解。这里可以先告诉大家,最终会调用View的onLayout方法,而ViewGroup的onLayout是抽象方法,所以它的子类LinearLayout必须要实现。
2.3.2.2 我们再来看LinearLayout中的 onLayout() 方法。
2.3.2.3 挑一个纵向的吧,我们再来看LinearLayout中的 layoutVertical() 方法。
2.3.2.4 我们再来看LinearLayout中的 setChildFrame() 方法。
又一次回到了View的layout方法,接下来就看View分发的layout。
我们先来看View中的 layout() 方法。
我们先来看View中的 onLayout() 方法。
空空如也,其实View的布局由父容器决定,所以空实现是正常的,当然也可以在自定义View中进行更改。
《Android 视图模块 全家桶》
Android开发之自定义控件(二)---onLayout详解
自定义View Layout过程 - 最易懂的自定义View原理系列(3)
3. android自定义listview控件,动态添加item,并对item进行操作
这是最基本的listView啊。把BaseAdapter弄明白就可以实现了。
4. Android自定义控件之可平移、缩放、旋转图片控件
先上效果图
源码
单点拖动图片对图片进行平移操作。双手缩放图片大小和旋转图片到一定的角度。图片缩放的时候 不能大于最大的缩放因子和小于最小的缩放因子。大于最大缩放因子或者小于最小缩放因子需要对图像进行回弹。图片旋转的角度只能为90度的倍数,不满足90度要进行回弹。图片回弹要一个渐变的效果。
大体思路: 首先,Android中提供了Matrix类可以对图像进行处理。其次,要显示一张图片最容易想到的就是ImageView。回弹要求渐变的过程,可以通过属性动画进行设置。所以大体的思路是:继承ImageView,重写onTouchEvent()方法,判断事件类型,在对应的事件使用Matrix对图像进行变换。
Matrix是一个已经封装好的矩阵,最重要的作用就是对坐标点进行变换。
举个栗子:
1.某个点(x0,y0,1)通过单位矩阵E映射得到的点还是(x0,y0,1)。
3.点(x0,y0,1)通过矩阵T映射得到的点就会做如下的变换
可以看到点(x0,y0,1)经过T矩阵在x轴方向上平移了dx,在y轴方向上平移了dy。
通过以上的变换可以得到具体的思路: 我们维护一个图像对应的矩阵mCurrentMatrix,该矩阵主要是对ImageView中的图像的各个点进行映射。ImageView在容器位置摆放完成之后,置mCurrentMatrix矩阵为单位矩阵。当onTouchEvent()方法中触发单点触控并且手指进行平移的时候,调用矩阵mCurrentMatrix的postTranslate(dx,dy),对mCurrentMatrix进行变换。当手指抬起,利用变换结束后的矩阵对图像的各个点进行映射,从而得到平移变换后的图像。同理可得,在两只手指进行缩放旋转的时候,我们对矩阵mCurrentMatrix进行各种变换,当缩放旋转的事件结束再利用变换完的矩阵去映射图像的各个点,从而得到缩放、旋转后的图像。
安卓自定义View进阶 - Matrix原理
安卓自定义View进阶 - Matrix详解
首先理清事件的逻辑:
初始化图像大小和位置
缩放图像大小和控件大小自适应,平移图像中心和控件中心重合
onTouchEvent()函数
平移操作
将图像对应的矩阵进行变换。
缩放操作
mBoundRectF为记录图像边界的矩形。缩放的时候选取图像的中心进行缩放。
旋转操作
旋转的时候旋转的旋转中心也是图像的中心
图像中各个点的映射
调用ImageView的setImageMatrix(Matrix matrix)会让ImageView根据设置的matrix去重新绘制图像。
更新图像的矩形边界
获得图像的矩形,并根据矩阵映射矩形各个点的坐标。
缩放回弹
旋转回弹
一些计算方法
要求图像的变换是一个渐变的过程,很容易想到的就是属性动画。因为属性动画本身就是对值进行不断set的过程。而我们维护的矩阵也是一个值,所以很自然可以想到,如果得到回弹之前的矩阵的值以及回弹之后矩阵的值,就可以根据动画监听器中动画当前的系数值去改变矩阵的值。
对animator对象设置完监听器之后,就可以在手指抬起的时候调用属性动画的start()方法开启动画。
自定义可平移、缩放、旋转的控件主要点有两个方面:一是onTouchEvent()中判断平移、旋转、缩放的触发条件,平移位移量、缩放比例因子、旋转角度的计算。二是Matrix矩阵的应用。