Android 布局平铺展开效果的属性动画

转自:Android 布局平铺展开效果的属性动画 - 博客频道 - CSDN.NET http://blog.csdn.net/debbytang/article/details/68496728
刚在整理项目代码,看到之前写的一个布局延伸平铺展开效果的代码堆积在Activity里面,然后整理之后简单封装了一下,在此记录。有需要的童鞋可以参考一下~

其实这里直接用布局的 gone 和 visible 属性也可以实现,而且最方便快捷,不过一瞬间的显示隐藏显得没那么好看,也不是我们想要的,所以用了属性动画去实现。Android 3.0 之后,Google 加入了属性动画框架,关于属性动画的详细介绍网上相关文章很多,具体这里可以参考鸿洋大神的文章:

[文章链接] http://blog.csdn.net/lmj623565791/article/details/38067475
布局文件就不贴了,没什么必要。主要的布局结构展示动画效果部分如下图:

这里写图片描述

外层为一个相对布局,然后红色矩形框内为两个线性布局,最下面的箭头为一个 Textview 。
然后主要效果如上文动图所示,其动画效果我抽取了一个简单的工具类,方便复用。

主要功能代码如下:

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;

/**
 * Created by debbytang.
 * Description:显示隐藏布局的属性动画(铺展)
 * Date:2017/3/30.
 */
public class HiddenAnimUtils {

    private int mHeight;//伸展高度

    private View hideView,down;//需要展开隐藏的布局,开关控件

    private RotateAnimation animation;//旋转动画

    /**
     * 构造器(可根据自己需要修改传参)
     * @param context 上下文
     * @param hideView 需要隐藏或显示的布局view
     * @param down 按钮开关的view
     * @param height 布局展开的高度(根据实际需要传)
     */
    public static HiddenAnimUtils newInstance(Context context,View hideView,View down,int height){
        return new HiddenAnimUtils(context,hideView,down,height);
    }

    private HiddenAnimUtils(Context context,View hideView,View down,int height){
        this.hideView = hideView;
        this.down = down;
        float mDensity = context.getResources().getDisplayMetrics().density;
        mHeight = (int) (mDensity * height + 0.5);//伸展高度
    }

    /**
     * 开关
     */
    public void toggle(){
        startAnimation();
        if (View.VISIBLE == hideView.getVisibility()) {
            closeAnimate(hideView);//布局隐藏
        } else {
            openAnim(hideView);//布局铺开
        }
    }

    /**
     * 开关旋转动画
     */
    private void startAnimation() {
        if (View.VISIBLE == hideView.getVisibility()) {
            animation = new RotateAnimation(180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        } else {
            animation = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        }
        animation.setDuration(30);//设置动画持续时间
        animation.setInterpolator(new LinearInterpolator());
        animation.setRepeatMode(Animation.REVERSE);//设置反方向执行
        animation.setFillAfter(true);//动画执行完后是否停留在执行完的状态
        down.startAnimation(animation);
    }

    private void openAnim(View v) {
        v.setVisibility(View.VISIBLE);
        ValueAnimator animator = createDropAnimator(v, 0, mHeight);
        animator.start();
    }

    private void closeAnimate(final View view) {
        int origHeight = view.getHeight();
        ValueAnimator animator = createDropAnimator(view, origHeight, 0);
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                view.setVisibility(View.GONE);
            }
        });
        animator.start();
    }

    private ValueAnimator createDropAnimator(final View v, int start, int end) {
        ValueAnimator animator = ValueAnimator.ofInt(start, end);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator arg0) {
                int value = (int) arg0.getAnimatedValue();
                ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
                layoutParams.height = value;
                v.setLayoutParams(layoutParams);
            }
        });
        return animator;
    }
}

使用:

在你需要的点击事件那里直接调用上面的工具类的 toggle() 方法就行了,就一行代码,如下:

@Override
    public void onClick(View v) {
        super.onClick(v);
        switch (v.getId()) {
        ...
         case R.id.down:
            HiddenAnimUtils.newInstance(xxx.this,xxx,down,77).toggle();
            breake;
        ...
        }
    }

补充:不想通过指定高度显示,而是根据控件自身的高度来设置平铺展开的高度

通过学习 当View为GONE状态时获取View的宽高 - zhuhai__yizhi的专栏 - CSDN博客 http://blog.csdn.net/zhuhai__yizhi/article/details/50897554得知当View为GONE状态时获取View的宽高方法,通过View.post()获取View的宽高引发的两个问题:1post的Runnable何时被执行,2为何View需要layout两次;以及发现Android的一个小bug - scnuxisan225的专栏 - CSDN博客 http://blog.csdn.net/scnuxisan225/article/details/49815269得知其原理逻辑。
步骤如下:
1.在xml布局把想平铺展开的控件设置为 android:visibility=”visible”
2.通过代码设置其不可见:

public class HomeActivity extends AppCompatActivity {

    @BindView(R.id.tv_showLayout)
    TextView tvShowLayout;
    @BindView(R.id.layout_info)
    LinearLayout layoutInfo;

    private int height = 10;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        ButterKnife.bind(this);

        // Android是消息驱动的模式,View.post的Runnable任务会被加入任务队列,
        // 并且等待第一次TraversalRunnable执行结束后才执行,此时已经执行过一次measure、layout过程了,
        // 所以在后面执行post的Runnable时,已经有measure的结果,因此此时可以获取到View的宽高
        layoutInfo.post(new Runnable() {
            @Override
            public void run() {
                //获取需要平铺展开的控件高度
                height = layoutInfo.getHeight();
                layoutInfo.setVisibility(View.GONE);
            }
        });
    }

    @OnClick({R.id.tv_showLayout})
    public void onViewClicked(View view) {
        HiddenAnimUtils.newInstance(HomeActivity.this, layoutInfo, tvShowLayout, height).toggle();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值