kotlin-转场动画基础

2020-11-05  本文已影响0人  jeffrey12138

原本想直接写自定义VIew的,然后看到前面还有转场动画,就顺手学了。

先说下animator来实现的转场动画,xml布局如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".RevealActivity">
    <CheckBox
        android:text="Play animation"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/checkBox" />

    <View
        android:id="@+id/view"
        android:layout_centerInParent="true"
        android:background="@color/colorAccent"
        android:onClick="onClick"
        android:visibility="invisible"
        android:layout_width="300dp"
        android:layout_height="300dp"/>

    <Button
        android:onClick="onClick"
        android:id="@+id/buttonChangeVisibility"
        android:layout_width="wrap_content"
        android:text="switch"
        android:layout_alignParentBottom="true"
        android:layout_alignParentEnd="true"
        style="?android:buttonBarButtonStyle"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true" />
</RelativeLayout>

然后逻辑代码如下,里面每一步的都有解释的,仔细看:

class RevealActivity : AppCompatActivity() {
    private lateinit var mView: View
    private lateinit var mPlayAnimationCheckBox: CheckBox
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_reveal)
        initView()
    }

    private fun initView() {
        mPlayAnimationCheckBox = findViewById(R.id.checkBox)
        mView = findViewById(R.id.view)
    }

    fun onClick(view: View) {
        when (view.id) {
            R.id.buttonChangeVisibility -> {
                //获取checkbox的勾选状态
                val state = mPlayAnimationCheckBox.isChecked
                //返回true的话就使用转场效果,false就使用正常的控制显示与隐藏
                if (state) {
                    if (mView.isShown) revealExite(mView) else revealEnter(mView)
                }else{
                    if (mView.isShown) mView.visibility=View.INVISIBLE else mView.visibility=View.VISIBLE
                }
            }
        }
    }

    private fun revealExite(view: View) {
        val w = mView.width
        val h = mView.height
        //这个圆的半径哈
        val r = hypot(w.toDouble(), h.toDouble()).toInt()
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                val animator = ViewAnimationUtils.createCircularReveal(mView, w, h, r.toFloat(), 0f)
                animator.duration = 5000
                animator.addListener(object : AnimatorListenerAdapter() {
                    override fun onAnimationEnd(animation: Animator) {
                        super.onAnimationEnd(animation)
                        mView.visibility = View.INVISIBLE
                    }
                })
                animator.start()
            } else {
                val revealAnimator = ObjectAnimator.ofFloat (view, "scaleX", w.toFloat(), 0f)
                val  revealAnimator1 = ObjectAnimator. ofFloat (view, "scaleY", h.toFloat(), 0f)
                val  set = AnimatorSet()
                set.duration = 5000//设置播放时间
                set.interpolator = LinearInterpolator()//设置播放模式,这里是平常模式
                set.playTogether(revealAnimator, revealAnimator1)//设置一起播放
                set.start()
            }
    }

    private fun revealEnter(view: View) {
        val width = view.width
        val height = view.height
        val r = hypot(width.toDouble(), height.toDouble()).toFloat()
        //如果要在你的程序中使用它,必须要设置最低的 api 版本是 21,往下版本的,在运行程序的时候就会抛出 .createCircularReveal() not found
        //异常,所以这里需要作出版本的判断
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            val animator=ViewAnimationUtils.createCircularReveal(view, width, height, 0f, r)
            //设置在多少时间内完成动画效果
            animator.duration = 5000
            //这一步十分关键,否则前面都设置都没有用了
            animator.start()
        } else {
            //解决21版本以下没法运行效果
           val revealAnimator = ObjectAnimator.ofFloat (view, "scaleX", 0f, width.toFloat())
            val  revealAnimator1 = ObjectAnimator. ofFloat (view, "scaleY", 0f, height.toFloat())
            val  set = AnimatorSet()
            set.duration = 5000//设置播放时间
            set.interpolator = LinearInterpolator()//设置播放模式,这里是平常模式
            set.playTogether(revealAnimator, revealAnimator1)//设置一起播放
            set.start()
        }
        mView.visibility = View.VISIBLE
    }

}

嗯,就这样可以实现animator的场景转换效果了

第二种,通过transition实现的情景转换:
这个需要三个布局,第一个是activity中,另外两个是需要作用于FrameLayout中的:
activity中的

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_scene"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".SceneActivity">

    <FrameLayout
        android:id="@+id/scene_root"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>

另外两个布局切换的

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_scene"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
   >

    <ImageView
        android:id="@+id/image"
        android:layout_width="160dp"
        android:layout_height="120dp"
        android:src="@drawable/chang_bai" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp">

        <ImageButton
            android:id="@+id/btnClose"
            android:transitionName="@string/icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="true"
            android:layout_marginTop="4dp"
            android:background="?android:selectableItemBackground"
            android:src="@drawable/ic_close_black_24dp" />

        <TextView
            android:id="@+id/tvTitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_toStartOf="@id/btnClose"
            android:text="@string/title"
            android:textAppearance="@style/TextAppearance.AppCompat.Title" />

        <TextView
            android:id="@+id/tvAddress"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/tvTitle"
            android:layout_marginTop="8dp"
            android:text="@string/address"
            android:textAppearance="@style/TextAppearance.AppCompat.Medium" />

        <TextView
            android:id="@+id/tvInfo"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/tvAddress"
            android:layout_marginTop="8dp"
            android:text="@string/info" />

    </RelativeLayout>

