Android控件篇

前言

此文涉及界面绘制流程、如何自定义View、如何刷新View、如何处理事件分发、如何定义动画、如何代码变换控件等。

手动刷新View

调用 requestLayout() 方法时,view 只会执行 onMeasure(先)及 onLayout(后)方法。

调用 invalidate ()方法时,view 会调用 onDraw()方法。

若只改变宽高调用 requestLayout() 方法即可,若只更新内容调用 invalidate ()方法。

关闭硬件加速时,调用任何一个View的invalidate()方法都会导致整个View树的重新绘制;开启硬件加速时,调用哪一个View的invalidate()方法就会重绘哪一个View。

界面绘制流程

setContentView将布局添加到DecorView里,形成一个树形结构。之后调动RootView.preformMeasure、preformLayout、preformDraw进行测量、布局、以及绘制。然后绘图数据讲给GPU计算、计算了好了交给硬件显示。

手机也是存在显卡的,显卡集成在cpu上,显卡主要是GPU(图像处理单元)

cpu跟GPU区别:GPU擅图像处理,所以cpu会通过接口将图像处理的一些计算等交给GPU

通过windowManger管理窗口,之后有windowManager调用系统服务WindowManagerService对窗口进行操作。

自定义View

常见分为组合控件以及非组合控件。

组合控件:通常是自定义布局,然后将布局添加到自定义控件里。

非组合控件:

自定义ViewGroup一般重写onMeasure跟onLayout。

自定义Viw一般再重写onDraw。

onMeasure

onMeausre为测量空间measureSpace,受父容器测量空间以及当前空间LayoutParams影响。根据测量空间可获得测量模式以及测量尺,重写onMeasure就是根据测量模式以及测量尺寸,设置自定义控件的尺寸。测量模式分为三种

EXCEATLY:当前size就应该是当前View取得尺寸,对应match_parent、固定尺寸。

AT_MOST:当前size是当前View能取得最大值,对应wrap_parent。

UNSPECIFIED:父容器对当前View没有任何限制,一般当前View可以取默认值。

onLayout

onLayout参数为当前View位置跟尺寸是否有变化boolean值,子控件到当前控件的上下左右边距。

onDraw

Canvas有各种绘制方法:drawLine、drawText等。

canvas.save:保存当前画布。可理解为ps里的锁定当前图层,然后新建一个图层,后续操作在新图层上。比如旋转、平移图层等,不影响原有图层。

canvas.resotre:恢复当前画布。可理解为将新图层跟已有图片合并。save跟restore是成对出现的。

事件分发机制

Down事件分发流程_哔哩哔哩_bilibili

https://www.cnblogs.com/Android-Alvin/p/13557877.html

概述

滑动屏幕会产生一系列事件,如action_down、action_move、action_up等,这一系列事件成为事件序列。

View类的dispatchTouchEvent负责处理事件

ViewGroup类的dispatchTouchEvent负责分发事件

处理事件优先级onTouchListener  > onClickListener > onTouchEvent

dispatchTouchEvent方法主要分为三块

第一块:判断是否拦截

第二块:如果不拦截的话,down事件的话遍历点击到的子控件,看子控件是否处理事件。

如果有子控件处理,则新建mFirstTouchTarget对象,mFirstTouchTarget.next为null。

第三块:如果mFirstTouchTarget为null,则询问自己是否处理。

如果mFirstTouchTarget不为null,当前控件拦截的话,就给子控件发送cancel事件并设置mFirstTouchTarget为null,后续事件询问自己是否处理。如果不拦截的话就讲事件交给子控件处理。

主要逻辑

down事件分发从父控件递归传给子控件,如果没有子控件处理(View默认onTouchEvent是会消费事件的,除TextView、ImageView等重写了onTouchEvent默认不消费外。所以子控件一般是会处理的),则询问自己是否处理,后续move事件不会再传给子控件。

所以如果控件都不做处理的话,事件一般是由最底层子控件消费了,如果想让父控件消费,一般就得父控件重写onIntercepterTouchEvent拦截事件。拦截后会向子控件发送cancel事件,后续事件就不会再传给子控件了。

滑动冲突解决方法

内部拦截法:

重写子控件的onIntercepterTouchEvent方法

action_down:调用禁止父容器拦截为true。

aciton_move:如果子控件要处理则返回true拦截。如果要父控件处理则调用禁止父控件拦截为false

重写父控件的onIntercepterTouchEvent方法

action_down:返回为false

action_move:返回为true

外部拦截法:

重写父布局的onIntercepterTouchEvent方法

action_down:返回为false,down事件不能拦截,拦截了子控件就收不到事件了。

action_move:如果需要拦截则返回为true,否则返回false。

action_up、action_cancel:返回为false,up事件不能拦截,拦截了子控件就收不到点击事件了。

滑动的方式

1、layout方法:毁掉onLayout方法了设置显示的位置。

2、offsetLeftAndRight与offsetTopAndBcottom:系统提供的一个上下左右移动的api

3、LayoutParams

4、scrollTo与scrollBy:移动的是View的内容,如果是ViewGroup,移动的是子View

5、Scroller:相比scrollTo与scrollBy,可以实现平滑的移动的。

分三步

第一步:初始化Scroller对象

第二步:调用scroller.startScroll(int startX, int startY, int dx, int dy, int duration),并调用invalidate()刷线View

第三部:重写View的computeScroll方法

调用scrollTo(mScroller.getCurrX(), mScroller.getCurrY())以及invalidate()重绘

6、属性动画:改变控件属性来滑动

7、ViewDragHelper:解决了android中手势处理过于复杂的问题,视图拖动助手。一般定义再ViewGroup里

分三步

第一步:初始化mDragHelper = ViewDragHelper.create(this, 1.0f, new DragHelperCallback());其中1.0f是灵敏度系数,系数越大越敏感。第一个参数为this,表示要拖动子View所在的Parent View

第二步:将触摸事件传递给ViewDragHelper

重写onIntercepterTouchEvent以及onTouchEvent,调用mDragHelper.shouldInterceptTouchEvent(event)以及mDragHelper.processTouchEvent(event);

第三步:再DragHelperCallback会掉方法里处理拖拽行为。

动画

Tween(补间)动画(View动画)

透明度、旋转、位移、缩放、动画集合

缺点不具备交互性

原理:每次绘制视图时,View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值,然后调用canvas.concat(tanstormToApply.getMatrix()),通过矩阵完成动画,如果动画没有完成,就继续调用invalidate()函数。

自定义补间动画:继承Animation

标准的动画效果

补间动画常用于视图View的一些标准动画效果:平移、旋转、缩放 & 透明度;

特殊的应用场景

Activity 的切换效果

Fragement 的切换效果

视图组(ViewGroup)中子元素的出场效果

属性动画:Animator

ValueAnimator

原理:类是先改变值,然后手动赋值给对象的属性从而实现动画;是间接对对象属性进行操作

ObjectAnimator

对象:不单单针对View,需要有set和get方法

继承自ValueAnimator

原理:类是先改变值,然后自动赋值给对象的属性从而实现动画;是直接对对象属性进行操作

自定义插值器:

补间动画 实现 Interpolator接口;属性动画实现TimeInterpolator接口。

实现float getInterpolation(float input)

根据动画的进度(0%-100%)计算出当前属性值改变的百分比。

自定义估值器:

继承TypeEvaluator,实现public T evaluate(float fraction, T startValue, T endValue)

根据 插值器计算出当前属性值改变的百分比 & 初始值 & 结束值 来计算 当前属性具体的数值

帧动动画


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值