高仿淘票票头像动画
来源:明朗__     阅读:438
源码超市
发布于 2019-06-11 02:35
查看主页

当pm对上一版的马蜂窝头像泡泡动画审美疲劳后,这次又觉得淘票票的头像动画好看,而后。。。
先看看效果吧!

tpp_01

效果原理分析

  1. 布局排列


    tpp_02

这里可以同自己设置View 或者继承ViewGroup去实现 不过自己设置View复杂度会高很多 我这里也是继承FrameLayout 通过增加和排列ImageView去实现的

  1. 动画过程


    tpp_03

上图已经把整个过程形容很清楚,剩下就是控制动画不断循环执行 以及控制动画的中止、开始 、快慢等一系列操作了

具体实现

1. 布局的初始化排列相关

public class AmoyTicketLayout extends FrameLayout {   public AmoyTicketLayout(@NonNull Context context) {        this(context, null);    }    public AmoyTicketLayout(@NonNull Context context, @Nullable AttributeSet attrs) {        this(context, attrs, 0);    }    public AmoyTicketLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        initView(context);    }        private void initView(Context context) {        eachWidth = SizeUtils.dp2px(context, 35);        eachMargin = SizeUtils.dp2px(context, 7);        distance = eachWidth - eachMargin;        //先增加0号view        initFirstView();        //循环增加其他子View         for (int i = 5; i >= 0; i--) {            LayoutParams layoutParams = getLayoutParams(i);            ImageView roundedImageView = getImageView();            addView(roundedImageView, layoutParams);        }    }    //增加0号view 并缩放到最小    private void initFirstView() {        ImageView imageView = getImageView();        imageView.setScaleX(0);        imageView.setScaleY(0);        addView(imageView, getLayoutParams(5));    }    private ImageView getImageView() {        ImageView roundedImageView = new ImageView(getContext());        roundedImageView.setScaleType(ImageView.ScaleType.FIT_XY);        return roundedImageView;    }    //每个子View的marginRight距离是相同的     private LayoutParams getLayoutParams(int i) {        LayoutParams layoutParams = new LayoutParams(eachWidth,eachWidth);        layoutParams.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;        int marginRight = (distance) * i;        layoutParams.setMargins(0, 0, marginRight, 0);        return layoutParams;    }}

数据初始化

public void initData(ArrayList<Drawable> drawables) {        if (null == drawables || drawables.isEmpty()) return;        int childCount = getChildCount();        if (childCount == 0) return;        int size = drawables.size();        if (size < childCount) return;        this.drawables = drawables;        //记录图片资源取到哪里 用于循环时标记使用        position = childCount - 1;        for (int i = 0; i < childCount; i++) {            //以为布局中6号为最后一个View  但是要求显示的要是第一个图片            ImageView imageView = (ImageView) getChildAt(childCount -(i + 1));            imageView.setBackground(drawables.get(i));        }    }

由上操作就完成布局初始排列 和图片资源的加载显示

tpp_04

2. 动画的具体实现

 public void startAnimations() {        if (!stopAnimator) return;        if (null == drawables || drawables.isEmpty()) {            stopAnimator = false;            return;        }        ValueAnimator valueAnimator = ValueAnimator.ofFloat(1.0f, 0.0f);        valueAnimator.setDuration(1000);        valueAnimator.setInterpolator(new LinearInterpolator());        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                float animatedValue = (float) animation.getAnimatedValue();                int childCount = getChildCount() - 1;                float v = 1.0f - animatedValue;                //计算每个单元平移的距离                float translationX = distance * (v);                for (int i = 0; i < getChildCount(); i++) {                    ImageView childView = (ImageView) getChildAt(i);                    if (i == childCount) {//当view为最后一个时 也就是6号 做缩小操作                        childView.setScaleX(animatedValue);                        childView.setScaleY(animatedValue);                    } else if (i == 0) {//当view为第一个时 也就是0号 做放大操作                        childView.setScaleX(v);                        childView.setScaleY(v);                    } else {//其余view 就通不断改变marginRight 来做平移动作                        FrameLayout.LayoutParams layoutParams = (LayoutParams) childView.getLayoutParams();                        int marginRight = (distance) * (childCount - i);                        layoutParams.setMargins(0, 0, (int) (marginRight - translationX), 0);                        childView.setLayoutParams(layoutParams);                    }                }            }        });        valueAnimator.addListener(new AnimatorListenerAdapter() {            @Override            public void onAnimationStart(Animator animation) {                //动画开始确定最后一个View的缩放中心点                int childCount = getChildCount() - 1;                ImageView imageView = (ImageView) getChildAt(childCount);                imageView.setPivotX(eachWidth);                imageView.setPivotY(eachWidth / 2);            }            @Override            public void onAnimationEnd(Animator animation) {                int childCount = getChildCount() - 1;                //动画结束删除最后一个View  也就是6号                removeViewAt(childCount);                                //确定获取图片资源的index                position++;                if (position >= drawables.size()) {                    position = 0;                }                                ImageView imageView = getImageView();                imageView.setBackground(drawables.get(position));                imageView.setScaleX(0);                imageView.setScaleY(0);                //动画结束 创立0号View 放到1号后面 其余view的index 将一律加1                addView(imageView, 0, getLayoutParams(5));                //再次启动动画                startAnimation();            }        });        valueAnimator.start();    }

单次动效


tpp_05

利用Rxjava的timer()实现循环轮播效果

//动画开始  private void startAnimation() {        subscribe = Observable.timer(500, TimeUnit.MILLISECONDS)                .observeOn(AndroidSchedulers.mainThread())                .subscribe(new Consumer<Long>() {                    @Override                    public void accept(Long aLong) throws Exception {                        startAnimations();                    }                });    }//动画中止操作    public void stopAnimator() {        stopAnimator = false;        if (null != subscribe) {            subscribe.dispose();            subscribe = null;        }    }    

最终效果


tpp_07
免责声明:本文为用户发表,不代表网站立场,仅供参考,不构成引导等用途。 系统环境 服务器应用
相关推荐
Debian9.5创立账户的一般操作方法
Java集合面试问题
CSS设置背景模糊
vue class 动态公告的几种方式
React Native Apache Cordova?Cordova?跨平台移动应用开发工具
首页
搜索
订单
购物车
我的