学更好的别人,

做更好的自己。

——《微卡智享》

本文长度为3489,预计阅读9分钟

前言

原来产品中有个功能要实现宫格中库位的移库效果,以前一直没做这块,也是为了先赶产品,所以没有做实现的拖拽效果,最近正好有时间,研究了一下DragAndDrop,做了一个Demo验证了一下,效果还是挺不错的,本篇就做一个分享。

今天这篇是传统的DragAndDrop效果实现,在JetPack库中新的dragandrop做的优化,要简单的很多,下一篇会说到,并做一下两个对比。

实现效果

DragAndDrop框架

微卡智享

在Android Level11后就增加了DragAndDrop拖拽框架,可以在界面中实现两个View的数据转换,具体的实现需要增加一个拖拽的事件,一个拖拽的监听器。

拖拽函数startDragAndDrop

拖拽功能通过View.startDragAndDrop来实现

public final boolean startDragAndDrop(ClipData data, View.DragShadowBuilder shadowBuilder, Object myLocalState, int flags) {throw new RuntimeException("Stub!");}

参数:

ClipData:用于存储传送的数据

DragShadowBuilder:拖动时展示的阴影

myLocalState:这个参数可以用作Activity内部一种轻量级的数据传输机制。监听方通过DragEvent#getLocalState()方法来获取数据。它不能跨Activity,如果在其他Activity调用getLocalState()方法会返回null

flags:设置为0表示不设置flag。

DRAG_FLAG_GLOBAL  表示可以跨window拖拽,典型的是分屏状态下的拖拽
DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION  通常跟DRAG_FLAG_GLOBAL_URI_READ和DRAG_FLAG_GLOBAL_URI_WRITE配合使用,用来在设备重启时保持权限。直到显示地调用Context.revokeUriPermission(这里我也没懂什么意思)
DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION  通常跟DRAG_FLAG_GLOBAL_URI_READ和DRAG_FLAG_GLOBAL_URI_WRITE配合使用,the URI permission grant applies to any URI that is a prefix match against the original granted URI。
DRAG_FLAG_GLOBAL_URI_READ  与DRAG_FLAG_GLOBAL一起使用,接收者将能够请求对包含在ClipData对象中的内容URI的读访问。
DRAG_FLAG_GLOBAL_URI_WRITE  与DRAG_FLAG_GLOBAL一起使用,接收者将能够请求对包含在ClipData对象中的内容URI的写访问。
DRAG_FLAG_OPAQUE 使拖动的阴影不透明。

监听事件OnDragListener

OnDragListener主要用于监听拖拽事件,当前可见的View都可以进行监听。

监听Drag的流程:

上面的流程通过Drag events事件来捕获,其中每个状态中还包含其他依赖于事件动作类型的数据,具体如下:

上面是简单的DragandDrop的介绍 ,接下来代码实现。

代码实现

微卡智享

01

build.gradle添加依赖项

implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4'implementation "androidx.draganddrop:draganddrop:1.0.0-alpha03"

文章开头用的宫格列表,所以用的BaseRecyclerviewadapter了,然后draganddrop直接用的是jetpack库中alpha03的最新版,要注意这个要求minsdk最小是24。

02

布局文件及定义类

一个main中加入了一个按钮和recyclerview,另一个是每个宫格的布局。

定义CDrugs类

