美文网首页
Android开发(12)——属性动画

Android开发(12)——属性动画

作者: 让时间走12138 | 来源:发表于2021-03-27 20:38 被阅读0次

    本节内容

    1.菜单效果实战

    2.旋转动画

    3.缩放平移透明度动画

    4.ViewPropertyAnimator

    5.属性动画实现菜单效果

    一、菜单效果实战(补间动画实战)
    1.做一个简单的菜单,点击一个按钮,然后从按钮下方弹出一些控件。
    image.png
    • 如上图,点击一下红色按钮,然后就会弹出黑色的这些控件,再点击一下,它们又会收回去。这些控件出来的时候,会带有一些旋转和移动的动画。(按道理,这些黑色按钮应该是在一条竖线上的,但是这里没有,可能是因为我出了点bug)
    2.红色的按钮在最上方,黑色的那些按钮都在红色按钮的后面,所以一开始只有红色按钮显示出来。
    3.最开始配置一下activity_main.xml,先拖动这些图片到drawable中,然后给每个按钮都设置一个id,然后用约束布局,布局一下。注意:这个时候要把所有的黑色按钮都放在红色按钮后面。最外面只有一个红色按钮。
    4.按钮的旋转动画是一样的,但是移动动画不一样。.因为旋转动画都是一样的,所以旋转动画直接用xml布局。创建一个anim包,然后新建一个resourcefile
    <rotate xmlns:android="http://schemas.android.com/apk/res/android"
        android:fromDegrees="0"
        android:toDegrees="360"
        android:pivotX="50%"
        android:pivotY="50%"
        />
    
    5.在MainActivity里面写一个函数,实现加载旋转动画。
     private fun loadRotateAnim() = AnimationUtils.loadAnimation(this,R.anim.rotate_anim)
    
    6.用代码实现加载移动动画的方法。
     private fun loadTranslateAnim(index:Int,isOpen:Boolean):TranslateAnimation{
           var startY:Float = 0f
           var endY :Float = 0f
           if(isOpen){
               endY = ((index+1)*(menu1.height+7)).toFloat()
           }else{
               startY = ((index+1)*(menu1.height+7)).toFloat()
           }
          return TranslateAnimation(0f,0f,startY, endY)
       }
    
    • isOpen:用来记录菜单现在是打开的还是闭合的。
    • index是从0开始的,所以我们设置移动的距离为(index+1)*(menu1.height+7),也就是黑色按钮的高度+7,然后乘以相应的倍数,这样的排列就比较美观。
    7.因为六个黑色按钮要同时实现动画效果,所以要把这几个按钮用数组存储一下
    private val menus : Array<ImageView> by lazy {
            arrayOf(menu1,menu2,menu3,menu4,menu5,menu6)
        }
    
    8.给红色按钮添加点击事件
    menuBtn.setOnClickListener{
                for((i,item) in menus.withIndex()) {
                    //旋转动画
                    //移动动画
                    //AnimationSet  包裹这两个动画
                    AnimationSet(true).apply {
                        addAnimation(loadRotateAnim())
                        addAnimation(loadTranslateAnim(i,isOpen))
                        duration=1000
                        fillAfter= true
                        interpolator = BounceInterpolator()
                        item.startAnimation(this)
                    }
                }
                isOpen = !isOpen
            }
    
    • interpolator = BounceInterpolator(),设置一个弹簧效果,看起来比较美观。interpolator:插值器。动画从起始到结束有一个过程,默认是匀速的,但是这个插值器就让它这个过程有了一些特殊的节奏。插值器有很多种类型,这个弹簧效果只是其中一种。
    9.设置一个变量来记录菜单是打开还是收回的。(前面是最终的代码,所以提前出现了isOpen)
    private var isOpen:Boolean = true
    
    • 结合前面loadTranslateAnim里的代码食用,如果菜单是打开的,那么endY为(index+1)(menu1.height+7),否则satrtY=(index+1)(menu1.height+7)。
    10.这个demo有一个bug,当弹出菜单序列的时候,我们点击黑色的按钮,但是并没有任何效果。因为补间动画只是 视觉上的动画效果,并没有真正改变控件的对应属性,所以这个按钮并不会真正被点击。例如我们添加以下代码:
    menu1.setOnClickListener{
                Log.v("swl","相机按钮被点击了")
            }
    
    • 当我们点击黑色按钮的时候,并不会出现“相机按钮被点击了”的文字提示。按钮的实体还是在红色按钮后面,它的y坐标并没有真正被改变。
    • 想要解决这个问题,还是需要用上属性动画,它可以真正更改视图对应的属性。
    二、旋转动画
    1.先在xml中随便布局一下,添加一个矩形和一个按钮,分别给它们添加一下id,然后给按钮设置一下点击事件。
    2.对于属性动画来说,不管是旋转,平移,缩放等都是ObjectAnimator来进行管理的。
    ObjectAnimator.ofFloat(view,"rotationX",0f,360f).apply {
                duration = 1000
                addListener(object :Animator.AnimatorListener{
                override fun onAnimationRepeat(animation: Animator?) {
                }
    
                override fun onAnimationEnd(animation: Animator?) {
                }
    
                override fun onAnimationCancel(animation: Animator?) {
                }
    
                override fun onAnimationStart(animation: Animator?) {
                }
    
                })
                addPauseListener(object :Animator.AnimatorPauseListener{
                override fun onAnimationPause(animation: Animator?) {
                }
    
                override fun onAnimationResume(animation: Animator?) {
                }
    
                })
                addUpdateListener (object :ValueAnimator.AnimatorUpdateListener{
                override fun onAnimationUpdate(animation: ValueAnimator?) {
                }
                })
                start()
                }
    
    • 第一个参数view,为动画的对象。第二个参数“rotationX”表示绕着水平中心线旋转,后面是旋转的起始度数和结束度数。
    • addListener:动画的监听器,有一些必须实现的方法。可以监听动画的开始、结束、取消和重复。
    • addPauseListener:暂停动画的监听器。可以监听动画暂停了,动画又重新开始了。
    • addUpdateListener:获取数据的更新范围。
    三、缩放平移透明度动画
    1.缩放动画
    val scaleX=  ObjectAnimator.ofFloat(view,"scaleX",0.1f,1.2f,1.0f,1.5f).apply {
                duration  =1000
                }
    val scaleY=  ObjectAnimator.ofFloat(view,"scaleY",0.1f,1.2f,1.0f,1.5f).apply {
                duration  =1000
                }
    
    如果想让宽和高同时动,那么可以使用两个函数。 playSequentially(scaleX,scaleY)顺序播放, playTogether(scaleX,scaleY)同时播放。
     AnimatorSet().apply {
                //顺序播放
                playSequentially(scaleX,scaleY)
                //同时播放
                playTogether(scaleX,scaleY)
                start()
                }
    
    还有一个方法可以让宽和高的动画同时播放。
                val holderX=
                PropertyValuesHolder.ofFloat("scaleX",0.1f,1.2f,1.0f,1.5f)
                val holderY =
                PropertyValuesHolder.ofFloat("scaleY",0.1f,1.2f,1.0f,1.5f)
    
                ObjectAnimator.ofPropertyValuesHolder(view,holderX,holderY).apply {
                duration = 1000
                start()
                }
    
    2.透明度动画
    ObjectAnimator.ofFloat(view,"alpha",0.5f,1.0f,0f).apply {
                duration =1000
                start()
                }
    
    • 透明度从0.5f变为1.0f,再变为0f。中间值可以设很多,它都会经历。
    3.平移动画
    ObjectAnimator.ofFloat(view,"translationX",300f,200f,250f).apply {
                duration = 1000
                start()
    
    • 先向右平移300f,再移动到200f,最后移动到250f,都是相对于控件最右侧的距离
    • 如果想让x和y方向上都有移动,那么可以使用PropertyValuesHolder
     val tx = PropertyValuesHolder.ofFloat("translationX",300f,200f,250f)
                val ty = PropertyValuesHolder.ofFloat("translationY",300f,200f,250f)
    
                ObjectAnimator.ofPropertyValuesHolder(view,tx,ty).apply {
                duration =1000
                start()
                }
    
    四、ViewPropertyAnimator
    1.如果是对view的属性来进行动画 可以使用简洁版的ObjectAnimator -

    ValuePropertyAnimator

    • 旋转360度
    view.animate().rotation(360f)
    
    • 透明度,淡出到0f。从1f到0f。
    view.animate().alpha(0f)
    
    • 移动,每次向右移动100f。在之前的基础上移动。
    view.animate().translationXBy(100f)
    
    • 让x和y都移动
         view.animate().translationXBy(100f)
                .translationYBy(100f).apply {
                duration =1000
                }
    
    • 缩放到1.5倍
    view.animate().scaleX(1.5f)
                .scaleY(1.5f)
    
    • 多个动画同时进行
           view.animate()
                    .scaleX(1.5f)
                    .scaleY(1.5f)
                    .alpha(0.5f)
                    .rotation(360f)
                    .alpha(1.0f).setDuration(2000)
    
    2.ViewPropertyAnimator和ObjectAnimator的比较
    • ViewPropertyAnimator :使用方便 值单一 同时进行
    • ObjectAnimator :多个值 控制顺序或同时进行
    3.ValueAnimator:动画过程中每个阶段的具体数据是用ValueAnimator来管理的,一般是用来自定义控件的。
    ValueAnimator.ofFloat(0f,100f).apply {
                    duration =1000
                    addUpdateListener (object :ValueAnimator.AnimatorUpdateListener{
                        override fun onAnimationUpdate(animation: ValueAnimator?) {
                      Log.v("swl","${animation?.animatedValue}")
                        }
                    })
                    start()
                }
    
    • 我们需要的数据是0-100,那么我们点击按钮之后,它每隔一段时间就会产生一个新的值给我们,是一个中间的数据。
    五、属性动画实现菜单效果
    1.首先图片控件和判断菜单是否打开的变量和之前一样
    private var isOpen:Boolean = true
        private val menus :Array<ImageView> by lazy{
            arrayOf(menu1,menu2,menu3,menu4,menu5,menu6)
        }
    
    2.给按钮设置点击事件。
    menuBtn.setOnClickListener {
                for((i,item)in menus.withIndex()){
                    //ObjectAnimator   多个值  1.5, 0.8 0.0
                    //ViewPropertyAnimator  一个值
                 //旋转 360
                    //移动  100
                    val ty = if(isOpen) (i+1)*(menu6.height+70).toFloat()  else 0f
                    item.animate()
                        .rotation(360f)
                        .translationY(ty)
                        .interpolator = BounceInterpolator()
    
                }
                isOpen = !isOpen
            }
    
    • 因为只有纵向上的移动,所以用translationY()方法。
    3.给黑色按钮设置点击事件
    menu1.setOnClickListener{
                Log.v("swl","相机打开了")
            }
    
    • 这个时候,再点击黑色按钮,底下就会打印相应的数据了。
    image.png

    相关文章

      网友评论

          本文标题:Android开发(12)——属性动画

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