Android 属性动画实例+疑惑

简要介绍

本文是参考请叫我大苏的博客,写的非常实用,这里主要是记录这个实例方便以后自己的使用,同时也在项目中遇到的疑惑贴出来,希望有人能帮忙解答一下,大家共同学习,谢谢。

demo介绍

本demo实现的就两个功能,一个竖直方向扩展图片,一个呈圆弧状扩展图片。图片如下:
竖直方向的动画
圆弧状动画
这里两个demo,主要是写一点实用的业务,避免以后到处查找,方便自己借鉴。

demo步骤

首先导入依赖:
compile ‘com.jakewharton:butterknife:5.1.1’

先在res文件夹下,创建animator文件夹,并创建一个round_show.xml动画,具体代码如下:

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:propertyName="alpha"
    android:valueFrom="0f"
    android:valueTo="1f"
    android:valueType="floatType">
</objectAnimator>

demo的布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="bottom|left"
        android:orientation="vertical">
        <ImageView
            android:id="@+id/img_home1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/bg_img"
            android:layout_margin="3dp"
            android:clickable="true"
            android:src="@drawable/ic_home_white_48dp"/>
        <ImageView
            android:id="@+id/img_refresh1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="3dp"
            android:background="@drawable/bg_img"
            android:clickable="true"
            android:src="@drawable/ic_refresh_white_48dp"/>
        <ImageView
            android:id="@+id/img_clear1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="3dp"
            android:clickable="true"
            android:background="@drawable/bg_img"
            android:src="@drawable/ic_clear_white_48dp"/>
        <ImageView
            android:id="@+id/img_back1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="3dp"
            android:clickable="true"
            android:background="@drawable/bg_img"
            android:src="@drawable/ic_chevron_left_white_48dp"/>
        <ImageView
            android:id="@+id/img_next1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/bg_img"
            android:layout_margin="3dp"
            android:clickable="true"
            android:src="@drawable/ic_navigate_next_white_48dp"/>
        <ImageView
            android:id="@+id/img_down_up1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="3dp"
            android:background="@drawable/bg_img"
            android:clickable="true"
            android:src="@drawable/ic_arrow_drop_down_white_48dp"/>
    </LinearLayout>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="bottom|center"
        android:layout_marginLeft="50dp">
        <ImageView
            android:id="@+id/img_home2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="3dp"
            android:clickable="true"
            android:background="@drawable/bg_img"
            android:src="@drawable/ic_home_white_48dp"/>
        <ImageView
            android:id="@+id/img_refresh2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="3dp"
            android:clickable="true"
            android:background="@drawable/bg_img"
            android:src="@drawable/ic_refresh_white_48dp"/>
        <ImageView
            android:id="@+id/img_clear2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="3dp"
            android:clickable="true"
            android:background="@drawable/bg_img"
            android:src="@drawable/ic_clear_white_48dp"/>
        <ImageView
            android:id="@+id/img_back2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="3dp"
            android:clickable="true"
            android:background="@drawable/bg_img"
            android:src="@drawable/ic_chevron_left_white_48dp"/>
        <ImageView
            android:id="@+id/img_next2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:clickable="true"
            android:background="@drawable/bg_img"
            android:src="@drawable/ic_navigate_next_white_48dp"/>
        <ImageView
            android:id="@+id/img_down_up2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="3dp"
            android:clickable="true"
            android:background="@drawable/bg_img"
            android:src="@drawable/ic_arrow_drop_up_white_48dp"/>
    </RelativeLayout>
</RelativeLayout>

