5.布局变化时的动画

5.1 问题

应用程序动态地添加或移除布局中的视图,希望这种变化能够以动画的形式展示出来。

5.2 解决方案

(API Level 11)
使用LayoutTransition对象自定义在布局中对视图结构修改后的动画效果。在Android3.0以后的版本中,只需要简单地在XML中设置android:animateLayoutChanges标识或者在Java代码中添加一个LayoutTransition对象,即可实现任何ViewGroup改变布局时的动画效果。
布局中的每个View对象在布局变换时有5种状态。应用程序可以为下面任何一种状态设置自定义动画:

  • APPEARING:容器中出现一个视图。
  • DISAPPEARING:容器中消失一个视图。
  • CHANGING:布局改变导致某个视图随之改变,例如调整大小,但不包括添加或移除视图。
  • CHANGE_APPEARING:其他视图的出现导致某个视图改变。
  • CHANGE_DISAPPEARING:其他视图的消失导致某个视图改变。

5.3 实现机制

以下两个代码演示了一个应用程序,该应用程序在基本的LinearLayout改变时创建动画。
res/layout/main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical" >
    <Button
        android:id="@+id/button_add"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onAddClick"
        android:text="Click To Add Item" />
    <LinearLayout
        android:id="@+id/verticalContainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:animateLayoutChanges="true"
        android:orientation="vertical" />
</LinearLayout>

添加或移除视图的Activity

public class MainActivity extends Activity {
    LinearLayout mContainer;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mContainer = (LinearLayout)findViewById(R.id.verticalContainer);
    }

        //添加可以移除自身的视图
    public void onAddClick(View v) {
        Button button = new Button(this);
        button.setText("Click To Remove");
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mContainer.removeView(v);
            }
        });

        mContainer.addView(button, new LinearLayout.LayoutParams(
                LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
    }
}

这个简单的示例在单击Add Item按钮时会在LinearLayout中添加Button实例。每个新的按钮在单击时都具有将自己从布局中移除的功能。要使此过程动起来,我们只需要在LinearLayout上设置android:animateLayoutChanges = “true”,之后框架会进行接下来的动作。默认情况下,新按钮会渐入到新的位置,而不会干扰其他视图;移除时按钮会出现渐出动画,而周围的视图则会平滑地填充移除时的空隙。
我们可以为每个过程自定义过渡动画来实现自定义的动画效果。参见以下代码会向之前的Activity中添加一些自定义过渡动画。
使用了自定义LayoutTransition的Activity

public class MainActivity extends Activity {

    LinearLayout mContainer;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // 布局改变时的动画
        mContainer = (LinearLayout) findViewById(R.id.verticalContainer);
        LayoutTransition transition = new LayoutTransition();
        mContainer.setLayoutTransition(transition);

        // 通过翻转进入的动画代替默认的出现动画
        Animator appearAnim = ObjectAnimator.ofFloat(null, "rotationY", 90f, 0f)
                .setDuration(transition.getDuration(LayoutTransition.APPEARING));
        transition.setAnimator(LayoutTransition.APPEARING, appearAnim);
        //通过翻转消失的动画代替默认的消失动画
        Animator disappearAnim = ObjectAnimator.ofFloat(null, "rotationX", 0f, 90f)
                .setDuration(transition.getDuration(LayoutTransition.DISAPPEARING));
        transition.setAnimator(LayoutTransition.DISAPPEARING, disappearAnim);

       /**
         * 通过滑动动画代替默认的布局改变时的动画
         * 我们需要立即设置一些动画属性,所以创建了多个
         * PropertyValueHolder对象的动画
         *这个动画会让视图滑动进入并短暂地缩小一半长度
         */
        PropertyValuesHolder pvhSlide = PropertyValuesHolder.ofFloat("y", 0, 1);
        PropertyValuesHolder pvhScaleY = PropertyValuesHolder.ofFloat("scaleY", 1f, 0.5f, 1f);
        PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofFloat("scaleX", 1f, 0.5f, 1f);
        Animator changingAppearingAnim = ObjectAnimator.ofPropertyValuesHolder(
                    this, pvhSlide, pvhScaleY, pvhScaleX)
                .setDuration(transition.getDuration(LayoutTransition.CHANGE_DISAPPEARING));
        transition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, changingAppearingAnim);
    }

    public void onAddClick(View v) {
        Button button = new Button(this);
        button.setText("Click To Remove");
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mContainer.removeView(v);
            }
        });

        mContainer.addView(button, new LinearLayout.LayoutParams(
                LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
    }
}

本例中,我们在Button布局中修改了APPEARING、DISAPPEARING和CHANGE_DISAPPEARING时的过渡动画。前两个过渡动画会影响到视图添加或移除时的效果。当单击Add Item按钮后,新增的按钮会水平旋转进入现有视图中。当单击Remove按钮时,该按钮会在视图中垂直旋转地消失。这两个动画都是通过创建新的ObjectAnimation对象并设置自定义旋转属性来实现的,而动画持续的时间则是每种过渡类型的默认时间(通过一个特定过渡类型的键值设置到我们的LayoutTransition实例上)。最后一种过渡动画稍微有点复杂,需要创建一个动画,让周围的视图可以平滑地运动到新位置,滑动的同时会产生缩放效果。

注意:
在自定义视图改变的过渡动画时,添加移动到视图新位置的动画非常重要,否则在创建视图或填充视图消失区域时可能会出现闪烁的现象。

为了实现这种效果,需要通过PropertyValuesHolder实例创建一个ObjectAnimator来设置一些属性。动画的每个属性都是单独的PropertyValuesHolder,并且通过ofPropertyValuesHolder()工厂方法添加到animator对象中。最后这个过渡动画使Remove按钮下面的所有按钮向上滑动到刚刚空出的位置,同时稍微收缩一下。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值