效果图

我们先来看看效果图:

  • 根据ScrollView或者HorizontalScrollView中的滑动距离设置对应子view的动画效果
  • 自定义ScrollView、HorizontalScrollView,以及LinearLayoutView
  • 获取并记录在布局文件中定义的自定义动画属性值

定义属性值

定义属性值,在layout.xml即布局文件中可以给view(泛指,可以为任何view)指定动画属性值,例如是否进行alpha动画,或者指定出场方式。

<?xml version="1.0" encoding="UTF-8"?><resources>    <declare-styleable name="XAnimator">        <attr name="x_alpha" format="boolean"/>        <attr name="x_scaleX" format="boolean"/>        <attr name="x_scaleY" format="boolean"/>        <attr name="x_startBgColor" format="color"/>        <attr name="x_endBgColor" format="color"/>        <attr name="from_direction">            <flag name="top" value="1" />            <flag name="bottom" value="2" />            <flag name="left" value="3" />            <flag name="right" value="4" />        attr>    declare-styleable>resources>
属性 说明
x_alpha 是否执行透明值变化动画(范围为0-1)
x_scaleX 是否执行x轴缩放动画(范围为0-1)
x_scaleY 是否执行y轴缩放动画(范围为0-1)
x_startBgColor 背景颜色渐变动画起始颜色值
x_endBgColor 背景颜色渐变动画结束颜色值
from_direction 出现方向,top, bottom, left, right,分别为从顶部,底部,左边,右边出现

定义属性类

用于记录在布局文件中指定的动画属性值XAnimator(即上面所定义的属性值)
在这里就不列出来了,可查看 XAnimatorAttr

布局代码

我们可以看到,使用就像ScrollView+LinearLayout一样,只不过在需要进行动画的子view(例如ImageView和LinearLayout)中指定了动画属性,在XAnimatorScrollView进行滑动的时候就可以根据指定的动画属性进行对应的设置。

<?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"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context=".MainActivity">    <com.iigo.library.XAnimatorScrollView        android:layout_width="match_parent"        android:layout_height="match_parent">        <com.iigo.library.XAnimatorLinearLayout            android:orientation="vertical"            android:layout_width="match_parent"            android:layout_height="match_parent">            <ImageView                android:layout_width="match_parent"                android:layout_height="match_parent"                android:src="@mipmap/duola_big" />            <ImageView                android:layout_width="match_parent"                android:layout_height="200dp"                android:src="@mipmap/duola1"                app:x_alpha="true"                app:x_scaleX="true"                app:x_scaleY="true"                app:from_direction="left"/>            <ImageView                android:layout_width="match_parent"                android:layout_height="200dp"                android:src="@mipmap/duola2"                app:from_direction="right"                app:x_alpha="true"                app:x_scaleX="true"                app:x_scaleY="true" />            <ImageView                android:layout_width="match_parent"                android:layout_height="200dp"                android:src="@mipmap/duola3"                app:from_direction="left"                app:x_alpha="true" />            <ImageView                android:layout_width="match_parent"                android:layout_height="200dp"                android:src="@mipmap/duola4"                app:from_direction="right"                app:x_alpha="true" />            <ImageView                android:layout_width="match_parent"                android:layout_height="200dp"                android:src="@mipmap/duola5"                app:x_endBgColor="@android:color/holo_red_light"                app:x_startBgColor="@android:color/holo_green_light" />            <LinearLayout                android:layout_width="match_parent"                android:layout_height="wrap_content"                app:x_endBgColor="@android:color/holo_orange_light"                app:x_startBgColor="@android:color/holo_green_light">                <ImageView                    android:layout_width="match_parent"                    android:layout_height="200dp"                    android:src="@mipmap/duola6" />            LinearLayout>        com.iigo.library.XAnimatorLinearLayout>    com.iigo.library.XAnimatorScrollView>RelativeLayout>

获取动画属性值

上面的布局代码中,我们在XAnimatorLinearLayout中使用了系统控件,例如ImageView和LinearLayout,那我们如何获取定义的动画属性值(即XAnimator)呢?

可以根据XmlResourceParser来进行获取

还不了解的可以看我文章 Android 关于XmlResourceParser

我们可以通过接口

XmlResourceParser parser = context.getResources().getLayout(layoutId);

解析layout资源文件来遍历获取动画属性

主要接口可参考 XAnimator

动画执行

在我们自定义的XAnimatorLinearLayout 中,增加onScrollChanged接口,在XAnimatorScrollView或XAnimatorHorizontalScrollView 调用onScrollChanged的时候,调用XAnimatorLinearLayout 中的onScrollChanged接口,再遍历子view,根据其设置的动画属性,设置对应scroll百分比的动画值。

