亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android事件沖突解決懸浮窗拖拽處理方案

 更新時(shí)間:2023年03月01日 16:31:38   作者:小迪vs同學(xué)  
這篇文章主要為大家介紹了Android事件沖突解決懸浮窗拖拽處理方案,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

需求場(chǎng)景

最近項(xiàng)目中要做一個(gè)音樂播放懸浮按鈕的功能,最終實(shí)現(xiàn)效果如下:

問題暴露

懸浮窗布局文件就不放了,就是水平LinearLayout里面放幾個(gè)ImageView。

做的過程當(dāng)中遇到一個(gè)問題,就是懸浮窗是可以任意拖拽的,懸浮窗里面的按鈕是可以點(diǎn)擊的,比如暫停,下一曲,關(guān)閉懸浮窗等。

按常規(guī)思路,先給整個(gè)懸浮窗setOnTouchListener(),然后再給你里面的按鈕setOnClickListener(),點(diǎn)擊運(yùn)行,結(jié)果發(fā)現(xiàn),點(diǎn)擊事件是可以響應(yīng),拖拽也沒問題,但是當(dāng)手指放在ImageView上拖拽時(shí),onTouchListener事件無法響應(yīng)。

此時(shí)第一感覺就是setOnTouchListener()setOnClickListener()沖突了,需要解決一下沖突。無奈自己對(duì)Android事件分發(fā)消費(fèi)機(jī)制一直都是一知半解的,一般都是出了問題需要解決,第一時(shí)間先百度,沒有解決方案就只能去研究Android事件分發(fā)消費(fèi)機(jī)制了,但是研究完也都是懵懵懂懂的,今天就決定把這個(gè)難點(diǎn)徹底消化掉。

主要研究了這篇文章Android事件分發(fā)消費(fèi)機(jī)制,然后對(duì)照著寫了個(gè)demo,一一去驗(yàn)證,加深了自己的理解,最后終于解決了我的問題。

解決思路

先說下解決思路,自定義LinearLayout,當(dāng)手指處于滑動(dòng)時(shí),直接攔截事件,交給自己的onTouchEvent處理即可,核心代碼如下:

/**
 * @author:Jason
 * @date:2021/8/24 19:49
 * @description:可拖拽的LinearLayout,解決子View設(shè)置OnClickListener之后無法拖拽的問題
 */
class DraggerbleLinearLayout : LinearLayout {
    constructor(context: Context, attr: AttributeSet) : this(context, attr, 0)
    constructor(context: Context, attr: AttributeSet, defStyleAttr: Int) : this(context, attr, defStyleAttr, 0)
    constructor(context: Context, attr: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attr, defStyleAttr, defStyleRes)
    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
        when (ev?.action) {
            MotionEvent.ACTION_MOVE -> {
                return true
            }
        }
        return super.onInterceptTouchEvent(ev)
    }
}

很簡單,就是在onInterceptTouchEvent()里面攔截move事件即可,這里你也可以重寫onTouchEvent(),在里面實(shí)現(xiàn)拖拽功能,但是這樣就固定死了,所以我選擇在外面setOnTouchListener(),需要拖拽功能時(shí)才去實(shí)現(xiàn)

    /**
     * 創(chuàng)建懸浮窗
     */
    @SuppressLint("ClickableViewAccessibility")
    private fun showWindow() {
        //獲取WindowManager
        windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
        val outMetrics = DisplayMetrics()
        windowManager.defaultDisplay.getMetrics(outMetrics)
        var layoutParam = WindowManager.LayoutParams().apply {
            /**
             * 設(shè)置type 這里進(jìn)行了兼容
             */
            type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
            } else {
                WindowManager.LayoutParams.TYPE_PHONE
            }
            format = PixelFormat.RGBA_8888
            flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
            //位置大小設(shè)置
            width = WRAP_CONTENT
            height = WRAP_CONTENT
            gravity = Gravity.LEFT or Gravity.TOP
            //設(shè)置劇中屏幕顯示
            x = outMetrics.widthPixels / 2 - width / 2
            y = outMetrics.heightPixels / 2 - height / 2
        }
        //在這里設(shè)置觸摸監(jiān)聽,以實(shí)現(xiàn)拖拽功能
        floatRootView?.setOnTouchListener(ItemViewTouchListener(layoutParam, windowManager))
        // 將懸浮窗控件添加到WindowManager
        windowManager.addView(floatRootView, layoutParam)
        isAdded = true
    }

主要是這行代碼

//在這里設(shè)置觸摸監(jiān)聽,以實(shí)現(xiàn)拖拽功能
floatRootView?.setOnTouchListener(ItemViewTouchListener(layoutParam, windowManager))

ItemViewTouchListener.kt文件內(nèi)容

/**
 * @author:Jason
 * @date: 2021/8/23 19:27
 * @description:
 */
class ItemViewTouchListener(val layoutParams: WindowManager.LayoutParams, val windowManager: WindowManager) : View.OnTouchListener {
    private var lastX = 0.0f
    private var lastY = 0.0f
    override fun onTouch(view: View, event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                //這里接收不到Down事件,不要在這里寫邏輯
            }
            MotionEvent.ACTION_MOVE -> {
                //重寫LinearLayout的OnInterceptTouchEvent之后,這里的Down事件會(huì)接收不到,所以初始位置需要在Move事件里賦值
                if (lastX == 0.0f || lastY == 0.0f) {
                    lastX = event.rawX
                    lastY = event.rawY
                }
                val nowX: Float = event.rawX
                val nowY: Float = event.rawY
                val movedX: Float = nowX - lastX
                val movedY: Float = nowY - lastY
                layoutParams.apply {
                    x += movedX.toInt()
                    y += movedY.toInt()
                }
                //更新懸浮球控件位置
                windowManager?.updateViewLayout(view, layoutParams)
                lastX = nowX
                lastY = nowY
            }
            MotionEvent.ACTION_UP -> {
                lastX = 0.0f
                lastY = 0.0f
            }
        }
        return true
    }
}

這里有一點(diǎn)需要注意的是,重寫了LinearLayoutonInterceptTouchEvent()后會(huì)導(dǎo)致setOnTouchListener()里面的ACTION_DOWN事件接收不到,所以不要在down事件里面寫邏輯。然后onTouch一定要返回true,表示要消費(fèi)事件,否則當(dāng)拖拽非ImageView區(qū)域時(shí)會(huì)拖不動(dòng)。

好了,花了一整天,就解決了這個(gè)小問題。

以上就是Android事件沖突解決懸浮窗拖拽處理方案的詳細(xì)內(nèi)容,更多關(guān)于Android事件沖突懸浮窗拖拽的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論