Android?Activity通用懸浮可拖拽View封裝的思路詳解
1,背景
在開(kāi)發(fā)中總會(huì)遇到一個(gè)可拖拽的懸浮View,不管是在開(kāi)發(fā)中,還是在線上,都時(shí)長(zhǎng)有這樣的控件,我們通常遇到這種情況,經(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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android中asset文件夾與raw文件夾的區(qū)別深入解析
本篇文章是對(duì)Android中的asset文件夾與raw文件夾區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫(huà)效果(十)
這篇文章主要為大家詳細(xì)介紹了Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫(huà)效果的第十篇,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08
Android通過(guò)AlarmManager類實(shí)現(xiàn)簡(jiǎn)單鬧鐘功能
這篇文章主要為大家詳細(xì)介紹了Android通過(guò)AlarmManager類實(shí)現(xiàn)簡(jiǎn)單鬧鐘功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06
Android WebView實(shí)現(xiàn)文件下載功能
這篇文章主要為大家詳細(xì)介紹了Android WebView實(shí)現(xiàn)文件下載功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05
Android WebView基礎(chǔ)應(yīng)用詳解
這篇文章主要為大家介紹了Android中WebView這一控件的基礎(chǔ)應(yīng)用,例如:播放音樂(lè),播放視頻等,文中的示例代碼講解詳細(xì),對(duì)于我們了解WebView很有幫助,需要的同學(xué)可以學(xué)習(xí)一下2021-12-12
Android如何通過(guò)scheme跳轉(zhuǎn)界面
Android如何通過(guò)scheme跳轉(zhuǎn)界面,這篇文章就為大家介紹了Android通過(guò)scheme跳轉(zhuǎn)界面的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07
Android網(wǎng)絡(luò)技術(shù)HttpURLConnection詳解
這篇文章主要為大家詳細(xì)介紹了Android網(wǎng)絡(luò)技術(shù)HttpURLConnection的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07
Android實(shí)現(xiàn)圓線按鈕進(jìn)度效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)圓線按鈕帶進(jìn)度,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05
Android異步消息處理機(jī)制實(shí)現(xiàn)原理詳解
這篇文章主要介紹了Android異步消息處理機(jī)制實(shí)現(xiàn)原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09

