使用Android拖放框架实现View的拖动

Posted 涂程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Android拖放框架实现View的拖动相关的知识,希望对你有一定的参考价值。

最近项目中需要实现一个类似于悬浮球的功能,可以自由拖动。 以前通过View的onTouchListener来实现过View的拖动功能,但是通过这种方式的话,需要额外处理Viwe的点击事件(单击事件)。

android拖放框架

拖放框架主要是用于把一个View拖放到另一个View,当启用多窗口模式后,也可以把View从一个应用拖放到另一个应用。可以设置要传递的数据,且在拖动过程中会绘制拖动路径(可以自定义绘制内容)。

startDrag()和startDragAndDrop()

可以通过调用View.startDrag或View.startDragAndDrop() (Android N以上)来告知系统开始拖动操作。这两个方法都需要传入4个参数,分别是:

DragShadowBuilder

可以通过View.DragShadowBuilder(View)来使用默认的拖动阴影(与传入的View样式相同),也可以继承View.DragShadowBuilder来实现不同的阴影。

OnDragListener

可以通过设置OnDragListener来实时监听拖动事件,在OnDragListener中可以获取到DragEvent,通过DragEvent中的Action可以知道当前拖动事件的操作类型。这些Action包含:

实现View的拖放

相比于通过onTouchListener方法来说,拖放框架自带了路径绘制,不用通过在拖动过程中持续获取坐标设置到View来显示路径,而且无需额外再处理View的单击事件,方便了许多。

以下是我做的简单实现:

        val dragView = findViewById<View>(R.id.drag_view)
        dragView?.run 
            val clipDataItem = ClipData.Item("111")
            val clipData = ClipData("111", arrayOf(ClipDescription.MIMETYPE_TEXT_PLAIN), clipDataItem)
            setOnLongClickListener 
                val dragShadowBuilder = View.DragShadowBuilder(it)
                //clipData是测试传递数据,无需传递数据可以直接传null
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) 
                    it.startDragAndDrop(clipData, dragShadowBuilder, null, 0)
                 else 
                    it.startDrag(clipData, dragShadowBuilder, null, 0)
                
                true
            
        

        //在根布局设置监听
        val rootView: FrameLayout = findViewById(android.R.id.content)
        rootView.setOnDragListener  v, event ->
            when (event.action) 
                DragEvent.ACTION_DRAG_STARTED -> 
                    //当调用View.startDrag()或startDragAndDrop()时会收到这个Action
                    
                    //先把View隐藏
                    if (dragView?.visibility == View.VISIBLE) 
                        dragView?.visibility = View.INVISIBLE
                    
                
                DragEvent.ACTION_DRAG_ENTERED -> 
                    //当被拖拽的View进入监听View的边界时会收到这个Action
                
                DragEvent.ACTION_DRAG_LOCATION -> 
                    //当被拖拽的View在监听View边界内移动时会收到这个Action
                
                DragEvent.ACTION_DRAG_EXITED -> 
                    //当被拖拽的View离开监听View的边界时会收到这个Action
                
                DragEvent.ACTION_DROP -> 
                    //释放
                    
                    //将View移动到释放时的位置,并显示(这里还应该处理贴边逻辑,暂未实现)
                    //设置View的中心在当前坐标
                    val width = (crossPromotionAdView?.width ?: 0) / 2
                    val height = (crossPromotionAdView?.height ?: 0) / 2
                    dragView?.x = event.x - width
                    dragView?.y = event.y - height
                    //显示View
                    dragView?.visibility = View.VISIBLE

                    //获取调用startDrag()或startDragAndDrop()时传入的数据
                    val clipDataItem = event.clipData.getItemAt(0).text
                
                DragEvent.ACTION_DRAG_ENDED -> 
                    //拖动结束
                
            
            
            //这边我所有事件默认都返回true,可以按需调整
            true
        

以上是关于使用Android拖放框架实现View的拖动的主要内容,如果未能解决你的问题,请参考以下文章

android 如何实现边缘拖动侧滑?

Android 拖放视图

拖放 Drag and drop

Android为View添加拖放效果

在sencha extjs疯狂拖放

android 可拖拽View的简单实现