然后直接在MainActiity中实现动画效果,具体看注释。代码如下:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ButterKnife.inject(this);
        downUpIcon2.performClick();
    }

    @InjectView(R.id.img_home1)
    ImageView homeIcon1;
    @InjectView(R.id.img_home2)
    ImageView homeIcon2;
    @InjectView(R.id.img_refresh1) ImageView refreshIcon1;
    @InjectView(R.id.img_refresh2) ImageView refreshIcon2;
    @InjectView(R.id.img_clear1) ImageView clearIcon1;
    @InjectView(R.id.img_clear2) ImageView clearIcon2;
    @InjectView(R.id.img_back1) ImageView backIcon1;
    @InjectView(R.id.img_back2) ImageView backIcon2;
    @InjectView(R.id.img_next1) ImageView nextIcon1;
    @InjectView(R.id.img_next2) ImageView nextIcon2;
    @InjectView(R.id.img_down_up1) ImageView downUpIcon1;
    @InjectView(R.id.img_down_up2) ImageView downUpIcon2;

    //垂直方向上的图片是否隐藏
    private boolean isIconHided1 = false;
    //圆弧方向上的图片是否隐藏
    private boolean isIconHided2 = false;
    //是否计算了图片间的间距,(间距方便设置动画)
    private boolean isIconCalculate = false;
    //垂直方向标识
    private static final int VERTIAL_ANIM = 1;
    //圆弧方向标识
    private static final int ROUND_ANIM = 2;
    //垂直图标点击事件
    @OnClick(R.id.img_down_up1)
    public void mDownUpClick(){
        if (isIconHided1){
            //展示垂直方向上的图片动画
            showIcons(VERTIAL_ANIM);
            //改变点击图标
            downUpIcon1.setImageResource(R.drawable.ic_arrow_drop_down_white_48dp);
        }else {
             //隐藏垂直方向上的图片动画
            hideIcons(VERTIAL_ANIM);
            //改变点击图标
            downUpIcon1.setImageResource(R.drawable.ic_arrow_drop_up_white_48dp);
        }
        isIconHided1 = !isIconHided1;
    }
    //圆弧图标点击事件
    @OnClick(R.id.img_down_up2)
    public void mDownUpClick2(){
        if (isIconHided2){
            //展示圆弧方向上的图片动画
            showIcons(ROUND_ANIM);
            //改变点击图标
            downUpIcon2.setImageResource(R.drawable.ic_arrow_drop_down_white_48dp);
        }else {
            //隐藏圆弧方向上的图片动画
            hideIcons(ROUND_ANIM);
            //改变点击图标
            downUpIcon2.setImageResource(R.drawable.ic_arrow_drop_up_white_48dp);
        }
        isIconHided2 = !isIconHided2;
    }
    //设置图片展示的动画
    private void showIcons(final int anim){
        if (anim == VERTIAL_ANIM){
            verialShowAnim(homeIcon1);
            verialShowAnim(refreshIcon1);
            verialShowAnim(clearIcon1);
            verialShowAnim(backIcon1);
            verialShowAnim(nextIcon1);

        }else if (anim == ROUND_ANIM){
            //以半径为300的圆形区域扩展
            float radius = 300f;
            //半径除以根号2
            float offset = radius / (float)Math.sqrt(2);
            ObjectAnimator animator = ObjectAnimator.ofFloat(homeIcon2,"translationX",-radius);
            ObjectAnimator animator1 = ObjectAnimator.ofFloat(refreshIcon2,"translationX",-offset);
            ObjectAnimator animator2 = ObjectAnimator.ofFloat(refreshIcon2,"translationY",-offset);
            ObjectAnimator animator3 = ObjectAnimator.ofFloat(clearIcon2,"translationY",-radius);
            ObjectAnimator animator4 = ObjectAnimator.ofFloat(backIcon2,"translationX",offset);
            ObjectAnimator animator5 = ObjectAnimator.ofFloat(backIcon2,"translationY",-offset);
            ObjectAnimator animator6 = ObjectAnimator.ofFloat(nextIcon2,"translationX",radius);
            roundShowAima(homeIcon2);
            roundShowAima(clearIcon2);
            roundShowAima(refreshIcon2);
            roundShowAima(backIcon2);
            roundShowAima(nextIcon2);
            AnimatorSet set = new AnimatorSet();
            set.setDuration(1000);
            //组合动画展示  
          set.play(animator).with(animator1).with(animator2)
          .with(animator3).with(animator4).with(animator5).with(animator6);
          set.start();
        }
    }
    //隐藏动画
    private void hideIcons(int anim){
        if (anim == VERTIAL_ANIM){
            //竖直收缩动画需要计算icon要平移的距离
            if (!isIconCalculate){
                //将计算出来的竖直距离存起来,方便设置动画时使用
                homeIcon1.setTag(calculateWidgetsDistance(homeIcon1,downUpIcon1)[1]);
                refreshIcon1.setTag(calculateWidgetsDistance(refreshIcon1,downUpIcon1)[1]);
                clearIcon1.setTag(calculateWidgetsDistance(clearIcon1,downUpIcon1)[1]);
                backIcon1.setTag(calculateWidgetsDistance(backIcon1,downUpIcon1)[1]);
                nextIcon1.setTag(calculateWidgetsDistance(nextIcon1,downUpIcon1)[1]);
                isIconCalculate = true;
            }
            //使用ValueAnimator,为了了解它的更多用法,这里将用多种方式来达到动画效果
            ValueAnimator animator = ValueAnimator.ofFloat(0.0f,1.0f);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float value = (float) animation.getAnimatedValue();
                    //竖直平移动画
                    float transY;
                    transY = ((int) homeIcon1.getTag()) * value;
                    homeIcon1.setTranslationY(transY);
                    transY = ((int) refreshIcon1.getTag()) * value;
                    refreshIcon1.setTranslationY(transY);
                    transY = ((int) clearIcon1.getTag()) * value;
                    clearIcon1.setTranslationY(transY);
                    transY = ((int) backIcon1.getTag()) * value;
                    backIcon1.setTranslationY(transY);
                }
            });
            ValueAnimator animator1 = ValueAnimator.ofFloat(0.0f,((int)nextIcon1.getTag()));
            animator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float value = (float) animation.getAnimatedValue();
                    nextIcon1.setTranslationY(value);
                }
            });
            //从不透明到完全透明
            ValueAnimator animator2 = ValueAnimator.ofFloat(1.0f,0.0f);
            animator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float value = (float) animation.getAnimatedValue();
                    homeIcon1.setAlpha(value);
                    refreshIcon1.setAlpha(value);
                    clearIcon1.setAlpha(value);
                    backIcon1.setAlpha(value);
                    nextIcon1.setAlpha(value);
                }
            });
            animator.setDuration(1000);
            animator1.setDuration(1000);
            animator2.setDuration(200);

            AnimatorSet set = new AnimatorSet();
            set.play(animator).with(animator1).before(animator2);
            set.start();
        }else if (anim == ROUND_ANIM){
            roundHideAnim(homeIcon2);
            roundHideAnim(refreshIcon2);
            roundHideAnim(clearIcon2);
            roundHideAnim(backIcon2);
            roundHideAnim(nextIcon2);
        }
    }

    private void verialShowAnim(View view){
        //0,表示view的Y坐标从当前位置平移到最初最初的位置
        ObjectAnimator animator = ObjectAnimator.ofFloat(view,"translationY",0);
        ObjectAnimator animator1 = ObjectAnimator.ofFloat(view,"alpha",1);
        animator.setDuration(1000);
        animator1.setDuration(1000);
        animator.start();
        animator1.start();
        View view1;
    }
    //圆弧隐藏
    private void roundHideAnim(View view){
        ObjectAnimator animator = ObjectAnimator.ofFloat(view,"translationX",0);
        ObjectAnimator animator1 = ObjectAnimator.ofFloat(view,"translationY",0);
        ObjectAnimator animator2 = ObjectAnimator.ofFloat(view,"alpha",0);
        AnimatorSet set = new AnimatorSet();
        set.setDuration(1000);
        set.play(animator).with(animator1).with(animator2);
        set.start();
    }
    private void roundShowAima(View view){
        ObjectAnimator animator7 = (ObjectAnimator) AnimatorInflater.loadAnimator(this,R.animator.round_show);
        animator7.setTarget(view);
        animator7.start();
    }
    /**
     * 计算两个view的距离
     * @param v1
     * @param v2
     * @return 返回new int[2], [0]横坐标距离,[1]纵坐标的距离
     */
    private int[] calculateWidgetsDistance(View v1, View v2){
        int[] location1 = new int[2];
        int[] location2 = new int[2];
        int[] ret = new int[2];
        v1.getLocationOnScreen(location1);
        v2.getLocationOnScreen(location2);

        ret[0] = Math.abs(location1[0] - location2[0]);
        ret[1] = Math.abs(location1[1] - location2[1]);
        return ret;
    }
}