package pers.vaccae.draganddropdemo.beanimport android.os.Parcel
import android.os.Parcelable/*** 作者:Vaccae* 邮箱:3657447@qq.com* 创建时间:14:26* 功能模块说明:*/
class CDrugs() : Parcelable {//货格号var drugs_ckcode = 0//药品编码var drugs_code = ""//药品名称var drugs_name = ""//药品规格var drugs_specs = ""//药品数量var qty = 0;constructor(parcel: Parcel) : this() {drugs_ckcode = parcel.readInt()drugs_code = parcel.readString()!!drugs_name = parcel.readString()!!drugs_specs = parcel.readString()!!qty = parcel.readInt()}override fun writeToParcel(parcel: Parcel, flags: Int) {parcel.writeInt(drugs_ckcode)parcel.writeString(drugs_code)parcel.writeString(drugs_name)parcel.writeString(drugs_specs)parcel.writeInt(qty)}override fun describeContents(): Int {return 0}companion object CREATOR : Parcelable.Creator<CDrugs> {override fun createFromParcel(parcel: Parcel): CDrugs {return CDrugs(parcel)}override fun newArray(size: Int): Array<CDrugs?> {return arrayOfNulls(size)}}}

03

编写适配器adapter

由于要每个宫格实现拽拖替换,所以在适配器中每个宫格都要加上拖拽的动作和监听。

在每个itemview中设置tag记录当前在adapter中的position,通过设置onDragListener来捕获监听事件,长按OnLongClick来实现拖拽。

在ClipData数据中,我们通过Intent传递,直接用ClipData.newIntent的方法实现,传入的是原来的位置,这样直接从列表中定位到对应序号就可以查到数据。

package pers.vaccae.draganddropdemo.adapterimport android.content.ClipData
import android.content.Intent
import android.view.DragEvent
import android.view.View
import androidx.core.view.DragStartHelper
import androidx.draganddrop.DropHelper
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import pers.vaccae.draganddropdemo.R
import pers.vaccae.draganddropdemo.bean.CDrugs/*** 作者:Vaccae* 邮箱:3657447@qq.com* 创建时间:14:49* 功能模块说明:*/
class DrugsAdapter(layoutId: Int, drugslist: MutableList<CDrugs>? = null) :BaseQuickAdapter<CDrugs, BaseViewHolder>(layoutId, drugslist) {var mDragEventListener = DragEventListener(this)override fun convert(holder: BaseViewHolder, item: CDrugs) {holder.setText(R.id.rcl_drugs_ckcode, item.drugs_ckcode.toString())holder.setText(R.id.rcl_drugs_code, item.drugs_code)holder.setText(R.id.rcl_drugs_name, item.drugs_name)holder.setText(R.id.rcl_drugs_specs, item.drugs_specs)holder.setText(R.id.rcl_qty, item.qty.toString())holder.itemView.setTag(holder.adapterPosition)holder.itemView.setOnDragListener(mDragEventListener)holder.itemView.setOnLongClickListener {//定义Intentval intent = Intent()intent.putExtra("pos", holder.adapterPosition)val dragdata = ClipData.newIntent("olditem", intent)val shadow: View.DragShadowBuilder = View.DragShadowBuilder(it)it.startDragAndDrop(dragdata, shadow, null, 0)}}
}

监听事件

写一个OnDragListener的事件,前面的流程图中可以看到,Droped的事件是用户手指在一个View的范围内松开拖拽影子的时候可以接受拖拽数据,所以事件中数据的替换直接在Droped中处理即可。

package pers.vaccae.draganddropdemo.adapterimport android.view.DragEvent
import android.view.View
import pers.vaccae.draganddropdemo.bean.CDrugs/*** 作者:Vaccae* 邮箱:3657447@qq.com* 创建时间:09:25* 功能模块说明:*/
class DragEventListener(adapter: DrugsAdapter) : View.OnDragListener {var mAdapter = adapteroverride fun onDrag(p0: View?, p1: DragEvent?): Boolean {p1?.let {when (it.action) {DragEvent.ACTION_DROP -> {val intent = it.clipData.getItemAt(0).intentval oldpos = intent.getIntExtra("pos", -1)//记录现在格的数据val nowpos = p0?.getTag() as Int//将现在格数据存到临时变量中val nowitem = CDrugs()nowitem.drugs_ckcode = mAdapter.data[nowpos].drugs_ckcodenowitem.drugs_code = mAdapter.data[nowpos].drugs_codenowitem.drugs_name = mAdapter.data[nowpos].drugs_namenowitem.drugs_specs = mAdapter.data[nowpos].drugs_specsnowitem.qty = mAdapter.data[nowpos].qty//修改现在格的数据mAdapter.data[nowpos].drugs_ckcode = nowitem.drugs_ckcode;mAdapter.data[nowpos].drugs_code = mAdapter.data[oldpos].drugs_codemAdapter.data[nowpos].drugs_name = mAdapter.data[oldpos].drugs_namemAdapter.data[nowpos].drugs_specs = mAdapter.data[oldpos].drugs_specsmAdapter.data[nowpos].qty = mAdapter.data[oldpos].qty//修改原来的格数据mAdapter.data[oldpos].drugs_code = nowitem.drugs_codemAdapter.data[oldpos].drugs_name = nowitem.drugs_namemAdapter.data[oldpos].drugs_specs = nowitem.drugs_specsmAdapter.data[oldpos].qty = nowitem.qtymAdapter.notifyItemChanged(nowpos)mAdapter.notifyItemChanged(oldpos)}}}return true}
}

事件最后的返回要都写true,返回false只能接受到ACTION_DRAG_STARTED事件,其他事件收不到。

04

主界面代码

主界面中加入一个初始化数据,生成对应的数据列表

package pers.vaccae.draganddropdemoimport android.content.ClipData
import android.content.ClipDescription
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ContentInfoCompat
import androidx.core.view.DragStartHelper
import androidx.core.view.OnReceiveContentListener
import androidx.draganddrop.DropHelper
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import pers.vaccae.draganddropdemo.adapter.DrugsAdapter
import pers.vaccae.draganddropdemo.adapter.DrugsAdapterNew
import pers.vaccae.draganddropdemo.bean.CDrugsclass MainActivity : AppCompatActivity() {private val recyclerView: RecyclerView by lazy { findViewById(R.id.recycler_view) }val drugslist = mutableListOf<CDrugs>()lateinit var adapter: DrugsAdapteroverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)//初始化数据initdata()adapter = DrugsAdapter(R.layout.rcl_item, drugslist)val gridLayoutManager = GridLayoutManager(this, 3)recyclerView.layoutManager = gridLayoutManagerrecyclerView.adapter = adapterval btn = findViewById<Button>(R.id.btn)btn.setOnClickListener {for(item in drugslist){Log.i("main", item.drugs_ckcode.toString() + " "+ item.drugs_code+" "+item.drugs_name)}}}fun initdata() {var ckcode = 1000for (i in 1..9) {val item = CDrugs()if (i % 3 == 0) {item.drugs_ckcode = ckcode + 3ckcode += 1000} else {item.drugs_ckcode = ckcode + i % 3}item.drugs_code = "00000$i"item.drugs_name = "测试药品$i"item.drugs_specs = "50ml"item.qty = idrugslist.add(item)}}
}

这样拖拽的效果就可以实现了,打印按钮是输出生成的List数据,虽然拖拽的效果在adapter中编写的,但在外面List数据中也会同步的进行修改。

上图中的顺序,点击打印按钮可以看一下输出列表。

可以看到输入的和界面上的也完全一致。

源码地址

https://github.com/Vaccae/Android-DragAndDropDemo.git

点击原文链接可以跳转到“码云”的下载地址

往期精彩回顾

OpenCV实现图片批号效期提取

OpenCV图像锐化---USM锐化和Laplace锐化

Android Studio 2021.1.1的getNdkVersion的Bug及解决办法

Android使用DragAndDrop拖拽效果实现宫格位置变换相关推荐

