美文网首页
雅虎新闻摘要加载

雅虎新闻摘要加载

作者: 有点健忘 | 来源:发表于2018-03-21 10:33 被阅读17次

    效果图请看这个帖子写的,跟着写的 https://www.jianshu.com/p/923513a70d15

    image.png
    看完别人的效果图,第一步不是赶紧往下看,而是自己脑子里想下,自己写的话该咋写。
    首先画6个小球,旋转, 然后往中心收缩,这都很常见,最后的扩散,我第一想到的是中心裁剪掉,也就是用clip方法了,也尝试自己写完看效果还行,然后跑去看作者的,发现作者很高明,通过修改paint的strokewidth来实现,又get到一个方法,不错。

    裁剪代码如下,150就是中间那空心的半径,从0开始变大

    path.reset();
            path.addCircle(0, 0, 150, Direction.CW);;
            canvas.clipPath(path, Region.Op.DIFFERENCE);
    

    clip用的也不多,所以没研究过Region.Op的几种都啥效果,就看着名字蒙了一个是对的。完事赶紧百度下,找到下边的几个帖子,可以学习下
    这里有clip那个属性的用法,看完这个,就赶紧画了个八卦图~~
    http://blog.csdn.net/richiezhu/article/details/52956163
    这里是介绍op的,感觉说的还不错,图文并茂
    http://www.runoob.com/w3cnote/android-tutorial-canvas-api2.html

    完整代码如下,简单说明下,因为不知道这种动画的具体要求,是不是小球一直转,等到加载完数据才手动调用方法来执行收缩和扩散动画,我就让它旋转一圈,监听动画结束完事开启收缩动画和扩散动画的,有需求再按照需求来吧,这里就随意了。

    import android.animation.Animator;
    import android.animation.AnimatorListenerAdapter;
    import android.animation.ValueAnimator;
    import android.animation.ValueAnimator.AnimatorUpdateListener;
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Paint.Style;
    import android.graphics.Path.Direction;
    import android.graphics.Path;
    import android.graphics.Region;
    import android.util.AttributeSet;
    import android.view.View;
    import android.view.animation.AccelerateInterpolator;
    import android.view.animation.AnticipateInterpolator;
    import android.view.animation.LinearInterpolator;
    
    public class DotRotate extends View {
    
        public DotRotate(Context context, AttributeSet attrs) {
            super(context, attrs);
            initPaint();
        }
    
        int[] colors = { Color.RED, Color.BLUE, Color.YELLOW, Color.GREEN, Color.GRAY, Color.parseColor("#215980") };
        float startAngle = 0;
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        Paint paintBG = new Paint(Paint.ANTI_ALIAS_FLAG);
        Path path=new Path();
        private void initPaint() {
            paint.setStyle(Style.FILL);
            paintBG.setColor(Color.WHITE);
            paintBG.setStyle(Style.STROKE);
        }
    
        int radius = 0;//原始几个小球的距离中心点的距离
        float radiusFactor = 1;//小球距离中心点的比例,收缩用
        
        int radiusMax;//扩散圆的最大值,用的宽高一半的
        float radiusTrans;//透密空心大小
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            int width=getMeasuredWidth()/2;
            int height=getMeasuredHeight()/2;
            radius =Math.min(width, height) * 2 / 3;//留点边界,所以就取2/3大小好啦
            radiusMax = (int) Math.sqrt(width*width+ height*height);
        }
        @Override
        protected void onDraw(Canvas canvas) {
    
            super.onDraw(canvas);
            if (radius == 0) {
                return;
            }
            
            float intervalAngle = (float) (2 * Math.PI / colors.length);
            canvas.save();
            canvas.translate(getWidth() / 2, getHeight()/2);
            
            if (radiusTrans > 0) {//开始中心扩散的时候,就不用画小球拉
                //通过裁剪实现
                path.reset();
                path.addCircle(0, 0, radiusTrans, Direction.CW);;
                canvas.clipPath(path, Region.Op.DIFFERENCE);
                canvas.drawColor(Color.WHITE);
                //或者用下边的代码
    //          paintBG.setStrokeWidth(radiusMax-radiusTrans);//画笔的宽就是减去透明部分的其他部分
                //举例说下,比如半径为40,画笔宽为10,那么最终线条是画在40-10/2,和40+10/2,就是说画笔宽度是平分在中心点的两边的,
                //所以下边就是计算中心点的坐标的代码拉
    //          canvas.drawCircle(0, 0, radiusTrans+(radiusMax-radiusTrans)/2, paintBG);
            } else {
                canvas.drawColor(Color.WHITE);
                for (int i = 0; i < colors.length; i++) {
                    double angle = startAngle + i * intervalAngle;
                    float x = (float) (radius * radiusFactor * Math.cos(angle));
                    float y = (float) (radius * radiusFactor * Math.sin(angle));
                    paint.setColor(colors[i]);
                    canvas.drawCircle(x, y, 10, paint);
                }
            }
    
            canvas.restore();
        }
    
        ValueAnimator animator;
    
        public void startAnimation() {
            animator = ValueAnimator.ofFloat(0, (float) (2 * Math.PI));
            animator.addUpdateListener(new AnimatorUpdateListener() {
    
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    startAngle = (Float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            animator.addListener(new AnimatorListenerAdapter() {
    
                @Override
                public void onAnimationEnd(Animator animation) {
                    startShrink();
    
                }
            });
            animator.setRepeatCount(0);
            animator.setDuration(2000);
            animator.setInterpolator(new LinearInterpolator());
            animator.start();
        }
    
        private void startShrink() {
            animator = ValueAnimator.ofFloat(1, 0.0f);//小球的半径缩放因子,从最大值到0
            animator.addUpdateListener(new AnimatorUpdateListener() {
    
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    radiusFactor = (Float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            animator.setDuration(1000);
            animator.setInterpolator(new AnticipateInterpolator());//有一个向外弹的动作,就靠这个加速器的
            animator.start();
            startEnd();
        }
    
        public void startEnd() {
            animator = ValueAnimator.ofFloat(10,radiusMax);
            animator.addUpdateListener(new AnimatorUpdateListener() {
    
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    radiusTrans =  (Float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            animator.addListener(new AnimatorListenerAdapter() {
    
                @Override
                public void onAnimationEnd(Animator animation) {
                    cancelAnimation();
                    setVisibility(GONE);
                }
            });
            animator.setDuration(1000);
            animator.setInterpolator(new AccelerateInterpolator());//用的加速插值器
            animator.setStartDelay(900);
            animator.start();
        }
    
        public void cancelAnimation() {
            if (animator != null) {
                animator.cancel();
                animator = null;
            }
        }
        
        
        @Override
        protected void onAttachedToWindow() {
            super.onAttachedToWindow();
            startAnimation();
        }
        @Override
        protected void onDetachedFromWindow() {
            if (animator != null) {
                animator.cancel();
                animator = null;
            }
            super.onDetachedFromWindow();
        }
    }
    
    

    附上kotlin版本

    import android.animation.Animator
    import android.animation.AnimatorListenerAdapter
    import android.animation.ValueAnimator
    import android.content.Context
    import android.graphics.*
    import android.util.AttributeSet
    import android.view.View
    import android.graphics.Paint.ANTI_ALIAS_FLAG
    import android.view.animation.AnticipateInterpolator
    
    /**
     * Created by charlie.song on 2018/6/4.
     */
    class LoadingView:View{
        constructor(context: Context?) : super(context){
            initPaint()
        }
        constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs){
            initPaint()
        }
        var colors = intArrayOf(Color.RED, Color.BLUE, Color.YELLOW, Color.GREEN, Color.GRAY, Color.parseColor("#215980"))//6个小球的颜色
        var startAngle = 0f //旋转的角度,弧度表示
        var paint = Paint(ANTI_ALIAS_FLAG) //小球用
        var paintBG = Paint(Paint.ANTI_ALIAS_FLAG)//画背景
        var paintClear=Paint() //裁剪中心用
        private fun initPaint() {
            paint.setStyle(Paint.Style.FILL)
            paintBG.setColor(Color.WHITE)
            paintBG.style=Paint.Style.FILL
            paintClear.setXfermode(PorterDuffXfermode(PorterDuff.Mode.CLEAR))//如果view设置了背景,那么clear的部分就会成灰黑色。
        }
    
        var radius = 0f//原始几个小球的距离中心点的距离
        var radiusFactor = 1f//小球距离中心点的比例,收缩用
        var clearRadius=0f;//中间透明的半径
        var path=Path()
        override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
            super.onLayout(changed, left, top, right, bottom)
            if(changed){
                radius=1f/4*Math.min(width,height)
            }
        }
    
        override fun onDraw(canvas: Canvas) {
            super.onDraw(canvas)
            if(radius==0f){
                return
            }
            canvas.save()
            canvas.translate(width/2f,height/2f)
            if(clearRadius>0){
                //注释的方法,如果要用,则得确保没有设置background,否则clear的部分就成了黑色了。
    //            canvas.drawColor(Color.DKGRAY)
    //            canvas.drawCircle(0f,0f,clearRadius,paintClear)
                canvas.clipPath(path.apply {
                    reset()
                    addCircle(0f,0f,clearRadius,Path.Direction.CW)
                },Region.Op.DIFFERENCE)
                canvas.drawColor(Color.DKGRAY) //需要注意,裁剪的时候先裁剪后绘制,否则无效
            }else{
                canvas.drawColor(Color.DKGRAY)
                //draw 6 balls
                (0 ..5).forEach {
                    val r=radius*radiusFactor;
                    val angle=Math.PI/180*60*it+startAngle
                    val x=r*Math.cos(angle)
                    val y=r*Math.sin(angle)
                    paint.color=colors[it]
                    canvas.drawCircle(x.toFloat(),y.toFloat(),10f,paint)
                }
            }
            canvas.restore()
        }
        private fun resetDefault(){
            startAngle=0f
            radiusFactor=1f
            clearRadius=0f;
        }
        var animaRotate:ValueAnimator?=null
         fun startLoading(){
             resetDefault()
            animaRotate=ValueAnimator.ofFloat(0f,Math.PI.toFloat()*2).apply {
                setDuration(2000L)
                repeatCount=ValueAnimator.INFINITE
                addUpdateListener(object : ValueAnimator.AnimatorUpdateListener{
                    override fun onAnimationUpdate(animation: ValueAnimator) {
                        startAngle=animation.animatedValue as Float
                        postInvalidate()
                    }
                })
                interpolator=null//改为线性加速,默认是中间加速的
                start()
            }
        }
    
        fun stopLoading(){
            animaRotate?.cancel()
            ValueAnimator.ofFloat(1f,0f).apply {
                setDuration(500L)
                addUpdateListener( object :ValueAnimator.AnimatorUpdateListener{
                    override fun onAnimationUpdate(animation: ValueAnimator) {
                        radiusFactor=animation.animatedValue as Float
                        postInvalidate()
                    }
                })
                addListener(object :AnimatorListenerAdapter(){
                    override fun onAnimationEnd(animation: Animator?) {
                        cancel()
                        startShowByCircle()
                    }
                })
                interpolator=AnticipateInterpolator()
                start()
            }
        }
    
        private fun startShowByCircle(){
            ValueAnimator.ofFloat(0f, Math.sqrt(width*width/4.0+height*height/4.0).toFloat()).apply {
                setDuration(700L)
                addUpdateListener( object :ValueAnimator.AnimatorUpdateListener{
                    override fun onAnimationUpdate(animation: ValueAnimator) {
                        clearRadius=animation.animatedValue as Float
                        postInvalidate()
                    }
                })
                start()
            }
        }
    
        override fun onDetachedFromWindow() {
            super.onDetachedFromWindow()
            animaRotate?.cancel()
        }
    }
    

    相关文章

      网友评论

          本文标题:雅虎新闻摘要加载

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