Android(安卓)UI绘制 - 动画基础
基础知识
Android的绘制系统(ActivityManagerService)
Android的事件系统(InputManagerService)
measure
MeasureSpecs
MeasureSpecs维护一个int型(32bit)数据,其中2bit表示mode,30bit表示size
size = MeasureSpec.getSize(measureSpec)mode = MeasureSpec.getMode(measureSpec)measureSpec = MeasureSpec.makeMeasureSpec(size, mode)getDefaultSize(size,measureSpec)//根据View默认大小size和父类measureSpec来测量当前View的大小
一个View的大小由父容器的MeasureSpec和自身的LayoutParams决定
测量过程
例子:修改ListView的onMeasure使得ListView完全展开
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //int widthMeasureSpec, int heightMeasureSpec是父容器的测量spec,现将父容器的高度测量spec修改成足够大,并且是AT_MOST模式,这样子容器即ListView认为父容器有足够大的空间就会将所有的内容完全展开了。 heightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, heightMeasureSpec);}
layout
view的layout过程:layout(确定自身的位置)->onLayout(空实现)
ViewGroup的layout过程:layout(确定自身的位置)->onLayout(确定子控件的位置,这里实现具体布局,并且会遍历子控件的layout对子控件执行layout)
例子:简单实现一个类似LinearLayout的横向布局
public class CustomViewGroup extends ViewGroup { private final static String TAG = "CustomViewGroup"; // view 的间隔 private final static int VIEW_MARGIN = 0; public CustomViewGroup(Context context) { super(context); } // 重写它的onMeasure() 在该方法中进行对子View的大小进行测量 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { for (int index = 0; index < getChildCount(); index++) { final View child = getChildAt(index); child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } // 重写onLayout方法实现子View的定位 @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = getChildCount(); int row = 0; //当前宽度 int lengthX = l; //当前高度 int lengthY = t; for (int i = 0; i < count; i++) { final View child = this.getChildAt(i); int width = child.getMeasuredWidth(); int height = child.getMeasuredHeight(); lengthX += width + VIEW_MARGIN; lengthY = row * (height + VIEW_MARGIN) + VIEW_MARGIN + height + t; if (lengthX > r) { lengthX = width + VIEW_MARGIN + l; row++; lengthY = row * (height + VIEW_MARGIN) + VIEW_MARGIN + height + t; } child.layout(lengthX - width, lengthY - height, lengthX, lengthY); } }}
draw
PS:invalidate最后也是通过调用rootView的performTraversals()来刷新视图的;而invalidate只会重新执行onDraw;requestLayout才会重新执行整个绘制过程
自定义View的四种构造函数及常见函数
// 如果View是在Java代码里面new的,则调用第一个构造函数 public CarsonView(Context context) { super(context); }// 如果View是在.xml里声明的,则调用第二个构造函数// 自定义属性是从AttributeSet参数传进来的 public CarsonView(Context context, AttributeSet attrs) { super(context, attrs); }// 不会自动调用// 一般是在第二个构造函数里主动调用// 如View有style属性时 public CarsonView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } //API21之后才使用 // 不会自动调用 // 一般是在第二个构造函数里主动调用 // 如View有style属性时 public CarsonView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); }
view.getTop() 子View左上角距父View顶部的距离 view.getBottom() 子View右下角距父View顶部的距离 view.getLeft() 子View左上角距父View左侧 view.getRight() 子View右下角距父View左侧 event.getX()/event.getY() 触摸点相对于其所在组件坐标系的坐标 event.getRawX()/event.getRawY() 触摸点相对于屏幕默认坐标系的坐标
view的移动方式
layout
offsetTopAndBottom、offsetLeftAndRight
scrollTo、scrollBy
LayoutParams
Scroller
颜色
自定义属性
在values目录下创建自定义属性的xml文件attrs_circle_view.xml
<?xml version="1.0" encoding="utf-8"?>
常用单位format:color boolean dimension float integer string fraction(百分比) enum(eg:orientation,单选) flag(eg:adjustResize|adjustPan,多选)
布局中进行设置
<?xml version="1.0" encoding="utf-8"?>
在代码中解析获取
mColor = a.getColor(R.styleable.CircleView_circle_color,Color.RED);
或者 直接在xml中使用(这种方式属性必须赋值否则会出错)
PS:还可以在lib中设置一个默认的style样式,在View直接取过来用。业务层需要使用时只需写一个同名的style则可覆盖之,达到全局修改样式的效果。
其他小细节
- post替代handler,View的内部本身提供了post系列的方法,完全可以替代Handler的作用,使用起来更加方便、直接。
- onAttachedToWindow,调用的时机是当包含View的Activity启动的时刻,适合启动线程/动画/注册各种东东
- onDetachedFromWindow,调用的时机是当包含View的Activity退出或当前View被remove的时刻,适合结束线程/动画/注销各种东东
帧动画
<?xml version="1.0" encoding="utf-8"?>
同样的也可用AnimationDrawable实现
补间动画
平移动画TranslateAnimation、缩放动画ScaleAnimation、旋转动画RotateAnimatioin、透明度动画AlphaAnimation
自定义动画:通过矩阵变换来实现,可用来做3D动画!继承Animation,实现initialize(初始化工作)、applyTransFormation(动画实现)即可。
常见属性
- < translate>
■ 表示x的起始值
■ 表示x的结束值
■ 表示y的起始值
■ 表示y的结束值 - < scale>
■ fromX 水平方向缩放起始值
■ toX 水平方向缩放结束值
■ fromY
■ toY
■ pivotX 缩放的轴点的x坐标
■ pivotY 缩放的轴点的y坐标
■ pivotXType x轴的所发模式,即中心点相对于哪个物体Animation.ABSOLUTE/RELATIVE_TO_SELF/RELATIVE_TO_PARENT
■ pivotYType y轴的所发模式 - < rotate>
■ fromeDegres旋转开始的角度
■ toDegrees
■ pivotX旋转的轴点的x坐标
■ pivotY - < alpha>
■ fromAlpha透明度起始值
■ toAlpha透明度结束值 - 共有属性
■duration动画持续时间
■ fillAfter动画结束后是否停留在结束位置
自定义补间动画
public class MyAnimation extends Animation{ @Override protected void applyTransformation(float interpolatedTime,Transformation transformation){ //interpolatedTime表示动画的时间进行比,transformation表示补间动画在不同时刻对View的变形程度 }}
布局动画LayoutAnimation
为容器型控件里的子View设置动画 LayoutAnimationController
xml实现
android:delay子类动画时间间隔 android:animationOrder="random" 子类的显示方式 normal默认random随机reverse倒序android:animation="@anim/slide_right" 表示孩子显示时的具体动画是什么
组合动画
AnimationSet
属性动画
ObjectAnimator
ObjectAnimator// .ofFloat(view, "rotationX", 0.0F, 360.0F)// .setDuration(500)// .start();
一次性修改多个属性
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f, 0f, 1f); PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f); PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f); ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY,pvhZ).setDuration(1000).start();
ValueAnimator
ValueAnimator animator = ValueAnimator.ofFloat(0, mScreenHeight - mBlueBall.getHeight()); animator.setTarget(mBlueBall); animator.setDuration(1000).start(); // animator.setInterpolator(value) animator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mBlueBall.setTranslationY((Float) animation.getAnimatedValue()); } });
常见属性
Transtion 过度动画
本质上过渡动画也还是属性动画,只不过做了一层封装,方便实现Activity和View的过渡效果
绘制辅助
Interpplator 插值器
- AccelerateDecelerateInterpolator:开始与结束时速度快,中间慢
- AccelerateInterpolator:开始慢然后加速
- CycleInterpolator:动画循环播放特定的次数,速率改变沿着正弦曲线
- DecelerateInterpolator:开始速度快然后减速
- LinearInterpolator:均匀的改变速度
TypeEvaluator 类型估值,主要用于设置动画操作属性的值。设置 属性值 从初始值过渡到结束值 的变化具体数值
- IntEvaluator Int类型估值器,返回int类型的属性改变
- FloatEvaluator Float类型估值器,返回Float类型属性改变
- ArgbEvaluator 颜色类型估值器
// 实现TypeEvaluator接口public class PointEvaluator implements TypeEvaluator { // 复写evaluate()在里面写入对象动画过渡的逻辑 @Override public Object evaluate(float fraction, Object startValue, Object endValue) { //fraction为插值器getInterpolation()的返回值,startValue/endValue为初始值/结束值 // 将动画初始值startValue 和 动画结束值endValue 强制类型转换成Point对象 Point startPoint = (Point) startValue; Point endPoint = (Point) endValue; // 根据fraction来计算当前动画的x和y的值 float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX()); float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY()); // 将计算后的坐标封装到一个新的Point对象中并返回 Point point = new Point(x, y); return point; }}
Activity转场动画
overridePendingTransition
更多相关文章
- Android中调用天气预报
- Android下相机的调用
- RelativeLayout属性详解
- Android学习笔记之mainfest文件中android属性
- Delphi xe7 up1 调用android振动功能
- android中TextView和EditText控件一些属性
- pro.Android(安卓)Media--调用内置的照相机
- Android控件之ImageView(显示图片的控件)
- RelativeLayout用到的一些重要的属性