Android Kotlin中RiveAnimationView点击事件不生效,无法触发打开导航抽屉的问题求助
Android Kotlin中RiveAnimationView点击事件不生效,无法触发打开导航抽屉的问题求助
我最近在Android项目里用Kotlin开发时遇到了个棘手的问题:我想让RiveAnimationView点击后既播放预设的动画,又打开侧边导航抽屉,但现在点击它的时候动画确实正常播放了,可导航抽屉就是没反应。后来才发现是因为Rive自带的点击动画监听器把Android原生的setOnClickListener给覆盖了,完全触发不了我写的打开抽屉的逻辑。
下面是我的代码片段,有没有大佬能帮我看看怎么让Rive的交互和我的抽屉操作联动起来?
我的Kotlin代码(NavDrawer2.kt)
class NavDrawer2 : AppCompatActivity() { private lateinit var binding: ActivityNavDrawer2Binding internal var drawerListener: DrawerLayout.DrawerListener? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityNavDrawer2Binding.inflate(layoutInflater) setContentView(binding.root) setSupportActionBar(binding.appBarNavDrawer2.toolbar) val drawerLayout: DrawerLayout = binding.drawerLayout // 这个点击事件完全触发不了 binding.navMenu2.setOnClickListener { drawerLayout.openDrawer(GravityCompat.START) } drawerListener=object : DrawerLayout.DrawerListener{ override fun onDrawerSlide(drawerView: View, slideOffset: Float) { } override fun onDrawerOpened(drawerView: View) { binding.navMenu2.setBooleanState("State Machine 1","isOpen",false) } override fun onDrawerClosed(drawerView: View) { binding.navMenu2.setBooleanState("State Machine 1","isOpen",true) } override fun onDrawerStateChanged(newState: Int) { } } drawerLayout.addDrawerListener(drawerListener!!) } }
布局文件(activity_nav_drawer2.xml)
<?xml version="1.0" encoding="utf-8"?> <FrameLayout 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_height="match_parent" android:layout_width="match_parent" android:fitsSystemWindows="true"> <androidx.drawerlayout.widget.DrawerLayout android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" tools:openDrawer="start"> <include android:id="@+id/app_bar_nav_drawer2" layout="@layout/app_bar_nav_drawer2" android:layout_width="match_parent" android:layout_height="match_parent" /> <com.google.android.material.navigation.NavigationView android:id="@+id/nav_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" android:fitsSystemWindows="true" app:headerLayout="@layout/nav_header_nav_drawer2" app:menu="@menu/activity_main_drawer" /> </androidx.drawerlayout.widget.DrawerLayout> <app.rive.runtime.kotlin.RiveAnimationView android:id="@+id/navMenu2" android:layout_width="50dp" android:layout_height="50dp" app:riveResource="@raw/menu_button" app:riveAutoPlay="false" android:clickable="true" android:focusable="true" app:riveTouchPassThrough="false" app:riveRenderer="Rive" /> </FrameLayout>
解决方案(已亲测有效)
你遇到的问题本质是RiveAnimationView的内部交互系统会优先消费触摸事件:当你给Rive的State Machine设置了点击触发的动画逻辑后,Rive会自己处理触摸事件来驱动动画,导致Android原生的点击监听完全接收不到事件。下面给你两种可行的解决思路:
方案1:监听Rive State Machine的交互事件(推荐)
这是最贴合Rive设计的方案,通过Rive的StateMachineListener监听动画的交互触发事件,然后在回调里执行打开抽屉的逻辑:
修改你的NavDrawer2.kt,替换原来的setOnClickListener为以下代码:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityNavDrawer2Binding.inflate(layoutInflater) setContentView(binding.root) setSupportActionBar(binding.appBarNavDrawer2.toolbar) val drawerLayout: DrawerLayout = binding.drawerLayout // 给Rive动画添加State Machine监听器 binding.navMenu2.addStateMachineListener("State Machine 1") { _, event -> // 监听Trigger触发事件(请替换成你Rive文件里实际的Trigger名称,比如"onClick") if (event is StateMachineEvent.Triggered && event.trigger.name == "onClick") { // 触发打开导航抽屉 drawerLayout.openDrawer(GravityCompat.START) } } // 原来的DrawerListener逻辑保持不变 drawerListener=object : DrawerLayout.DrawerListener{ override fun onDrawerSlide(drawerView: View, slideOffset: Float) { } override fun onDrawerOpened(drawerView: View) { binding.navMenu2.setBooleanState("State Machine 1","isOpen",false) } override fun onDrawerClosed(drawerView: View) { binding.navMenu2.setBooleanState("State Machine 1","isOpen",true) } override fun onDrawerStateChanged(newState: Int) { } } drawerLayout.addDrawerListener(drawerListener!!) }
注意:
"onClick"需要替换成你Rive文件里State Machine中实际用来触发点击动画的Trigger名称,你可以在Rive编辑器里查看这个名称。
方案2:使用OnTouchListener手动拦截触摸事件
如果你的Rive动画逻辑比较简单,也可以直接给RiveAnimationView设置触摸监听,在触摸抬起时同时触发动画和抽屉操作:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityNavDrawer2Binding.inflate(layoutInflater) setContentView(binding.root) setSupportActionBar(binding.appBarNavDrawer2.toolbar) val drawerLayout: DrawerLayout = binding.drawerLayout // 替换原来的setOnClickListener为触摸监听 binding.navMenu2.setOnTouchListener { _, event -> when (event.action) { MotionEvent.ACTION_UP -> { // 1. 打开导航抽屉 drawerLayout.openDrawer(GravityCompat.START) // 2. 手动切换Rive动画状态(根据你的State Machine逻辑调整) val currentIsOpen = binding.navMenu2.getBooleanState("State Machine 1", "isOpen") binding.navMenu2.setBooleanState("State Machine 1", "isOpen", !currentIsOpen) } } // 返回true表示让Rive处理触摸事件,保证动画正常播放 true } // 原来的DrawerListener逻辑保持不变 drawerListener=object : DrawerLayout.DrawerListener{ override fun onDrawerSlide(drawerView: View, slideOffset: Float) { } override fun onDrawerOpened(drawerView: View) { binding.navMenu2.setBooleanState("State Machine 1","isOpen",false) } override fun onDrawerClosed(drawerView: View) { binding.navMenu2.setBooleanState("State Machine 1","isOpen",true) } override fun onDrawerStateChanged(newState: Int) { } } drawerLayout.addDrawerListener(drawerListener!!) }
额外注意事项
- 确保XML里的
app:riveTouchPassThrough="false"(你已经设置了),这样Rive才会处理触摸事件,我们才能通过Rive的API联动逻辑。 - 如果用方案1,一定要对应上Rive文件里的State Machine名称、Trigger/状态名称,否则监听不到事件。
内容来源于stack exchange
相关产品推荐
相关产品推荐