  1. 不一样的 9 宫格图片展示,仿 Nice 首页图片列表 9 图样式,并实现拖拽效果

    ImageNice9Layout 项目地址:wobiancao/ImageNice9Layout  简介:不一样的 9 宫格图片展示,仿 Nice 首页图片列表 9 图样式,并实现拖拽效果 写在开头: ...

  2. android 跟随动画,Android实现View拖拽跟随手指移动效果

    今天想实现这个功能,但是网上搜索代码,都是利用setPadding,setMargin 等方法去实现的,这在Android 4.0 以前是没问题的,但是,android 4.0 后系统已经提供了更简单 ...

  3. Android实现高德地图上拉,ScrollLayout:上拉滑动上滑拖出,类似高德地图百度地图抽屉拖拽效果...

    摘要 在ScrollView或者ListView里面使用ViewPager.支持手势上拉滑出,中途停顿,下滑退出页面,类似高德地图百度地图内场景抽屉拖拽效果效果 Gif动画 类似使用 Demo 下载A ...

  4. android气泡聊天消息背景,Android使用贝塞尔曲线仿QQ聊天消息气泡拖拽效果

    本文实例为大家分享了Android仿QQ聊天消息气泡拖拽效果展示的具体代码,供大家参考,具体内容如下 先画圆,都会吧.代码如下: public class Bezier extends View { ...

  5. Android 贝塞尔曲线——类似QQ红点拖拽效果

    在Android绘制中,提供了更为丰富绘制api--Path类,包括直线,二阶贝塞尔曲线,三阶贝塞尔曲线,弧形,圆,椭圆,圆角矩形等等,path的绘制最终是调用了C中的绘制方法. 下面来看一下常用的几 ...

  6. Android仿QQ消息拖拽效果(二)

    前言 本文参考辉哥贝塞尔曲线 - QQ消息汽包拖拽,前面我们使用二阶贝塞尔曲线绘制了拖拽圆点效果Android仿QQ消息拖拽效果(一)(二阶贝塞尔曲线使用),这里我们在此基础之上实现仿QQ消息拖拽爆炸 ...

  7. Android之实现RecyclerView拖拽效果和固定部分元素不进行交换位置(包含源代码下载地址)

    1.效果爆照 启动的效果 拖动过程中的效果 拖动后的效果 2.需求和问题 需求:RecyclerView实现拖拽效果,但是部分固定位置不能进行拖拽也不能在拖拽的过程中交换顺序

  8. android rebound平移,Android 仿 IOS 拖拽回弹之进阶 ReboundFrameLayout

    Android 仿 IOS 拖拽回弹之进阶 ReboundFrameLayout 前言 IOS 拖拽回弹给用户的体验不得不赞然后 Android 原生的 API 各种不支持, 于是乎出现的很多仿 IO ...

  9. 小程序Android端movable-view拖拽卡顿掉帧的优化

    背景: 最近项目中使用到movable-view来做一个拖拽排序的功能,等到功能都实现完成后到真机测试发现,拖拽动画在Android端存在严重的卡顿掉帧,及其不跟手,但是在IOS端却挺流畅.查阅Goo ...

  10. 仿QQ消息气泡拖拽效果

    此次的自定义View是仿qq消息列表,消息气泡拖拽效果. 1.原理介绍:自定义view,绘制原始点圆,touch点圆,然后将两圆用贝塞尔曲线连接并填充. 2.应用WindowManager,将自定义v ...

最新文章

  1. Cortex-M3的工作模式和特权级别
  2. 笔记-项目范围管理-确认范围与控制范围的区别
  3. GetClientRect相当于GetWindowRect和ScreenToClient区别
  4. Drawbot赋能商家: 智能助手主打上新详情
  5. python按键退出循环_python – 按退出键退出循环
  6. Windows访问samba:\\IP不行,那就\\IP\共享名
  7. paip.spring 获取bean getBean 没有beanid的情况下
  8. My SQL数据库基本操作
  9. vsftpd移植到ARM开发板
  10. WinDbg手动修复堆栈
  11. 高仿优酷Android客户端图片左右滑动(自动切换)
  12. 铁路基因的传承与创新
  13. 家门口的微醺“buff”——酒分之一开启社区酒吧式便利店次元
  14. 通过Requst进行12306查票(2022-09-10)
  15. Java 面试题看这些就够了
  16. 营地第一天之今天我是伙委
  17. python大牛_成为Python大牛必须要掌握的高端语法——yield
  18. Unity Android通过拍照和相册上传头像(图片)
  19. 帝国cms php序号,帝国cms输出数字排序序号的列表
  20. Command ‘yum‘ not found, did you mean

热门文章

  1. Linux学习:四层负载均衡详解
  2. python 邮件合并的基本操作步骤_邮件合并操作过程
  3. 如何上色?怎样才能配出好看的颜色?
  4. ESP-AT 应用: AT+MQTT 对接腾讯 QCloud 云
  5. [1-1] 把时间当做朋友(李笑来)Chapter 1 【心智的力量】 摘录
  6. MacBook Air 2013全新安装Win7
  7. 梁建章:我带领携程战胜所有竞争对手的方法论
  8. 零点起飞学java web_零点起飞学Java Web开发 (徐林林) 高清PDF_IT教程网
  9. IMO 双帐号同步API文档
  10. 【CSS】水滴动画|水滴融合效果