安卓:实现一个全屏拖拽、自动贴边半隐藏的自定义视窗
作者:访客发布时间:2023-10-28分类:程序开发学习浏览:149
大家好,我是似曾相识2022年不喜欢唱跳篮球,但对杰伦的Rap却情有独钟。
今天给大家带来一个可全屏拖拽,手指离开屏幕后自动贴边,隔一定时间后自动半隐藏的这么一个效果.话不多说直接上效果图:
看到这个效果是不是感觉很熟悉?没错,很多商业应用程序首页都带一个小助手的图标,使用的时候点击它就自动弹出,不使用的时候自动贴边隐藏,当然也是可以随意全屏拖拽,为的是防止遮挡一些关键位置的信息,影响用户体验。接下来咱们就来一步步实现它!
要实现上图效果咱们得罗列所有的功能点:
- 自定义观,这里要显示图片所以继承自图像视图或其子类即可
- 监听屏幕滑动事件,记录和计算当前视图的位置信息
- 动画效果,很明显使用平移动画
- 圆角图片和描边,使用第三方图像视图即可
为了解决小圆球这个图标的问题咱们自定视图时直接继承自第三方圆形图像视图、一举两得直接解决了第一和第四步.咱们把焦点聚焦到第二三部分,这也是最为复杂的部分.
之前文章安卓:自定义view实现图片缩放及坐标的计算(上)中有写到监听界面各类手势可以使用GestureDetector,这里咱们就不采用重写OnTouchEvent方法然后再里面监听各类ACTION_UP、ACTION_DOWN、ACTION_MOVE事件的模式来写了。但还是需要重写OnTouchEvent方法将GestureDetector的处理结果返回给它即可:
override fun onTouchEvent(event: MotionEvent): Boolean {
return gestureDetector.onTouchEvent(event)
}
接下来只需在GestureDetector入参的GestureDetector.SimpleOnGestureListener监听中执行对应的操作:
首先需要在按下按下方法中记录最后点击屏幕的位置信息最后一个X、耐用,这里备份一份点击时的位置信息Movex、移动、用于后续逻辑判断.
override fun onDown(e: MotionEvent): Boolean {
lastX = e.rawX.toInt()
lastY = e.rawY.toInt()
moveX = lastX
moveY = lastY
return true
}
在在滚动上中需要不停修改自定义视图的位置,所以我们需要计算出需要移动位置的信息.通过当前实时滑动点的信息和最后记录的点信息计算出滑动距离,再重新计算当前视图的上下左右位置,最后咱们采取布局()方式进行位置设置.
override fun onScroll(
e1: MotionEvent,
e2: MotionEvent,
distanceX: Float,
distanceY: Float
): Boolean {
//获取当前实时点信息
val rawX = e2.rawX.toInt()
val rawY = e2.rawY.toInt()
//变化量
dX = rawX - lastX
dY = rawY - lastY
//获取最新的视图位置
var left = left + dX
var right = right + dX
var top = top + dY
var bottom = bottom + dY
//添加限制范围,上下左右不能超出屏幕范围
if (left < 0) {
left = 0
right = left + width
}
if (right > windowWith) {
right = windowWith
left = right - width
}
if (top < 40) {
top = 40
bottom = top + height
}
if (bottom > windowHight) {
bottom = windowHight
top = bottom - height
}
//更新当前视图位置
layout(left, top, right, bottom)
//更新最后屏幕点信息
lastX = rawX
lastY = rawY
return true
}
到此,咱们已经实现了可全屏拖拽的效果了:
现在只差最后一步,通过位置信息判断图标该往哪边贴边,以及移动距离的计算.
由于GestureDetector没有抬起监听,所以逻辑咱们还是得在OnTouchEvent方法中通过监听ACTION_UP的动作进行操作。判断该往哪边贴边很简单,如果最后松开的位置X坐标的超过屏幕一半就往右贴,反之往左。动画咱们还是使用ValueAnimator,因为我们移动也是用布局()方法进行操作.
override fun onTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_UP -> {
val x = event.rawX
val y = event.rawY
//抬起点和最后一次按下点x、y距离大于视图宽的一半才执行
if (abs(x - moveX) > width / 2 || abs(y - moveY) > width / 2) {
val isRight = x > windowWith / 2
//贴边
startAnimator(isRight, windowWith - width, 0)
//隔1.5秒收边
postDelayed({
startAnimator(isRight, windowWith - width * 2 / 3, -width / 3)
}, 1500)
}
return true
}
}
return gestureDetector.onTouchEvent(event)
}
//属性动画执行
private fun startAnimator(isRight: Boolean, rightValue: Int, leftValue: Int) {
ValueAnimator.ofInt(
left,
if (isRight) rightValue else leftValue
).apply {
addUpdateListener { animation ->
val value = animation.animatedValue as Int
//根据监听值不断改变当前视图位置
layout(value, top, value + width, bottom)
}
//插值器 先快后慢
interpolator = AccelerateDecelerateInterpolator()
duration = 600
start()
}
}
这里使用了两次动画,第一次根据计算得出的方向进行贴边平移,隔了1.5秒后再进行隐藏的操作。到此我们的所有功能全部都实现了接下来总结几点:
- 自定义观时尽量选择最接近目标功能的视图进行继承
- 屏幕事件监听除了重写OnTouchEvent进行动作监听的方式还有GestureDetector、ScaleGestureDetector等方式
- 重写了OnTouchEvent方法后需要注意其返回值,如果都返回假的情况该视图的点击事件有可能会被父观或其他设有监听事件控件所消费,导致滑动监听不被触发.
以上便是实现一个全屏拖拽、自动贴边半隐藏的自定义查看的所有内容,希望能给大家带来帮助!
- 程序开发学习排行
-
- 1鸿蒙HarmonyOS:Web组件网页白屏检测
- 2HTTPS协议是安全传输,为啥还要再加密?
- 3HarmonyOS鸿蒙应用开发——数据持久化Preferences
- 4记解决MaterialButton背景颜色与设置值不同
- 5鸿蒙HarmonyOS实战-ArkUI组件(RelativeContainer)
- 6鸿蒙HarmonyOS实战-ArkUI组件(Stack)
- 7[Android][NDK][Cmake]一文搞懂Android项目中的Cmake
- 8Android广播如何解决Sending non-protected broadcast问题
- 9鸿蒙HarmonyOS实战-ArkUI组件(mediaquery)
- 最近发表
-
- WooCommerce最好的WordPress常用插件下载博客插件模块的相关产品
- 羊驼机器人最好的WordPress常用插件下载博客插件模块
- IP信息记录器最好的WordPress常用插件下载博客插件模块
- Linkly for WooCommerce最好的WordPress常用插件下载博客插件模块
- 元素聚合器Forms最好的WordPress常用插件下载博客插件模块
- Promaker Chat 最好的WordPress通用插件下载 博客插件模块
- 自动更新发布日期最好的WordPress常用插件下载博客插件模块
- WordPress官方最好的获取回复WordPress常用插件下载博客插件模块
- Img to rss最好的wordpress常用插件下载博客插件模块
- WPMozo为Elementor最好的WordPress常用插件下载博客插件模块添加精简版