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

Android自定义View点击事件失效及动画不运行问题求助

问题描述

我有一个用于控制设备连接状态的Service类,当设备接入电源时,会通过WindowManager显示一个自定义View。但目前遇到两个问题:

  • 自定义View的点击事件完全失效
  • 设置的Lottie动画无法正常运行

Service类代码

class Service : Service() {

    private var customLockScreenView: CustomLockScreenView? = null
    private var windowManager: WindowManager? = null

    private val powerConnectionReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            when (intent.action) {
                Intent.ACTION_POWER_CONNECTED -> powerWasConnected()
                Intent.ACTION_POWER_DISCONNECTED -> powerWasDisconnected()
            }
        }
    }

    @SuppressLint("MissingInflatedId", "InflateParams")
    override fun onCreate() {
        super.onCreate()
        
        val filter = IntentFilter().apply {
            addAction(Intent.ACTION_POWER_CONNECTED)
            addAction(Intent.ACTION_POWER_DISCONNECTED)
        }
        registerReceiver(powerConnectionReceiver, filter)
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(powerConnectionReceiver)
        powerWasDisconnected()
    }

    override fun onBind(intent: Intent): IBinder? {
        return null
    }

    private fun powerWasConnected() {
        windowManager = getSystemService(WINDOW_SERVICE) as WindowManager?

        if (customLockScreenView == null) {
            customLockScreenView = CustomLockScreenView(this)

            customLockScreenView!!.setClick(object : OnSingleClickListener {
                override fun onSingleClick() {
                    Log.d("Clicks Service", "Custom view clicked!")
                }
            })
            customLockScreenView!!.findViewById<LottieAnimationView>(R.id.animationView).setAnimation(R.raw.anim20)

            Log.d("TAG", "powerWasConnected: Power is connected")
            val layoutParams = WindowManager.LayoutParams(
                WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.MATCH_PARENT,
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
                    WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
                else
                    WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                        or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                android.graphics.PixelFormat.TRANSLUCENT,
            )
            layoutParams.gravity = Gravity.CENTER
            windowManager?.addView(customLockScreenView, layoutParams)
            
            Handler().postDelayed({
                customLockScreenView?.let {
                    windowManager?.removeView(it)
                    customLockScreenView = null 
                }
            }, 5000)
        }
    }

    private fun powerWasDisconnected() {
        Log.d("TAG", "powerWasDisconnected: Power is disconnected")
        clearFilter()
    }

    private fun clearFilter() {
        customLockScreenView?.let {
            windowManager?.removeView(it)
            customLockScreenView = null 
        }
    }
}

自定义View类代码

class CustomLockScreenView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr) {

    var clickListener: OnSingleClickListener? = null

    fun setClick(listener: OnSingleClickListener) {
        clickListener = listener
    }
    
    init {
        LayoutInflater.from(context).inflate(R.layout.custom_lock_screen, this, true)
        
        findViewById<LottieAnimationView>(R.id.animationView).setAnimation(R.raw.anim20)

        findViewById<RelativeLayout>(R.id.main)?.setOnClickListener {
            clickListener?.onSingleClick()
        }
    }
}

自定义View布局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"
    android:id="@+id/view2"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/color_toolbar"
    android:clickable="true">

    <com.airbnb.lottie.LottieAnimationView
        android:id="@+id/animationView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:padding="@dimen/_55sdp"
        app:lottie_rawRes="@raw/anim20"
        app:lottie_autoPlay="true"
        app:lottie_loop="true"
        app:lottie_speed="1" />

    <LinearLayout
        android:id="@+id/layoutBattery"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="@dimen/_35sdp"
        android:clickable="false"
        android:focusable="false"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tvPercentage"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_margin="@dimen/_10sdp"
            android:fontFamily="@font/regular"
            android:text="10%"
            android:textColor="@color/white"
            android:textSize="@dimen/_30ssp" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:src="@drawable/ic_battery" />
    </LinearLayout>

    <ImageView
        android:id="@+id/iv_close"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/_25sdp"
        android:src="@drawable/ic_click"
        android:visibility="invisible" />

</RelativeLayout>

点击监听抽象类

abstract class SingleClickListener : View.OnClickListener {
    private var mLastClickTime: Long = 0

    abstract fun onSingleClick(view: View?)

    override fun onClick(view: View) {
        val currentTime = SystemClock.uptimeMillis()
        if (currentTime - mLastClickTime > MIN_CLICK_INTERVAL) {
            mLastClickTime = currentTime
            onSingleClick(view)
        }
    }

    companion object {
        private const val MIN_CLICK_INTERVAL: Long = 1000
    }
}

点击监听接口

interface OnSingleClickListener {
    fun onSingleClick()
}

问题修复方案

1. 修复点击事件失效问题

核心原因:

  • WindowManager布局参数添加了FLAG_NOT_FOCUSABLE标记,直接导致View无法获取焦点,无法接收点击事件。
  • 自定义View中绑定点击监听的目标ID错误:布局根View的ID是view2,但代码中尝试绑定不存在的R.id.main,监听未生效。

修复步骤:

(1)调整WindowManager参数flags

移除FLAG_NOT_FOCUSABLE,保留FLAG_NOT_TOUCH_MODAL允许下层View接收非当前View区域的点击:

val layoutParams = WindowManager.LayoutParams(
    WindowManager.LayoutParams.MATCH_PARENT,
    WindowManager.LayoutParams.MATCH_PARENT,
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
        WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
    else
        WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
    android.graphics.PixelFormat.TRANSLUCENT,
)

(2)修正点击监听绑定目标

将绑定的ID改为布局中实际存在的view2:

init {
    LayoutInflater.from(context).inflate(R.layout.custom_lock_screen, this, true)
    
    findViewById<LottieAnimationView>(R.id.animationView).setAnimation(R.raw.anim20)

    findViewById<RelativeLayout>(R.id.view2).setOnClickListener {
        clickListener?.onSingleClick()
    }
}

2. 修复Lottie动画不运行问题

核心原因:

  • 重复设置动画:布局XML、自定义View初始化、Service中三次设置同一动画,导致初始化逻辑冲突。
  • 未显式触发动画播放,即使XML设置了lottie_autoPlay="true",WindowManager添加View后可能需要手动启动。

修复步骤:

(1)移除重复的动画设置

删除Service中多余的动画设置代码:

// 删掉此行
// customLockScreenView!!.findViewById<LottieAnimationView>(R.id.animationView).setAnimation(R.raw.anim20)

(2)显式启动动画

在自定义View初始化时添加playAnimation()调用:

init {
    LayoutInflater.from(context).inflate(R.layout.custom_lock_screen, this, true)
    
    val lottieView = findViewById<LottieAnimationView>(R.id.animationView)
    lottieView.setAnimation(R.raw.anim20)
    lottieView.playAnimation()

    findViewById<RelativeLayout>(R.id.view2).setOnClickListener {
        clickListener?.onSingleClick()
    }
}

内容的提问来源于stack exchange,提问作者Shivam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 18:18:11