</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_scene"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <ImageView
        android:layout_width="match_parent"
        android:id="@+id/image"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:src="@drawable/chang_bai"
        android:transitionName="@string/pic"
        />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp">

        <ImageButton
            android:id="@+id/btnInfo"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="true"
            android:layout_marginTop="4dp"
            android:background="?android:selectableItemBackground"
            android:src="@drawable/ic_info_black_24dp" />

        <TextView
            android:id="@+id/tvTitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_toStartOf="@id/btnInfo"
            android:text="@string/title"
            android:textAppearance="@style/TextAppearance.AppCompat.Headline" />

        <TextView
            android:id="@+id/tvAddress"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/tvTitle"
            android:layout_marginTop="8dp"
            android:text="@string/address"
            android:textAppearance="@style/TextAppearance.AppCompat.Medium" />

    </RelativeLayout>

</LinearLayout>

然后逻辑实现的代码如下:在这里提示下,如果出现某个按钮无法点击的情况下,请查看使用的上下文的是不是baseContext,个人不太建议滥用这个,因为你点击看的时候,就会发现他们俩返回的不是同一个对象,点击this的时候会跳到你的activity中,而点击baseContext会发现追到ContextWrapper类里面,这可能会导致你无法找到对应布局中控件!!!这血一样的教训啊!!

class SceneActivity : AppCompatActivity() {
    private var mOverViewScene: Scene? = null
    private var mInfoScene: Scene? = null
     override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_scene)
        val sceneRoot = findViewById<ViewGroup>(R.id.scene_root)
        mOverViewScene =
            Scene.getSceneForLayout(sceneRoot, R.layout.scene_overview, baseContext)
        mInfoScene = Scene.getSceneForLayout(sceneRoot, R.layout.scene_info, baseContext)
        TransitionManager.go(mOverViewScene)
         onCLickListener()
    }

    private fun onCLickListener() {
        btnInfo.setOnClickListener {
            val transition =
                TransitionInflater.from(baseContext)
                    .inflateTransition(R.transition.transition)
            TransitionManager.go(mInfoScene, transition)
        }
        btnClose?.setOnClickListener {
            TransitionManager.go(mOverViewScene)
        }
    }

}

嗯,这就实现了的说!!!
第三种,就是实现activity之间的情景转换
xml如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".FirstActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ImageView
            android:id="@+id/iv1"
            android:layout_width="0dp"
            android:layout_height="160dp"
            android:layout_weight="1"
            android:background="?attr/selectableItemBackground"
            android:onClick="onClick"
            android:src="@drawable/pic1" />

        <ImageView
            android:id="@+id/iv2"
            android:layout_width="0dp"
            android:layout_height="160dp"
            android:layout_weight="1"
            android:background="?attr/selectableItemBackground"
            android:onClick="onClick"
            android:src="@drawable/pic2" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:orientation="horizontal"
        android:layout_height="wrap_content">

        <ImageView
            android:id="@+id/iv3"
            android:layout_width="0dp"
            android:layout_height="160dp"
            android:layout_weight="1"
            android:background="?attr/selectableItemBackground"
            android:onClick="onClick"
            android:src="@drawable/pic3" />

        <ImageView
            android:id="@+id/iv4"
            android:layout_width="0dp"
            android:layout_height="160dp"
            android:layout_weight="1"
            android:background="?attr/selectableItemBackground"
            android:onClick="onClick"
            android:src="@drawable/pic4" />

    </LinearLayout>

</LinearLayout>

第二个activity如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".SecondActivity">
    <ImageView
        android:id="@+id/iv"
        android:transitionName="img"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

实现逻辑如下:

class FirstActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_first)

    }

    fun onClick(view: View) {
        var resId = when (view.id) {
            R.id.iv1 -> R.drawable.pic1
            R.id.iv2 -> R.drawable.pic2
            R.id.iv3 -> R.drawable.pic3
            R.id.iv4 -> R.drawable.pic4
            else -> null
        }
        val intent = Intent(this, SecondActivity::class.java)
        intent.putExtra("resId", resId)
        //设置情景转换效果
        val transition: Transition = Explode()
        //剔除状态栏跟随转换效果
        transition.excludeTarget(android.R.id.statusBarBackground, true)
        //设置进场的转换效果
        window.enterTransition = transition
        //设置离场的转换效果
        window.exitTransition = transition
        //设置再次进入此页面时的转场动画
        window.reenterTransition = transition
        //设置转场元素为共享元素
        window.sharedElementEnterTransition = transition
        //设置共享元素,需要在另一个activity中的 iv.transitionName = "img"设定transitionName为img,这样另一个activity也会实现转场效果
        val shareElement =
            Pair.create(view, "img")
        val options =
            ActivityOptions.makeSceneTransitionAnimation(this, shareElement)
        startActivity(intent, options.toBundle())
    }
}
class SecondActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)
        val resId = intent.extras!!.getInt("resId")
        val iv =
            findViewById<View>(R.id.iv) as ImageView
        iv.transitionName = "img"
        iv.setImageResource(resId)
        val transition: Transition = Explode()
        transition.excludeTarget(android.R.id.statusBarBackground, true)
        window.enterTransition = transition
        window.exitTransition = transition
    }
}

这里面的注释都写得很清楚,他们的实现功能是啥,所以请各位看官慢看,不过反正你们看了也不会点赞什么的,那算了,哼

上一篇 下一篇

猜你喜欢

热点阅读