Android?Activity通用懸浮可拖拽View封裝的思路詳解
1,背景
在開發(fā)中總會遇到一個(gè)可拖拽的懸浮View,不管是在開發(fā)中,還是在線上,都時(shí)長有這樣的控件,我們通常遇到這種情況,經(jīng)常需要自己封裝,需要耗費(fèi)時(shí)間,我這邊封裝了一個(gè)可以通用的懸浮可拖拽View,這樣使用的時(shí)候,只需要傳入自己要設(shè)計(jì)的樣式和位置既可
2,思路
2.1,封裝通用的基礎(chǔ)懸浮View
設(shè)計(jì)通用的父View
1,傳入的childView是可以自定義layout,可以傳入任何樣式
childView = setChildView()
2,可以設(shè)置初始的位置
layoutParams = setChildInitLayoutParams()
3,可以修改自定義view控件
setChildAction(childView)
4,提供點(diǎn)擊事件處理
protected abstract fun setEventClick()
子view繼承父view就可以實(shí)現(xiàn)自己想要的功能了
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 //點(diǎn)擊區(qū)域偏移量 private var regionW: Int = 0 //判斷是否可以移動(dòng) 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 = "設(shè)置懸浮" } override fun setEventClick() { Toast.makeText(context,"懸浮view",Toast.LENGTH_LONG).show() } }
2.3,設(shè)計(jì)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的添加和使用
//創(chuàng)建出要顯示的View DragViewManager.getInstance(this).create(new DemoLineView(this,null)); //隱藏要顯示的View DragViewManager.getInstance(this).dismiss(); //顯示要顯示的View DragViewManager.getInstance(this).show();
代碼鏈接地址:gitee.com/component_i…
到此這篇關(guān)于Android Activity通用懸浮可拖拽View封裝的文章就介紹到這了,更多相關(guān)Android Activity拖拽View封裝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android編程實(shí)現(xiàn)的首頁左右滑動(dòng)切換功能示例
這篇文章主要介紹了Android編程實(shí)現(xiàn)的首頁左右滑動(dòng)切換功能,涉及Android事件監(jiān)聽及響應(yīng)相關(guān)操作技巧,需要的朋友可以參考下2017-07-07listview 選中高亮顯示實(shí)現(xiàn)方法
當(dāng)點(diǎn)擊左側(cè)ListView后,選中的一行就會一直呈高亮狀態(tài)顯示,圖中選中行字的顏色顯示為藍(lán)色(注意:是選中行后一直高亮,而不是只是點(diǎn)擊時(shí)高亮),如果再次點(diǎn)擊另外的一行, 則新的那一行就高亮,下面就來實(shí)現(xiàn)這個(gè)高亮效果的顯示2012-11-11Android開發(fā)基礎(chǔ)使用ProgressBar加載進(jìn)度條示例
這篇文章主要介紹了安卓開發(fā)基礎(chǔ)使用ProgressBar加載進(jìn)度條示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02Android實(shí)例HandlerThread源碼分析
本篇文章主要給大家通過實(shí)例代碼分析了Android中HandlerThread的用法以及步驟,需要的朋友參考學(xué)習(xí)下吧。2017-12-12Android RefreshLayout實(shí)現(xiàn)下拉刷新布局
這篇文章主要為大家詳細(xì)介紹了Android RefreshLayout實(shí)現(xiàn)下拉刷新布局,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10