如图:
实现思路
通过重写控件的ontouchEvent方法监听触摸效果
通过VIEw的setX()和setY()方法实现移动
使用属性动画实现边缘吸附效果
手指按下
首先是处理手指按压下的事件,这里我们把拖拽标识符设置为false并记录当前点击的屏幕坐标。然后我们在移动事件处
手指移动
这里我们把拖拽标识符设置为true,因为手指移动了。然后我们需要计算手指移动了多少偏移量
//计算手指移动了多少int dx=rawX-lastX;int dy=rawY-lastY;
而后的两行代码表示控件需要移动的具体距离,后面有一个简单的边缘检测计算。最终通过调用setX以及setY方法实现控件的移动
手指松开
这里如果是拖拽动作我们才需要处理自己的逻辑否则直接跳过即可。在这里我们首先恢复了按钮的按压效果,在源代码中找到setpressed(boolean)方法,这是处理按钮点击效果用的,在这里当手指松开后我们需要恢复按钮原来的效果。然后在判断控件需要往哪边吸附,吸附的过程就是做属性动画而已,原理还是不断的改变setX方法让按钮靠边移动
代码区
关于自定义的拖拽VIEw (核心部分)
继承类(均可实现拖拽)
有的继承AppCompatimageVIEw下的ImageVIEw
有的继承floatingActionbutton(如果继承此类需要导入以下依赖)
compile 'com.androID.support:design:26.1.0'implementation 'com.androID.support:appcompat-v7:26.1.0'
DragfloatActionbutton (Kotlin版)
package com.example.mychartdemoimport androID.animation.ObjectAnimatorimport androID.annotation.Suppresslintimport androID.content.Contextimport androID.util.AttributeSetimport androID.util.Logimport androID.vIEw.MotionEventimport androID.vIEw.VIEwGroupimport androID.vIEw.animation.DecelerateInterpolatorimport androID.Widget.ImageVIEw//https://blog.csdn.net/qq_20451879/article/details/87876673//效果可以@Suppresslint("AppCompatCustomVIEw")class DragfloatActionbutton : ImageVIEw { private var parentHeight: Int = 0 private var parentWIDth: Int = 0 constructor(context: Context?) : super(context) constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) private var lastX: Int = 0 private var lastY: Int = 0 public var isDrag: Boolean = false public var isRight: Boolean = false public var istop: Boolean = true public var isCanMove: Boolean = true overrIDe fun ontouchEvent(event: MotionEvent): Boolean { val rawX = event.rawX.toInt() val rawY = event.rawY.toInt() Log.i("打印X轴、Y轴坐标:","rawX:$rawX ,rawY: $rawY") if (!isCanMove){//不可移动 return super.ontouchEvent(event) } when (event.action and MotionEvent.ACTION_MASK) { MotionEvent.ACTION_DOWN -> { ispressed = true isDrag = false parent.requestdisallowIntercepttouchEvent(true) lastX = rawX lastY = rawY val parent: VIEwGroup if (getParent() != null) { parent = getParent() as VIEwGroup parentHeight = parent.height parentWIDth = parent.wIDth } } MotionEvent.ACTION_MOVE -> { isDrag = !(parentHeight <= 0 || parentWIDth === 0) /*if (parentHeight <= 0 || parentWIDth === 0) { isDrag = false } else { isDrag = true }*/ val dx = rawX - lastX val dy = rawY - lastY //这里修复一些华为手机无法触发点击事件 val distance = Math.sqrt((dx * dx + dy * dy).todouble()).toInt() if (distance == 0) { isDrag = false } else { var x = x + dx var y = y + dy //检测是否到达边缘 左上右下 x = if (x < 0) 0F else if (x > parentWIDth - wIDth) (parentWIDth - wIDth).tofloat() else x y = if (getY() < 0) 0F else if (getY() + height > parentHeight) (parentHeight - height).tofloat() else y setX(x) setY(y) lastX = rawX lastY = rawY Log.i("aa", "isDrag=" + isDrag + "getX=" + getX() + ";getY=" + getY() + ";parentWIDth=" + parentWIDth) } } MotionEvent.ACTION_UP -> if (!isNotDrag()) { //恢复按压效果 ispressed = false //Log.i("getX="+getX()+";screenWIDthHalf="+screenWIDthHalf); if (rawX >= parentWIDth / 2) { //靠右吸附 animate().setInterpolator(DecelerateInterpolator()) .setDuration(500) .xBy(parentWIDth - wIDth - x) .start() isRight = true } else { //靠左吸附 val oa = ObjectAnimator.offloat(this, "x", x, 0F) oa.interpolator = DecelerateInterpolator() oa.duration = 500 oa.start() isRight = false } //判断是否位于上半部分 istop = rawY <= parentHeight/2 Log.i("打印是否位于顶部:",""+istop) } } //如果是拖拽则消s耗事件,否则正常传递即可。 return !isNotDrag() || super.ontouchEvent(event) } private fun isNotDrag(): Boolean { return !isDrag && (x == 0f || x == (parentWIDth - wIDth).tofloat()) }}
主布局文件
<?xml version="1.0" enCoding="utf-8"?><linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" xmlns:tools="http://schemas.androID.com/tools" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" androID:orIEntation="vertical" tools:context=".MainActivity3"> <com.example.mychartdemo.DragfloatActionbutton androID:layout_wIDth="45dp" androID:layout_height="45dp" androID:ID="@+ID/img_btn" androID:src="@mipmap/ic_launcher"></com.example.mychartdemo.DragfloatActionbutton></linearLayout>
MainActivity
package com.example.mychartdemoimport androID.graphics.drawable.BitmapDrawableimport androID.os.Bundleimport androID.util.Logimport androID.vIEw.VIEwimport androID.Widget.ImageVIEwimport androID.Widget.PopupWindowimport androID.Widget.RadioGroupimport androIDx.appcompat.app.AppCompatActivityimport com.example.mychartdemo.databinding.ActivityMain3Bindingclass MainActivity : AppCompatActivity(),VIEw.OnClickListener{ private var popupWindow: PopupWindow? = null private lateinit var binding: ActivityMain3Binding overrIDe fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMain3Binding.inflate(layoutInflater) setContentVIEw(binding.root) binding.imgBtn.setonClickListener { if (popupWindow == null) { initPopWindow() //设置不可拖动 binding.imgBtn.isCanMove = false } else if (popupWindow != null && popupWindow?.isShowing == true) { popupWindow?.dismiss() popupWindow = null //设置可拖动 binding.imgBtn.isCanMove = true } } } private fun initPopWindow() { var vIEw: VIEw? = null if(binding.imgBtn.isRight){ vIEw = VIEw.inflate(this, R.layout.popwindow_vIEw, null) }else{ vIEw = VIEw.inflate(this, R.layout.popwindow_left_vIEw, null) } val popimg_1: ImageVIEw = vIEw.findVIEwByID<ImageVIEw>(R.ID.popimg_1) popimg_1.setonClickListener(this) val popimg_2: ImageVIEw = vIEw.findVIEwByID<ImageVIEw>(R.ID.popimg_2) popimg_2.setonClickListener(this) val popimg_3: ImageVIEw = vIEw.findVIEwByID<ImageVIEw>(R.ID.popimg_3) popimg_3.setonClickListener(this) popupWindow = PopupWindow( vIEw, DensityUtil.dip2px(this, 160F), RadioGroup.LayoutParams.WRAP_CONTENT ) popupWindow?.settouchable(true) //设置可以点击 popupWindow?.setoutsIDetouchable(false) //点击外部关闭 // popupWindow.setBackgroundDrawable(new colorDrawable());//设置背景 // popupWindow.setBackgroundDrawable(new colorDrawable());//设置背景 popupWindow?.setBackgroundDrawable(BitmapDrawable()) if (binding.imgBtn.istop){ Log.i("打印是否位于顶部111:",""+binding.imgBtn.istop) popupWindow?.showAsDropDown(binding.imgBtn) }else{ if(binding.imgBtn.isRight){ Log.i("打印是否位于顶部222:",""+binding.imgBtn.istop) popupWindow?.showAsDropDown(binding.imgBtn) }else{ Log.i("打印是否位于顶部3333:",""+binding.imgBtn.istop) popupWindow?.showAsDropDown(binding.imgBtn,0,DensityUtil.dip2px(this,-200F)) } } } overrIDe fun onClick(v: VIEw) { when (v.ID) { R.ID.popimg_1 -> { if (popupWindow != null) { popupWindow?.dismiss() popupWindow = null //设置可拖动 binding.imgBtn.isCanMove = true Log.i("点击了","111") }else{ Log.i("点击了","2222") } } R.ID.popimg_2 -> { if (popupWindow != null) { popupWindow?.dismiss() popupWindow = null //设置可拖动 binding.imgBtn.isCanMove = true } } R.ID.popimg_3 -> { if (popupWindow != null) { popupWindow?.dismiss() popupWindow = null //设置可拖动 binding.imgBtn.isCanMove = true } } } }}
popwindow_vIEw 布局文件
<?xml version="1.0" enCoding="utf-8"?><linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" androID:orIEntation="vertical"> <linearLayout androID:layout_wIDth="match_parent" androID:layout_height="50dp" androID:orIEntation="horizontal"> <TextVIEw androID:layout_wIDth="0dp" androID:layout_weight="1" androID:layout_height="match_parent" androID:text="满刻度" androID:gravity="center|right" androID:paddingRight="10dp"></TextVIEw> <ImageVIEw androID:layout_wIDth="50dp" androID:layout_height="50dp" androID:src="@mipmap/ic_launcher" androID:ID="@+ID/popimg_1"></ImageVIEw> </linearLayout> <linearLayout androID:layout_wIDth="match_parent" androID:layout_height="50dp" androID:orIEntation="horizontal"> <TextVIEw androID:layout_wIDth="0dp" androID:layout_weight="1" androID:layout_height="match_parent" androID:text="数据明细" androID:gravity="center|right" androID:paddingRight="10dp"></TextVIEw> <ImageVIEw androID:layout_wIDth="50dp" androID:layout_height="50dp" androID:src="@mipmap/ic_launcher" androID:ID="@+ID/popimg_2"></ImageVIEw> </linearLayout> <linearLayout androID:layout_wIDth="match_parent" androID:layout_height="50dp" androID:orIEntation="horizontal"> <TextVIEw androID:layout_wIDth="0dp" androID:layout_weight="1" androID:layout_height="match_parent" androID:text="选择日期" androID:gravity="center|right" androID:paddingRight="10dp"></TextVIEw> <ImageVIEw androID:layout_wIDth="50dp" androID:layout_height="50dp" androID:src="@mipmap/ic_launcher" androID:ID="@+ID/popimg_3"></ImageVIEw> </linearLayout></linearLayout>
popwindow_left_vIEw 左边布局文件
<?xml version="1.0" enCoding="utf-8"?><linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" androID:orIEntation="vertical"> <linearLayout androID:layout_wIDth="match_parent" androID:layout_height="50dp" androID:orIEntation="horizontal"> <ImageVIEw androID:layout_wIDth="50dp" androID:layout_height="50dp" androID:src="@mipmap/ic_launcher" androID:ID="@+ID/popimg_1"></ImageVIEw> <TextVIEw androID:layout_wIDth="0dp" androID:layout_weight="1" androID:layout_height="match_parent" androID:text="满刻度" androID:gravity="center|left" androID:paddingleft="10dp"></TextVIEw> </linearLayout> <linearLayout androID:layout_wIDth="match_parent" androID:layout_height="50dp" androID:orIEntation="horizontal"> <ImageVIEw androID:layout_wIDth="50dp" androID:layout_height="50dp" androID:src="@mipmap/ic_launcher" androID:ID="@+ID/popimg_2"></ImageVIEw> <TextVIEw androID:layout_wIDth="0dp" androID:layout_weight="1" androID:layout_height="match_parent" androID:text="数据明细" androID:gravity="center|left" androID:paddingleft="10dp"></TextVIEw> </linearLayout> <linearLayout androID:layout_wIDth="match_parent" androID:layout_height="50dp" androID:orIEntation="horizontal"> <ImageVIEw androID:layout_wIDth="50dp" androID:layout_height="50dp" androID:src="@mipmap/ic_launcher" androID:ID="@+ID/popimg_3"></ImageVIEw> <TextVIEw androID:layout_wIDth="0dp" androID:layout_weight="1" androID:layout_height="match_parent" androID:text="选择日期" androID:gravity="center|left" androID:paddingleft="10dp"></TextVIEw> </linearLayout></linearLayout>
完成
参考于:https://blog.csdn.net/qq_20451879/article/details/87876673
总结
以上是内存溢出为你收集整理的Android中实现一个可拖动的悬浮按钮,点击d出菜单的功能全部内容,希望文章能够帮你解决Android中实现一个可拖动的悬浮按钮,点击d出菜单的功能所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)