MotionLayout 弹弓:预备,拉开,缩小,1234,伸展运动。来来来,把它上面的招牌也动起来,显示,隐藏,1234...

⏱ 0. 深入意向

上次试了试 G 哥的动画神器 🏄MotionLayout,感觉还不错,就想拿手头的项目改改。有个学校项目,公共资源,没问题,拿来试试手啦!

✏️计划是这样的:

bar
将肚子缩小成条状。循环跳动。想起来简单,做起来可就繁琐了。


👣1. 直线运动

其实,不要看它变来变去,这个是直线运动:涨大是高度变大,缩小是高度缩小。
linear
🔣四块砖的是我原版,缩小的是准备要做的东西。我拿🔣四块砖抄到新的项目内练习 🏄MotionLayout。


🙌 2. 准备材料

如果你想抄过去就能用的话,就大错特错了。你数数那🔣四块砖需要多少份材料?
不卖关子了,答案如下:
count
一块砖内有四份,总共 16 份。
🐸:什么,连 ➰ConstraintLayout 都包了。
😝:是啊,不包的话,跑起来会死得很难看,下面会有解说。


🟢 3. 排队进场

先不说什么是排队进场,让我们直接转换成 🏄MotionLayout 看看。

<androidx.constraintlayout.widget.ConstraintLayout
    ...>
	<!--    1-->
	<androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/row_test_takers"
        ...">
		
		<ImageView
			android:id="@+id/img_test_takers"
			.../>

		<TextView
			android:id="@+id/label_test_takers"
			.../>

		<TextView
			android:id="@+id/test_takers_record"
			...>
			
    </androidx.constraintlayout.widget.ConstraintLayout>
	
	<!--    2-->
	...
	
	<!--    3-->
	...
	
	<!--    4-->
	...

</androidx.constraintlayout.widget.ConstraintLayout>

这就是你显示状态,对不对?转换后就成了这样:
four
里面有四大天王。再接着,你很勤劳的把它们加进 start 区,接着打开 res / xml / 某某_scene.xml ,把 start 区的东西抄进 end 区。接着改呀改成了我上面那个横幅版本,心想着大功告成了,跑起来一看:

wrong
😨:老曹降临,怎么和设计的不一样,缩是缩了,有些东西不听话也。就是不知道老板收不收货,想想:跑到老板面前,把手机拿远一点,把动画点给他/她,说做好了,可能会过关吧?
😸:那 他/她 不批死你啊 !? 哈哈哈…
🤐:所以,我花了几个小时,看错在哪里。终于,解决方案如下:

排队进场

转换前,把所有要变的东西都排成一线。

<androidx.constraintlayout.widget.ConstraintLayout
    ...>
	<!--    1-->
	<androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/row_test_takers"
        ...">
    </androidx.constraintlayout.widget.ConstraintLayout>
	
	<ImageView
		android:id="@+id/img_test_takers"
		.../>

	<TextView
		android:id="@+id/label_test_takers"
		.../>

	<TextView
		android:id="@+id/test_takers_record"
		...>
	
	<!--    2-->
	...
	
	<!--    3-->
	...
	
	<!--    4-->
	...

</androidx.constraintlayout.widget.ConstraintLayout>

转换后就成了这样了:
many
超多,点鼠标都点得你手指疼。
因为拆开来了,所有的东西都要重新连一遍,麻烦。
期间,那个 原本的 Layout.xml 和 Layout_scene.xml 内物体的位置会打架,所以在 Layout.xml 所有有关位置的点通通都要删除。
delete
噼里啪啦,键盘和鼠标混合双打,删删删!


🌄 4. 设计流程复习

已经会的,可以跳过。咱们复习一遍。
1️⃣、XML 排队
2️⃣、转换🏄MotionLayout
3️⃣、打开 <>Code 版,删除所有与 位置 有关的东西。
layout
4️⃣、回 GUI 版,加所有物件进 start 区。

start
连接物件成 🔣四块砖 的大版。
5️⃣、打开 某某Layout_scene.xml 文件,从 start 区抄进 end 区。
在这里插入图片描述
6️⃣、将所有物件改造成横幅版。


🎎 5. 创建连接

差不多完了,咱们来加连接 Transition 和 点击 click 。

tran1
满意的话,加 click 功能:
plus
打开 某某Layout_scene.xml : 咱们制作回路

抄
把 id 换位,回路就做成了。回 Layout.xml ,玩玩新的连接,就可以用了。


📥 6. 插回 🏄MotionLayout

我那是在另外一个项目干的,把 某某layout.xml 和 xml/某某Layout_scene.xml 的文件抄回正版项目。怎么插回去呢?

当然是 < include > layout

example
这是我的例子,还加了提醒 TextView,“@+id/label_sat_title” 。


🏇 7. 用 🏄MotionLayout 控制其它物件

你可以通过 MotionLayout.TransitionListener 控制周围的物件。
这是 LiveTemplate 捷径:

$layout$.setTransitionListener(
    object: MotionLayout.TransitionListener {
        override fun onTransitionStarted(p0: MotionLayout?, 
                p1: Int, p2: Int) {
            // work on here
        }
 
        override fun onTransitionChange(
                motionLayout: MotionLayout?,
                startId: Int, endId: Int, progress: Float) { }
 
        override fun onTransitionCompleted(
                motionLayout: MotionLayout?,
                currentId: Int) { }
 
        override fun onTransitionTrigger(
                motionLayout: MotionLayout?,
                p1: Int, p2: Boolean, p3: Float) { }
    }
)

比如上面的提醒,“@+id/label_sat_title” 。我要让它跟动画同步显示、隐藏。
首先,我增加一个公共参数:

@AndroidEntryPoint
class SchoolScoresFragment : Fragment() {

    ...
    // sat scorebar switch
    private var scorebarSwitch = false

用捷径加监听:

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // view binding
        _binding = FragmentSchoolScoresBinding.inflate(inflater, container, false)
        val root = binding.root

        ...

        // observer
        scoresVM.scores.observe(viewLifecycleOwner, {
            if (it != null) {
                ...

                binding.scoresDetail.mlTestTaker.setTransitionListener(
                    object: MotionLayout.TransitionListener {
                        @RequiresApi(Build.VERSION_CODES.R)
                        override fun onTransitionStarted(p0: MotionLayout?,
                                                         p1: Int, p2: Int) {
                            val scoreTitle = binding.labelSatTitle
                            if (scorebarSwitch)
                                scoreTitle.visibility = View.VISIBLE
                            else
                                scoreTitle.visibility = View.GONE
                        }

                        override fun onTransitionChange(motionLayout: MotionLayout?,
                                startId: Int, endId: Int, progress: Float) { }

                        override fun onTransitionCompleted(motionLayout: MotionLayout?,
                                currentId: Int) {
                            scorebarSwitch =
                                currentId == binding.scoresDetail.mlTestTaker.startState
                        }

                        override fun onTransitionTrigger(motionLayout: MotionLayout?,
                                p1: Int, p2: Boolean, p3: Float) { }
                    }
                )
            }
        })

简单啊!
🏃跑来看看:
animated
成功!


📙 8. 英文版

Action!Go 🏄MotionLayout: Settle Here! Settle There…Done!
帮帮忙,在那里鼓个掌!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值