软件编程
位置:首页>> 软件编程>> Android编程>> Android Activity通用悬浮可拖拽View封装的思路详解

Android Activity通用悬浮可拖拽View封装的思路详解

作者:熊熊君fly  发布时间:2023-08-08 15:31:48 

标签:Android,Activity,拖拽,View

1,背景

在开发中总会遇到一个可拖拽的悬浮View,不管是在开发中,还是在线上,都时长有这样的控件,我们通常遇到这种情况,经常需要自己封装,需要耗费时间,我这边封装了一个可以通用的悬浮可拖拽View,这样使用的时候,只需要传入自己要设计的样式和位置既可

2,思路

2.1,封装通用的基础悬浮View

设计通用的父View

1,传入的childView是可以自定义layout,可以传入任何样式

childView = setChildView()

2,可以设置初始的位置

layoutParams = setChildInitLayoutParams()

3,可以修改自定义view控件

setChildAction(childView)

4,提供点击事件处理

protected abstract fun setEventClick()

子view继承父view就可以实现自己想要的功能了

abstract class AbsParentDragView : FrameLayout, View.OnTouchListener {

//需要添加的子控件
   private var childView: View? = null
   //子控件的宽
   protected var childWidth: Int = 0
   //子控件的高
   protected var childHeight: Int = 0
   //子控件的位置属性
   lateinit var layoutParams: LayoutParams
   //点击区域偏移量
   private var regionW: Int = 0
   //判断是否可以移动
   private var isCanMove: Boolean = false

private val MIN_TAP_TIME = 1000

private val MIN_DISTANCE_MOVE = 4

private var mState = TouchState.STATE_STOP

private var distance: Int = 0

private enum class TouchState {
       STATE_MOVE, STATE_STOP
   }

constructor(context: Context) : super(context) {
       initView()
   }

constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
       initView()
   }

constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
       context,
       attrs,
       defStyleAttr
   ) {
       initView()
   }

private fun initView() {

childView = setChildView()

setChildAction(childView)
       addView(childView)
       setOnTouchListener(this)
       layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)

regionW = DensityUtil.dip2px(context, 3f)
       distance = DensityUtil.dip2px(context,1f) * MIN_DISTANCE_MOVE

post {
           childView?.width?.let {
               childWidth = it
           }
           childView?.height?.let {
               childHeight = it
           }

layoutParams = setChildInitLayoutParams()
           initLayoutParams()
       }

}

protected abstract fun setChildView(): View?

protected abstract fun setChildInitLayoutParams(): FrameLayout.LayoutParams

protected abstract fun setChildAction(childView: View?)

private fun initLayoutParams() {
       layoutParams.gravity = Gravity.LEFT or Gravity.TOP
       childView?.layoutParams = layoutParams
   }

private fun updateLayoutParams(dx: Int, dy: Int) {
       layoutParams.gravity = Gravity.LEFT or Gravity.TOP
       layoutParams.leftMargin = dx - childWidth / 2
       layoutParams.topMargin = dy - childHeight / 2 - StateUtils.getStatusBarHeight(context)
       childView?.layoutParams = layoutParams
   }

private var mStartX:Int = 0
   private var mStartY:Int = 0
   override fun onTouch(view: View, event: MotionEvent): Boolean {
       val x = event.rawX.toInt()
       val y = event.rawY.toInt()
       when(event.action){
           MotionEvent.ACTION_DOWN -> {
               mStartX = x
               mStartY = y
               if (isPointChoice(x, y)) {
                   isCanMove = true
               }
           }
           MotionEvent.ACTION_MOVE -> {
               if (Math.abs(x - mStartX) < distance
                   && Math.abs(y - mStartY) < distance) {
                   if (mState == TouchState.STATE_STOP) {
                       return true
                       //break
                   }
               } else if (mState != TouchState.STATE_MOVE) {
                   mState = TouchState.STATE_MOVE
               }

if(isCanMove){
                   updateLayoutParams(x, y)
               }

mState = TouchState.STATE_MOVE
           }
           MotionEvent.ACTION_UP -> {
               isCanMove = false

if (mState != TouchState.STATE_MOVE
                   && event.eventTime - event.downTime < MIN_TAP_TIME) {
                   setEventClick()
               }

mState = TouchState.STATE_STOP
           }
       }

return isCanMove
   }

protected abstract fun setEventClick()

private fun isPointChoice(x: Int, y: Int): Boolean {
       val cLocation = IntArray(2)
       childView?.getLocationOnScreen(cLocation)

val horizontalMatch =
           x > (cLocation[0] + regionW) && x < (cLocation[0] + childWidth + regionW)
       val verticalMatch =
           y < (cLocation[1] + childHeight + DensityUtil.dip2px(context,10f)) && y > (cLocation[1] - regionW)

if (horizontalMatch && verticalMatch) {
           return true
       }

return false
   }
}

2.1,继承通用View

class DemoLineView(context: Context, attrs: AttributeSet?) : AbsParentDragView(context, attrs) {
   override fun setChildView(): View? {
       return LayoutInflater.from(context).inflate(R.layout.layout_draw_item, this, false)
   }

override fun setChildInitLayoutParams(): LayoutParams {
       layoutParams.topMargin = DensityUtil.getScreenHeight(
           context
       ) - childHeight - DensityUtil.dip2px(context, 80f)
       layoutParams.leftMargin = DensityUtil.getScreenWidth(
           context
       ) - childWidth - DensityUtil.dip2px(context, 20f)
       return layoutParams
   }

override fun setChildAction(childView: View?) {
       val tvSafeLine = childView?.findViewById<TextView>(R.id.tvSafeLine)
       tvSafeLine?.text = "设置悬浮"
   }

override fun setEventClick() {
       Toast.makeText(context,"悬浮view",Toast.LENGTH_LONG).show()

}

}

2.3,设计view的控制器

open class DragViewManager private constructor(context: Activity) {
   private var activity: Activity = context
   companion object : SingletonHolder<DragViewManager, Activity>(::DragViewManager)
   private lateinit var dragView: AbsParentDragView
   private val contentView = activity.window.decorView.findViewById<View>(android.R.id.content) as FrameLayout
   fun create(dragView: AbsParentDragView){
       this.dragView = dragView
       if(contentView.contains(dragView)){
           contentView.removeView(dragView)
       }
       contentView.addView(dragView)
   }
   fun show(){
       dragView.visibility = View.VISIBLE
   }
   fun dismiss(){
       dragView.visibility = View.INVISIBLE
   }
}

2.4,view的添加和使用

//创建出要显示的View
DragViewManager.getInstance(this).create(new DemoLineView(this,null));
//隐藏要显示的View
DragViewManager.getInstance(this).dismiss();
//显示要显示的View
DragViewManager.getInstance(this).show();

代码链接地址:gitee.com/component_i&hellip;

来源:https://juejin.cn/post/7039300295775485965

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com