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完全展开

@Override
protected 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"?>
<resources>
    <declare-styleable name="CircleView">
        <attr name="circle_color" format="color"/>
    </declare-styleable>
</resources>

常用单位format:color boolean dimension float integer string fraction(百分比) enum(eg:orientation,单选) flag(eg:adjustResize|adjustPan,多选)

布局中进行设置

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    >
    <scut.carson_ho.diy_view.CircleView
        app:circle_color="#FF4081"
         />
</RelativeLayout>

在代码中解析获取

mColor = a.getColor(R.styleable.CircleView_circle_color,Color.RED);

或者 直接在xml中使用(这种方式属性必须赋值否则会出错)

<TextView
        android:id="@+id/dialog_loading_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="?attr/circle_color"/>

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"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:drawable="@drawable/a_0"
        android:duration="100" />
    <item
        android:drawable="@drawable/a_1"
        android:duration="100" />
    <item
        android:drawable="@drawable/a_2"
        android:duration="100" />
</animation-list>

同样的也可用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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值