public final class XAnimatorLinearLayout extends LinearLayout{    private static ArgbEvaluator argbEvaluator = new ArgbEvaluator();    public XAnimatorLinearLayout(Context context) {        super(context);    }    public XAnimatorLinearLayout(Context context, AttributeSet attrs) {        super(context, attrs);    }    public XAnimatorLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @TargetApi(Build.VERSION_CODES.LOLLIPOP)    public XAnimatorLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);    }    public void onScrollChanged(int l, int t, int oldl, int oldt){        boolean isVertical = getOrientation() == VERTICAL;        for (int i = 0;i < getChildCount();i++) {            View child = getChildAt(i);            XAnimatorAttr xAnimatorAttr = (XAnimatorAttr) child.getTag(R.id.XAnimator);            if (xAnimatorAttr == null){                continue;            }            int referDistance = isVertical ? child.getTop() : child.getLeft();            int referParentSize = isVertical ? ((ViewGroup)getParent()).getHeight()                    : ((ViewGroup)getParent()).getWidth();            int referChildSize  = isVertical ? child.getHeight() : child.getWidth();            int absolute = referDistance - (isVertical ? t : l);            int visibleSize = referParentSize - absolute;            float ratio = limitValue(visibleSize / (float) referChildSize, 0, 1);            if (absolute <= referParentSize) {                performAnimator(child, xAnimatorAttr, ratio);            } else {                drawHideState(child, xAnimatorAttr);            }        }    }    /**     * Now perform animator for the child view.     *     * @param child The child view.     * @param xAnimatorAttr The {@link XAnimatorAttr} of the child view.     * @param ratio The ratio of the scroll(0 <= ration <= 1).     * */    private void performAnimator(View child, XAnimatorAttr xAnimatorAttr, float ratio){        if (child == null                || xAnimatorAttr == null){            return;        }        if (xAnimatorAttr.isAlpha()){            child.setAlpha(ratio);        }        if (xAnimatorAttr.isScaleX()){            child.setScaleX(ratio);        }        if (xAnimatorAttr.isScaleY()){            child.setScaleY(ratio);        }        if (xAnimatorAttr.getStartBgColor() != -1                && xAnimatorAttr.getEndBgColor() != -1){            child.setBackgroundColor((Integer) argbEvaluator.evaluate(ratio,                    xAnimatorAttr.getStartBgColor(),                    xAnimatorAttr.getEndBgColor()));        }        switch (xAnimatorAttr.getFromDirection()){            case XAnimatorAttr.FROM_DIRECTION_BOTTOM:                child.setTranslationY(child.getHeight() * (1 - ratio));                break;            case XAnimatorAttr.FROM_DIRECTION_TOP:                child.setTranslationY(-child.getHeight() * (1 - ratio));                break;            case XAnimatorAttr.FROM_DIRECTION_LEFT:                child.setTranslationX(-child.getWidth() * (1 - ratio));                break;            case XAnimatorAttr.FROM_DIRECTION_RIGHT:                child.setTranslationX(child.getWidth() * (1 - ratio));                break;            default: break;        }    }    /**     * When the child view is not yet displayed on the screen, will draw its hide state.     *     * @param child The child view.     * @param xAnimatorAttr  The attr of the child view.     * */    private void drawHideState(View child, XAnimatorAttr xAnimatorAttr){        if (child == null                || xAnimatorAttr == null){            return;        }        if(xAnimatorAttr.isAlpha()){            child.setAlpha(0);        }        if(xAnimatorAttr.isScaleX()){            child.setScaleX(0);        }        if(xAnimatorAttr.isScaleY()){            child.setScaleY(0);        }        switch (xAnimatorAttr.getFromDirection()){            case XAnimatorAttr.FROM_DIRECTION_BOTTOM:                child.setTranslationY(child.getHeight());                break;            case XAnimatorAttr.FROM_DIRECTION_TOP:                child.setTranslationY(-child.getHeight());                break;            case XAnimatorAttr.FROM_DIRECTION_LEFT:                child.setTranslationX(-child.getWidth());                break;            case XAnimatorAttr.FROM_DIRECTION_RIGHT:                child.setTranslationX(child.getWidth());                break;                default: break;        }    }    /**     * Limit the value between min and max.     *     * @param value The limit value.     * @param min The min value.     * @param max The max value.     * */    private float limitValue(float value, float min ,float max) {        return Math.max(Math.min(value,max), min);    }}

Github

更多相关文章

  1. Android(安卓)自定义控件属性,自定义Dialog定位
  2. android中自定义的控件,使用自定义属性attrs.xml
  3. Android中动画的详细讲解
  4. 自定义TextView实现跑马灯
  5. Android高德地图开发(2)——地图显示+自定义控件
  6. Android(安卓)ApiDemos示例解析(21):App->Device Admin
  7. Android7.1启动系统App必须配置加密
  8. Android(安卓)Api demo系列(一) (App>Activity>Animation)
  9. Android(安卓)自定义View——拖动选择时间控件

随机推荐

  1. Android(安卓)root权限获取大揭秘
  2. Android中layout_gravity与gravity及layo
  3. 在移动互联时代下,介绍几个Android(安卓)
  4. android中Webview与javascript的交互(互相
  5. Android(安卓)开发技术周报 Issue#292
  6. Android、IOS开发思路及项目文件结构
  7. 主题:三,android编码规范 & 常用布局 & 常
  8. Android(安卓)轻松实现语音识别
  9. android ndk初体验和Android.mk文件报: no
  10. Android将使用ext4文件系统的特性