Android?控件自動(dòng)貼邊實(shí)現(xiàn)實(shí)例詳解
正文
最近接到個(gè)需求,需要在用戶與App交互時(shí),把SDK中之前實(shí)現(xiàn)過的懸浮控件貼邊隱藏,結(jié)束交互后延遲一段時(shí)間再自動(dòng)顯示。本篇文章介紹一下實(shí)現(xiàn)的思路。
判斷交互
用戶與App交互、結(jié)束交互可以通過監(jiān)聽觸摸事件來(lái)實(shí)現(xiàn)。建議使用的Activity的dispatchTouchEvent,Activity下的所有觸摸事件分發(fā)時(shí)都會(huì)回調(diào)此方法,代碼如下:
class AutoEdgeHideActivity : BaseGestureDetectorActivity() {
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
when (ev.action) {
MotionEvent.ACTION_DOWN -> {
// 手指按下,開始本次交互
// 在此實(shí)現(xiàn)隱藏邏輯
}
MotionEvent.ACTION_UP -> {
// 手指抬起,結(jié)束本次交互
// 在此實(shí)現(xiàn)延遲顯示功能
}
}
return super.dispatchTouchEvent(ev)
}
}
隱藏與顯示
想要實(shí)現(xiàn)的效果是當(dāng)用戶與App交互時(shí),懸浮控件平移貼邊,但保留一部分顯示。結(jié)束交互延遲一段時(shí)間后,懸浮控件平移回原來(lái)的位置。
此處通過ValueAnimator來(lái)實(shí)現(xiàn),計(jì)算好控件的起始和結(jié)束位置,然后改變控件的x坐標(biāo),代碼如下:
private fun xCoordinateAnimator(view: View, startX: Float, endX: Float) {
val animator = ValueAnimator.ofFloat(startX, endX)
animator.addUpdateListener {
// 不斷更改控件的X坐標(biāo)
view.x = it.animatedValue as Float
}
// 設(shè)置插值器,速度由快變慢
animator.interpolator = DecelerateInterpolator()
// 設(shè)置動(dòng)畫的持續(xù)時(shí)間
animator.duration = 500
animator.start()
}
示例
整合之后做了個(gè)示例Demo,完整代碼如下:
class AutoEdgeHideActivity : BaseGestureDetectorActivity() {
private lateinit var binding: LayoutAutoEdgeHideActivityBinding
private var widthPixels: Int = 0
private val autoShowInterval = 2
private var interacting = false
private var hidden = false
private var lastPositionX: Float = 0f
private val handler = Handler(Looper.myLooper() ?: Looper.getMainLooper())
private val autoShowRunnable = Runnable { autoShow() }
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.layout_auto_edge_hide_activity)
widthPixels = resources.displayMetrics.widthPixels
binding.includeTitle.tvTitle.text = "AutoEdgeHideExample"
binding.vFloatView.setOnClickListener {
if (hidden) {
// 當(dāng)前為隱藏狀態(tài),先顯示
// 把之前的延遲線程先取消
handler.removeCallbacks(autoShowRunnable)
autoShow()
Toast.makeText(this, "手動(dòng)顯示控件", Toast.LENGTH_SHORT).show()
} else {
// 相應(yīng)正常的事件
Toast.makeText(this, "點(diǎn)擊了浮標(biāo)控件", Toast.LENGTH_SHORT).show()
}
}
}
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
when (ev.action) {
MotionEvent.ACTION_DOWN -> {
if (!checkIsTouchFloatView(ev, binding.vFloatView)) {
// 起始ACTION_DOWN事件在浮標(biāo)控件外,自動(dòng)隱藏浮標(biāo)控件,標(biāo)記正在交互
interacting = true
handler.removeCallbacks(autoShowRunnable)
autoHide()
}
}
MotionEvent.ACTION_UP -> {
if (interacting) {
// 交互結(jié)束,一定時(shí)間后自動(dòng)顯示,時(shí)間可以自由配置
interacting = false
handler.postDelayed(autoShowRunnable, autoShowInterval * 1000L)
}
}
}
return super.dispatchTouchEvent(ev)
}
/**
* 檢查是否觸摸浮標(biāo)控件
*/
private fun checkIsTouchFloatView(ev: MotionEvent, view: View): Boolean {
val screenLocation = IntArray(2)
view.getLocationOnScreen(screenLocation)
val viewX = screenLocation[0]
val viewY = screenLocation[1]
return (ev.x >= viewX && ev.x <= (viewX + view.width)) && (ev.y >= viewY && ev.y <= (viewY + view.height))
}
private fun autoShow() {
if (hidden) {
hidden = false
binding.vFloatView.let {
xCoordinateAnimator(it, it.x, lastPositionX)
}
}
}
private fun autoHide() {
if (!hidden) {
hidden = true
binding.vFloatView.let {
// 記錄一下顯示狀態(tài)下的x坐標(biāo)
lastPositionX = it.x
// 隱藏時(shí)的x坐標(biāo),留一點(diǎn)控件的邊緣顯示(示例中默認(rèn)控件在屏幕右側(cè))
val endX = widthPixels - it.width * 0.23f
xCoordinateAnimator(it, lastPositionX, endX)
}
}
}
private fun xCoordinateAnimator(view: View, startX: Float, endX: Float) {
val animator = ValueAnimator.ofFloat(startX, endX)
animator.addUpdateListener {
view.x = it.animatedValue as Float
}
animator.interpolator = DecelerateInterpolator()
animator.duration = 500
animator.start()
}
}
效果如圖:

以上就是Android 控件自動(dòng)貼邊實(shí)現(xiàn)實(shí)例詳解的詳細(xì)內(nèi)容,更多關(guān)于Android 控件自動(dòng)貼邊的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android線性布局與相對(duì)布局的實(shí)現(xiàn)
大家好,本篇文章主要講的是Android線性布局與相對(duì)布局的實(shí)現(xiàn),感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下2022-02-02
Android斬首行動(dòng)接口預(yù)請(qǐng)求
這篇文章主要為大家介紹了Android斬首行動(dòng)之接口預(yù)請(qǐng)求實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
Android WebView交互傳遞json字符串并解析的方法
這篇文章主要給大家介紹了關(guān)于Android中WebView交互傳遞json字符串并解析的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)各位Android開發(fā)者具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-05-05
Flutter自動(dòng)路由插件auto_route使用詳解
這篇文章主要為大家介紹了Flutter自動(dòng)路由插件auto_route的基本使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
Android Camera2實(shí)現(xiàn)最簡(jiǎn)單的預(yù)覽框顯示
這篇文章主要為大家詳細(xì)介紹了Android Camera2實(shí)現(xiàn)最簡(jiǎn)單的預(yù)覽框顯示,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
Flutter UI實(shí)現(xiàn)側(cè)拉抽屜菜單
這篇文章主要為大家詳細(xì)介紹了Flutter UI實(shí)現(xiàn)側(cè)拉抽屜菜單,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
Android動(dòng)態(tài)繪制餅狀圖的示例代碼
這篇文章主要介紹了Android動(dòng)態(tài)繪制餅狀圖的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2018-03-03

