SoFunction
Updated on 2025-04-09

Detailed explanation of Android Activity's universal suspension and drag-and-drop view packaging ideas

1. Background

During development, you will always encounter a drag-and-drop floating view. Whether it is during development or online, there are such controls for a long time. We usually encounter this situation and often need to encapsulate it ourselves, which takes time. I have encapsulated a universal floating drag-and-drop view. When using this, you only need to pass in the style and position you want to design.

2. Ideas

2.1, Package common basic suspended view

Design a common parent view

1. The childView passed in can be customized layout and can be passed in any style.

childView = setChildView()

2. The initial position can be set

layoutParams = setChildInitLayoutParams()

3. You can modify custom view controls

setChildAction(childView)

4. Provide click event processing

protected abstract fun setEventClick()

The child view can implement the function you want by inheriting the parent view

abstract class AbsParentDragView : FrameLayout,  {

    //Subcontrols that need to be added    private var childView: View? = null
    //The width of the child control    protected var childWidth: Int = 0
    //The height of the child control    protected var childHeight: Int = 0
    //Position properties of child control    lateinit var layoutParams: LayoutParams
    //Click area offset    private var regionW: Int = 0
    //Judge whether it can be moved    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(): 

    protected abstract fun setChildAction(childView: View?)

    private fun initLayoutParams() {
         =  or 
        childView?.layoutParams = layoutParams
    }

    private fun updateLayoutParams(dx: Int, dy: Int) {
         =  or 
         = dx - childWidth / 2
         = dy - childHeight / 2 - (context)
        childView?.layoutParams = layoutParams
    }

    private var mStartX:Int = 0
    private var mStartY:Int = 0
    override fun onTouch(view: View, event: MotionEvent): Boolean {
        val x = ()
        val y = ()
        when(){
            MotionEvent.ACTION_DOWN -> {
                mStartX = x
                mStartY = y
                if (isPointChoice(x, y)) {
                    isCanMove = true
                }
            }
            MotionEvent.ACTION_MOVE -> {
                if ((x - mStartX) < distance
                    && (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
                    &&  -  < 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, Inheriting General View

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


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

    override fun setChildAction(childView: View?) {
        val tvSafeLine = childView?.findViewById<TextView>()
        tvSafeLine?.text = "Set up the floating"
    }

    override fun setEventClick() {
        (context,"Suspended View",Toast.LENGTH_LONG).show()

    }

}

2.3, Design the controller for 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 = <View>() as FrameLayout
    fun create(dragView: AbsParentDragView){
         = dragView
        if((dragView)){
            (dragView)
        }
        (dragView)
    }
    fun show(){
         = 
    }
    fun dismiss(){
         = 
    }
}

2.4, Add and use of view

//Create the View to be displayed(this).create(new DemoLineView(this,null));
//Hide the View to be displayed(this).dismiss();
//Show the View to be displayed(this).show();

Code link address:/component_i…

This is the article about Android Activity universal floating and drag view packaging. For more information about Android Activity drag view packaging, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!