以上就是一个完整的demo实现,比较简单,仅供大家一起来学习,也再次感谢请叫我大苏

一点疑惑,希望有人解答

这里是另外一个自己写的测试demo,布局文件主要注意几点,后面会有疑问(1,这里整体是线性布局,第一个子线性布局高度已经用了matchparent。2,第一个子线程布局下有一个Button隐藏在了界面下方,初始时,界面上看不见。3,Button下有一个线程布局,且该线性布局的高度是WrapContent,在界面上仍然看不到)布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.lfq.MainActivity">
  <LinearLayout
      android:id="@+id/ly_content"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:orientation="vertical">
      <Button
          android:id="@+id/bt_1"
          android:layout_width="match_parent"
          android:layout_height="40dp"
          android:onClick="onClick"
          android:text="点击弹出" />
      <Button
          android:layout_below="@id/bt_1"
          android:layout_width="match_parent"
          android:layout_height="40dp"
          android:text="hello"/>
  </LinearLayout>
    <Button
        android:id="@+id/bt_4"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:onClick="onClick"
        android:text="点击弹出" />
    <LinearLayout
        android:id="@+id/ly_show"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:id="@+id/tv_content1"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:gravity="center"
            android:onClick="onClick1"
            android:text="test content 1"
            android:textColor="#4a4a4a"
            android:textSize="16sp" />
        <View
            android:layout_width="match_parent"
            android:layout_height="1px"
            android:background="#e0e0e0" />
        <TextView
            android:id="@+id/tv_content2"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:gravity="center"
            android:onClick="onClick2"
            android:text="test content 2"
            android:textColor="#4a4a4a"
            android:textSize="16sp" />
        <View
            android:layout_width="match_parent"
            android:layout_height="1px"
            android:background="#e0e0e0" />

        <TextView
            android:id="@+id/tv_content3"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:gravity="center"
            android:onClick="onClick3"
            android:text="test content 3"
            android:textColor="#4a4a4a"
            android:textSize="16sp" />
    </LinearLayout>
