美文网首页
Android开发(18)——自定义加载动画(1):贪吃加载动画

Android开发(18)——自定义加载动画(1):贪吃加载动画

作者: 让时间走12138 | 来源:发表于2021-04-06 19:47 被阅读0次

    本节内容

    1.Demo简介

    2.分析贪吃动画的尺寸比例

    3.画圆

    4.实现张嘴闭嘴动画

    5.小球移动动画

    一、demo简介
    1.效果展示如下图,我截了三个瞬间,但其实这是一个连续的动画,就是这个大圆不停地吞下小圆。
    image.png
    QQ图片20210406180050.png
    QQ图片20210406180117.png
    2.这个动画可以拆分为两部分,首先是大圆张嘴闭嘴的动画,相当于画一个圆弧,规定一下它的角度就好。小圆就是一个从右向左移动的动画。然后不停地刷新界面,让动画的持续时间为永恒,这样就会有一个持续的动态效果。
    二、分析贪吃动画的尺寸比例
    1.在制作动画之前,我们要先建一个模型,来确定一下大圆和小圆的比例。这个比例是自己设置的,可以自行修改。下图是画布的宽度大于高度的情况。
    • R = minHeight /6
    • Cx = (width - minwidth)/2 + 3R
    • Cy = height/2
    image.png
    还有一种是画布宽度小于高度的情况,如下图所示:这个时候
    • 6R+0.5R+2R = minwidth。 R = minwidth /8.5
    • Cx = 3R
    • Cy =height/2
    image.png
    2.确定了大圆圆心坐标之后,小圆的圆心坐标也可以知道了。
    三、画圆
    1.先创建一个类继承自view,并实现其对应的构造方法
    class MouseLoadingView : View {
        constructor(context: Context):super(context){}
        constructor(context: Context,attrs:AttributeSet?):super(context,attrs){}
        constructor(context: Context,attrs:AttributeSet?,style:Int):super(context,attrs,style){}
    }
    
    2.定义一下大圆(嘴)的半径(3R),小圆的半径(R)以及两圆之间的间距(0.5R),还有嘴的圆心坐标
     //嘴的半径
        private var mouseRadius = 0f
        //小圆的半径
        private var ballRadius = 0f
        //嘴和小球的间距
        private var space = 0f
     //嘴的圆心
        private var cx = 0f
        private var cy = 0f
    
    3. 在onSizeChanged方法里面计算尺寸。
     override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
           if(measuredWidth>=measuredHeight){
               ballRadius= measuredHeight/6f
                cx = (measuredWidth-8.5f*ballRadius)/2 + 3*ballRadius
            }else{
               ballRadius= measuredWidth/8.5f
                cx = 3*ballRadius.toFloat()
            }
            mouseRadius = 3*ballRadius
            space = ballRadius/2f
    
            cy = measuredHeight/2f
        }
    
    4.提供一个画笔
    //画笔
        private val mPaint = Paint().apply {
            style = Paint.Style.FILL
            color = context.resources.getColor(R.color.colorAccent,null)
        }
    
    5.在onDraw方法里面画一个圆
    override fun onDraw(canvas: Canvas?) {
     canvas?.drawCircle(cx,cy,mouseRadius,mPaint)
    }
    
    6.在xml文件里面添加这个自定义类
      <com.example.loadinganim.MouseLoadingView
            android:id="@+id/loadingView"
            android:layout_width="100dp"
            android:layout_height="100dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.498"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.11" />
    
    7.如果用上面的方法来画圆,会出现一些bug,如下图所示
    image.png
    这是因为,当宽度大于高度时,R= height/6。如果R过小,那么圆心的坐标就会偏左,那么就会有一部份圆出界。为了避免这种情况发生,无论什么情况下,都把R设置为最小的那个/8.5。
    8.重新计算一下半径
    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
            super.onSizeChanged(w, h, oldw, oldh)
            //计算尺寸
            //小球的半径
           ( Math.min(measuredHeight,measuredWidth)/8.5f ).also {r->
                ballRadius = r
                //嘴的半径
                mouseRadius = 3*r
                //嘴和小球的间距
                space = r/2
    
                //嘴的圆心
                cx = ((measuredWidth- 8.5*r)/2 + 3*r).toFloat()
                cy = measuredHeight/2f
            }
        }
    
    四、实现张嘴闭嘴动画
    1.张嘴相当于画了一个弧,画弧需要确定一个矩形区域——即大圆所在的矩形。还需要设置一个角度,也就是弧度。绘制出来如下图所示。
    override fun onDraw(canvas: Canvas?) {
     canvas?.drawArc(
                cx-mouseRadius,
                cy-mouseRadius,
                cx+mouseRadius,
                cy+mouseRadius,
               45f,270f,true,mPaint
            )
    }
    
    image.png
    2.这是一个静态的过程,想让它变成动态的话,只需要一直修改嘴张开的角度即可。所以我们定义一个动画因子,作为弧度
     //嘴张开的角度 - >张嘴的动画因子
         private var mouseAngle = 0f
    
    3.然后在onDraw方法里面,把死数据改为我们动画因子即可。
    canvas?.drawArc(
               cx-mouseRadius,
               cy-mouseRadius,
               cx+mouseRadius,
               cy+mouseRadius,
               mouseAngle,360-2*mouseAngle,true,mPaint
           )
    
    4.添加两个按钮,来显示动画和暂停动画。当点击按钮时,实现对应的点击事件。
    5.所以在MouseLoadingView类里面提供几个方法给外部调用
        }
        //提供给外部使用
        //显示动画
        fun show(){
         createAnimator()
            start()
        }
        //隐藏动画
        fun hide(){
          stop()
        }
    
    6.createAnimator()是创建动画的函数。从0-45-0的是动画因子的变化,监听一下动画执行的过程,不断刷新动画因子的数值,然后刷新界面。
    private fun createAnimator() {
        ValueAnimator.ofFloat(0f, 45f, 0f).apply {
                duration = 650
                repeatCount = ValueAnimator.INFINITE
                addUpdateListener {
                    mouseAngle = it.animatedValue as Float
                    //刷新界面
                    invalidate()
                }
                animators.add(this)
            }
    }
    
    7.因为动画效果有很多,所以我们要用一个数组来保存所有的动画
      //保存所有的动画对象
        private var animators = mutableListOf<ValueAnimator>()
    
    8.添加几个启动和结束动画的方法
    //启动动画
        private fun start(){
            for(anim in animators){
                anim.start()
            }
        }
    //暂停动画
        private fun stop(){
        for(anim in animators){
            anim.end()
        }
    
    五、小球移动动画
    1.创建一个小球,然后让它从右边向左边移动即可。小球圆心的x坐标在不断改变,y坐标与大圆一样。所以我们要给小球设置一个移动的动画因子。
    //小球移动的动画因子
        private var ballTranslateX = 0f
    
    2.然后在onDraw()方法里面绘制小球
            //绘制小球
            canvas?.drawCircle(cx+ballTranslateX,cy,ballRadius,mPaint)
    
    3.之后,在createAnimator()方法里面添加小球的动画。让小球移动的距离从4.5R到0,也就是直到小圆与大圆重合。
     ValueAnimator.ofFloat(4.5f*ballRadius, 0f).apply {
                duration = 650
                repeatCount = ValueAnimator.INFINITE
                addUpdateListener {
                    ballTranslateX = it.animatedValue as Float
                    //刷新界面
                    invalidate()
                }
                animators.add(this)
            }
    
    4.在MainActivity里面添加按钮的点击事件
    class MainActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            startBtn.setOnClickListener{
                loadingView.show()
                pauseView.show()
            }
    
            stopBtn.setOnClickListener {
                loadingView.hide()
                pauseView.hide()
            }
        }
    }
    
    差不多就这些内容。自定义加载动画的难点,主要在于找到动画因子。

    相关文章

      网友评论

          本文标题:Android开发(18)——自定义加载动画(1):贪吃加载动画

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