美文网首页
Android——自定义View(三)

Android——自定义View(三)

作者: 如愿以偿丶 | 来源:发表于2019-09-29 22:01 被阅读0次

    1.概述

      最近看到 红橙Darren 写的贝塞尔曲线 - 花束直播点赞效果后实现,来记录一下自己实现的步骤。

    2.效果

                  在这里插入图片描述

    3.实现思路:

      1.点击添加按钮的时候有一张图片
      2.延S型曲线从底部向上运动

    在这里插入图片描述

    4.开始

      4.1.自定义RelativeLayout,初始化一些基本的参数

        public class LoveLayout extends RelativeLayout {
            //随机数
            private Random mRandom;
            //设置资源
            private int[] mImageRes;
            //屏幕宽高
            private int mWidth,mHeight;
            //图片的宽高
            private int mResWidth,mResheight;
            //插值器集合
            private Interpolator[] mInterpolator;
        
            public LoveLayout(Context context) {
                this(context,null);
            }
        
            public LoveLayout(Context context, AttributeSet attrs) {
                this(context, attrs,0);
            }
        
            public LoveLayout(Context context, AttributeSet attrs, int defStyleAttr) {
                super(context, attrs, defStyleAttr);
                init();
            }
        
            private void init() {
                //1.初始化随机数
                mRandom = new Random();
                //2.初始化资源图片
                mImageRes = new int[]{R.drawable.green,R.drawable.red,R.drawable.note};
                //3.获取图片的宽高
                Drawable drawable = getContext().getResources().getDrawable(R.drawable.green);
                mResheight = drawable.getIntrinsicHeight();
                mResWidth = drawable.getIntrinsicWidth();
                //4.插值器集合
        //        mInterpolator = new Interpolator[]{new AccelerateDecelerateInterpolator()
        //                                            ,new AccelerateInterpolator()
        //                                            ,new DecelerateInterpolator()
        //                                            ,new LinearInterpolator()};
            }
        
        
            @Override
            protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
                mWidth = MeasureSpec.getSize(widthMeasureSpec);
                mHeight = MeasureSpec.getSize(heightMeasureSpec);
            }
    }
    

      4.2.点击添加按钮,不断的往RelativeLayout中添加随机的ImageView,然后开始执行缩放和透明度的动画,采用属性动画ObjectAnimator.ofFloat();

        public void addView() {
             //创建ImageView,设置图片资源
             final ImageView ivLove = new ImageView(getContext());
             //设置图片资源随机
             ivLove.setImageResource(mImageRes[mRandom.nextInt(mImageRes.length)]);
             //设置图片添加位置
             RelativeLayout.LayoutParams params =  new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
             params.addRule(ALIGN_PARENT_BOTTOM);
             params.addRule(CENTER_HORIZONTAL);
             ivLove.setLayoutParams(params);
             //添加到父容器
             addView(ivLove);
        
             //添加属性动画  缩放和透明度效果
             AnimatorSet set = getAnimator(ivLove);
             //执行动画
             set.start();
          }
        
        private AnimatorSet getAnimator(ImageView ivLove) {
             //1.设置动画,透明度,缩放
             AnimatorSet innerAnimator = new AnimatorSet();
             ValueAnimator alphaAnimator = ObjectAnimator.ofFloat(ivLove,"alpha",0.5f,1f);
             ValueAnimator scaleXAnimator = ObjectAnimator.ofFloat(ivLove,"scaleX",0.5f,1f);
             ValueAnimator scaleYAnimator = ObjectAnimator.ofFloat(ivLove,"scaleY",0.5f,1f);
             innerAnimator.setDuration(350);
             //一起执行
             innerAnimator.playTogether(alphaAnimator,scaleXAnimator,scaleYAnimator);
             return innerAnimator ;
            }    
        }
    

      4.3.将图片延S型曲线进行运动(使用贝塞尔曲线 + 属性动画 + 自定义TypeEvaluator)

    先看一下公式

    在这里插入图片描述
        /**
         * 贝塞尔路径动画  自定义TypeEvaluator
         * @return
         */
        private Animator getBezierAnimator(final ImageView ivLove) {
            //1.四个点 p0,p1,p2,p3
            PointF point0 = new PointF(mWidth / 2 - mResWidth / 2,mHeight - mResheight) ;
            //2.P2点的y坐标要大于p1点的y坐标
            PointF point1 = getPoint(1);
            PointF point2 = getPoint(2);
            //终点为屏幕的一半
            Log.e("getBezierAnimator",mHeight+"");
            PointF point3 = new PointF(mRandom.nextInt(mWidth - mResWidth),0);
    
            //构造方法中传入中间的点
            LoveTypeEvaluator typeEvaluator = new LoveTypeEvaluator(point1,point2);
            ValueAnimator bezierAnimator = ObjectAnimator.ofObject(typeEvaluator,point0,point3);
    //        bezierAnimator.setInterpolator(mInterpolator[mRandom.nextInt(mInterpolator.length -1)]);
            bezierAnimator.setDuration(6000);
            bezierAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    //获取当前的值
                    PointF pointF = (PointF) animation.getAnimatedValue();
                    //设置位置
                    ivLove.setX(pointF.x);
                    ivLove.setY(pointF.y);
                    //获取的是自定义TypeEvaluator,evaluate方法中的t值,该值是0-1的
                    float alpha = animation.getAnimatedFraction(); //他是0-1的数
                    ivLove.setAlpha(1- alpha + 0.2f);
                }
            });
    
            return bezierAnimator;
        }
    
        /**
         * 1代表p1  2代表p2
         * p1的时候y最大值位 mHeight / 2
         * p2的时候y最大值 mHeight / 2 + ((2-1) *mHeight / 2) = mHeight
         * @param index
         * @return
         */
        private PointF getPoint(int index) {
            return new PointF(mRandom.nextInt(mWidth - mResWidth),mRandom.nextInt(mHeight / 2 +(index-1)*mHeight/2));
        }
    
        //自定义TypeEvaluator
        public class LoveTypeEvaluator implements TypeEvaluator<PointF> {
            //中间点p1,p2,实现TypeEvaluator实现的evaluate方法只有起始点和终点,所以中间点需要我们通过构造方法传入
            private PointF point1;
            private PointF point2;
        
            public LoveTypeEvaluator(PointF point1, PointF point2) {
                this.point1 = point1;
                this.point2 = point2;
            }
        
            /**
             *
             * @param t [0 ,1]
             * @param point0    起始点
             * @param point3    终点
             * @return
             */
            @Override
            public PointF evaluate(float t, PointF point0, PointF point3) {
                PointF pointF = new PointF();
                //直接套上方的公式,三阶贝塞尔曲线
                pointF.x = point0.x * (1-t) * (1-t) * (1-t)
                            + 3 * point1.x * t * (1-t) * (1-t)
                            + 3 * point2.x * t * t * (1 - t)
                            + point3.x * t * t * t;
        
                pointF.y = point0.y * (1-t) * (1-t) * (1-t)
                            + 3 * point1.y * t * (1-t) * (1-t)
                            + 3 * point2.y * t * t * (1 - t)
                            + point3.y * t * t * t;
                return pointF;
            }
        }
    

    5.最终总结

      5.1.自定义的RelativeLayout

    /**
     * Created by ych on 2019/8/17.
     * Description: 花束直播点赞
     *      分析:1.点击的时候会有一张图片有放大和透明度的变化,图片向上延S路运动,图片是随机的图片
     *            2.移动的过程也有透明度变化
     *      思路:添加图片addView
     */
        public class LoveLayout extends RelativeLayout {
            //随机数
            private Random mRandom;
            //设置资源
            private int[] mImageRes;
            //屏幕宽高
            private int mWidth,mHeight;
            //图片的宽高
            private int mResWidth,mResheight;
            //插值器集合
            private Interpolator[] mInterpolator;
        
            public LoveLayout(Context context) {
                this(context,null);
            }
        
            public LoveLayout(Context context, AttributeSet attrs) {
                this(context, attrs,0);
            }
        
            public LoveLayout(Context context, AttributeSet attrs, int defStyleAttr) {
                super(context, attrs, defStyleAttr);
                init();
            }
        
            private void init() {
                //1.初始化随机数
                mRandom = new Random();
                //2.初始化资源图片
                mImageRes = new int[]{R.drawable.green,R.drawable.red,R.drawable.note};
                //3.获取图片的宽高
                Drawable drawable = getContext().getResources().getDrawable(R.drawable.green);
                mResheight = drawable.getIntrinsicHeight();
                mResWidth = drawable.getIntrinsicWidth();
                //4.插值器集合
        //        mInterpolator = new Interpolator[]{new AccelerateDecelerateInterpolator()
        //                                            ,new AccelerateInterpolator()
        //                                            ,new DecelerateInterpolator()
        //                                            ,new LinearInterpolator()};
            }
        
        
            @Override
            protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
                mWidth = MeasureSpec.getSize(widthMeasureSpec);
                mHeight = MeasureSpec.getSize(heightMeasureSpec);
            }
        
            public void addView() {
                //创建ImageView,设置图片资源
                final ImageView ivLove = new ImageView(getContext());
                //设置图片资源随机
                ivLove.setImageResource(mImageRes[mRandom.nextInt(mImageRes.length)]);
                //设置图片添加位置
                RelativeLayout.LayoutParams params =  new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
                params.addRule(ALIGN_PARENT_BOTTOM);
                params.addRule(CENTER_HORIZONTAL);
                ivLove.setLayoutParams(params);
                //添加到父容器
                addView(ivLove);
        
                //添加属性动画  放大和透明度效果
                AnimatorSet set = getAnimator(ivLove);
                set.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        //将view移除
                        removeView(ivLove);
                    }
                });
                set.start();
        
            }
        
            private AnimatorSet getAnimator(ImageView ivLove) {
                AnimatorSet allAnimatorSet = new AnimatorSet();
        
                //1.设置动画,透明度,缩放
                AnimatorSet innerAnimator = new AnimatorSet();
                ValueAnimator alphaAnimator = ObjectAnimator.ofFloat(ivLove,"alpha",0.5f,1f);
                ValueAnimator scaleXAnimator = ObjectAnimator.ofFloat(ivLove,"scaleX",0.5f,1f);
                ValueAnimator scaleYAnimator = ObjectAnimator.ofFloat(ivLove,"scaleY",0.5f,1f);
                innerAnimator.setDuration(350);
                //一起执行
                innerAnimator.playTogether(alphaAnimator,scaleXAnimator,scaleYAnimator);
        
                //2.设置运动路径动画    playSequentially按顺序一次执行
                allAnimatorSet.playSequentially(innerAnimator,getBezierAnimator(ivLove));
        
                return allAnimatorSet;
            }
        
            /**
             * 贝塞尔路径动画  自定义TypeEvaluator
             * @return
             */
            private Animator getBezierAnimator(final ImageView ivLove) {
                //1.四个点 p0,p1,p2,p3
                PointF point0 = new PointF(mWidth / 2 - mResWidth / 2,mHeight - mResheight) ;
                //2.P2点的y坐标要大于p1点的y坐标
                PointF point1 = getPoint(1);
                PointF point2 = getPoint(2);
                //终点为屏幕的一半
                Log.e("getBezierAnimator",mHeight+"");
                PointF point3 = new PointF(mRandom.nextInt(mWidth - mResWidth),0);
        
                //构造方法中传入中间的点
                LoveTypeEvaluator typeEvaluator = new LoveTypeEvaluator(point1,point2);
                ValueAnimator bezierAnimator = ObjectAnimator.ofObject(typeEvaluator,point0,point3);
        //        bezierAnimator.setInterpolator(mInterpolator[mRandom.nextInt(mInterpolator.length -1)]);
                bezierAnimator.setDuration(6000);
                bezierAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        //获取值
                        PointF pointF = (PointF) animation.getAnimatedValue();
                        //设置最终之
                        ivLove.setX(pointF.x);
                        ivLove.setY(pointF.y);
                        //逐渐消失
                        float alpha = animation.getAnimatedFraction(); //他是0-1的数
                        ivLove.setAlpha(1- alpha + 0.2f);
                    }
                });
        
                return bezierAnimator;
            }
        
            /**
             * 1代表p1  2代表p2
             * p1的时候y最大值位 mHeight / 2
             * p2的时候y最大值 mHeight / 2 + ((2-1) *mHeight / 2) = mHeight
             * @param index
             * @return
             */
            private PointF getPoint(int index) {
                return new PointF(mRandom.nextInt(mWidth - mResWidth),mRandom.nextInt(mHeight / 2 +(index-1)*mHeight/2));
            }
        }
    

      5.2.自定义的TypeEvaluator

        /**
         * Created by ych on 2019/8/17.
         * Description:
         */
        public class LoveTypeEvaluator implements TypeEvaluator<PointF> {
            //中间点
            private PointF point1;
            private PointF point2;
        
            public LoveTypeEvaluator(PointF point1, PointF point2) {
                this.point1 = point1;
                this.point2 = point2;
            }
        
            /**
             *
             * @param t [0 ,1]
             * @param point0    起始点
             * @param point3    终点
             * @return
             */
            @Override
            public PointF evaluate(float t, PointF point0, PointF point3) {
                PointF pointF = new PointF();
                //直接套公式,三阶贝塞尔曲线
                pointF.x = point0.x * (1-t) * (1-t) * (1-t)
                            + 3 * point1.x * t * (1-t) * (1-t)
                            + 3 * point2.x * t * t * (1 - t)
                            + point3.x * t * t * t;
        
                pointF.y = point0.y * (1-t) * (1-t) * (1-t)
                            + 3 * point1.y * t * (1-t) * (1-t)
                            + 3 * point2.y * t * t * (1 - t)
                            + point3.y * t * t * t;
                return pointF;
            }
        }
    

    相关文章

      网友评论

          本文标题:Android——自定义View(三)

          本文链接:https://www.haomeiwen.com/subject/bavqpctx.html