</LinearLayout>

再贴出MainActivity的控制动画界面。比较简单,只为了测试:

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //第二个子线性布局(隐藏在界面下方,界面上看不到)
        ly_show = (LinearLayout) findViewById(R.id.ly_show);
        //第二个子线性布局中的一个子控件
        tv=(TextView) findViewById(R.id.tv_content1);
        //隐藏在第一个子线性布局下的BUtton
        bt = (Button) findViewById(R.id.bt_4);
        //第一个子线性布局中的Button
        bt2 = (Button) findViewById(R.id.bt_1);
    }
    public void onClick(View view) {
//        float curTranslation = tv.getTranslationY();
        //float height=ly_show.getHeight();
        ObjectAnimator//
            //界面来我们测试的主要内容就是第一个参数,也就是下面的ly_show位置
                .ofFloat(ly_show, "translationY", 0.0F, -360.0F, 0.0F)//
                .setDuration(500)//
                .start();
    }
}

(1)效果:我们依次将动画的对象,也就是上面注释中说到的ly_show位置那个参数替换为tv、bt、bt2。
这里我们会发现真正有正常动画的也就是bt以及bt2,而tv以及ly_show不会产生动画效果,弹不出来。
(2)改变:我们将第二个子线性布局中的高度wrapcontent改为一个固定的值200dp,然后测试,会出现动画效果。但是tv仍然没有动画效果。
(3)将整体的线性布局改为帧布局,将第二个子线性布局高度设置为wrapcontent会发现能正常动画,但是界面很丑。
(4)将整体改为Relativilayout,,用layout_below将原来的bt_4隐藏到界面下面,然后对这个Button进行动画测试,发现并没有动画效果。
其实还有很多可以测试的地方,大家慢慢体验,关键问题就是属性对话与布局间存在的冲突关系搞不清楚,希望有大拿帮忙解答一下,谢谢。

猜你喜欢

转载自blog.csdn.net/firesmog/article/details/62417984