You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 10:59:35