绘制界面只是创建自定义视图的一个部分。您还需要 让视图以与 模拟真实世界的动作。
让应用中的对象表现得像真实对象一样。例如, 由于对象 在现实生活中不能这样做而是将图片从一个位置移到 另一个。
用户可以在界面中感受到甚至微妙的行为或感觉,并对 模仿现实世界的细微差别。例如,当用户快滑界面对象时, 让他们在开始时产生一种惯性,使运动延迟末尾 让他们感受到这种动量会将物体超出 快速滑动。
本页将演示如何使用 Android 框架的功能来添加 将这些真实行为添加到您的自定义视图中。
处理输入手势
像许多其他界面框架一样,Android 支持输入事件模型。用户
操作会变成触发回调的事件,并且您可以替换
回调以自定义应用对用户的响应方式。最常见的输入内容
事件是“触摸”,这会触发
onTouchEvent(android.view.MotionEvent)
。
您可以重写此方法来处理事件,如下所示:
Kotlin
override fun onTouchEvent(event: MotionEvent): Boolean { return super.onTouchEvent(event) }
Java
@Override public boolean onTouchEvent(MotionEvent event) { return super.onTouchEvent(event); }
触摸事件本身并不是特别有用。现代触控界面
定义从手势(例如点按、拉、推、
即快速滑动和缩放为了将原始触摸事件转换为手势,Android
提供
GestureDetector
。
通过传入类的实例来构建 GestureDetector
用于实现
GestureDetector.OnGestureListener
。
如果您只想处理几个手势,
GestureDetector.SimpleOnGestureListener
而不是实现 GestureDetector.OnGestureListener
界面。例如,以下代码会创建一个类,用于扩展
GestureDetector.SimpleOnGestureListener
和替换项
onDown(MotionEvent)
。
Kotlin
private val myListener = object : GestureDetector.SimpleOnGestureListener() { override fun onDown(e: MotionEvent): Boolean { return true } } private val detector: GestureDetector = GestureDetector(context, myListener)
Java
class MyListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onDown(MotionEvent e) { return true; } } detector = new GestureDetector(getContext(), new MyListener());
无论您是否使用 GestureDetector.SimpleOnGestureListener
,
始终实施
onDown()
方法,该方法会返回 true
。必须这样做,因为所有手势
以 onDown()
消息开头。如果您退回 false
自onDown()
起,为
GestureDetector.SimpleOnGestureListener
包含的内容,则系统假定
而忽略其余手势,以及
系统不会调用 GestureDetector.OnGestureListener
。仅退货
来自onDown()
的false
(如果您要忽略整个)
手势。
实现 GestureDetector.OnGestureListener
并创建
是 GestureDetector
的实例,则可以使用
GestureDetector
,用于解读您在
onTouchEvent()
。
Kotlin
override fun onTouchEvent(event: MotionEvent): Boolean { return detector.onTouchEvent(event).let { result -> if (!result) { if (event.action == MotionEvent.ACTION_UP) { stopScrolling() true } else false } else true } }
Java
@Override public boolean onTouchEvent(MotionEvent event) { boolean result = detector.onTouchEvent(event); if (!result) { if (event.getAction() == MotionEvent.ACTION_UP) { stopScrolling(); result = true; } } return result; }
当您向 onTouchEvent()
传递其未传递的触摸事件时,
识别为手势的一部分,它会返回 false
。然后,您可以
自定义手势检测代码。
创建物理上合理的动作
手势是控制触摸屏设备的有效方式, 不合常理,也很难记住,除非 结果。
例如,假设您想要实现一个水平快速滑动手势, 设置在围绕其纵轴旋转的视图中绘制的项。此手势 如果界面做出响应是沿快滑方向快速移动,那么这才是合理的。 然后放慢速度,就好像用户推动飞轮转动一样。
关于如何
为滚动操作添加动画效果
手势详细说明了如何实现您自己的 scoll
行为但模拟飞轮的感觉并非易事。丰富的物理学知识
需要数学和数学知识才能使飞轮模型正常工作。幸运的是
Android 提供了辅助类来模拟此行为和其他行为。通过
Scroller
类是处理飞轮式快速滑动手势的基础。
要开始快滑,请调用
fling()
指定起始速度以及最小和最大 x 和 y
即 fling 的值。对于速度值,您可以使用
GestureDetector
。
Kotlin
fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean { scroller.fling( currentX, currentY, (velocityX / SCALE).toInt(), (velocityY / SCALE).toInt(), minX, minY, maxX, maxY ) postInvalidate() return true }
Java
@Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { scroller.fling(currentX, currentY, velocityX / SCALE, velocityY / SCALE, minX, minY, maxX, maxY); postInvalidate(); return true; }
调用 fling()
将设置快滑的物理模型
手势。之后,通过调用Scroller
Scroller.computeScrollOffset()
定期更新。computeScrollOffset()
会更新
通过读取当前时间和 Scroller
对象的内部状态,
使用物理模型计算 x 和 y 位置。
。致电
getCurrX()
和
getCurrY()
检索这些值
大多数视图会传递 Scroller
对象的 x 和 y
直接定位到
scrollTo()
。
此示例略有不同:它使用的是当前的滚动条 x 位置
用于设置视图的旋转角度。
Kotlin
scroller.apply { if (!isFinished) { computeScrollOffset() setItemRotation(currX) } }
Java
if (!scroller.isFinished()) { scroller.computeScrollOffset(); setItemRotation(scroller.getCurrX()); }
Scroller
类会为您计算滚动位置,但
不会自动将这些位置应用到您的视图中。应用新坐标
使滚动动画看起来流畅。您可以通过两种方式
执行此操作:
- 通过调用
postInvalidate()
在调用fling()
之后。此方法要求您 计算滚动偏移onDraw()
并在每次滚动偏移时调用postInvalidate()
更改。 - 设置
ValueAnimator
为快滑持续时间添加动画效果,并添加一个要处理的监听器 通过调用addUpdateListener()
。 通过此方法,您可以为View
。
让转场更顺畅
用户希望现代界面能够在各种状态之间流畅转换:界面元素 即淡入和淡出,而不是出现和消失; 和结束平稳,而不是突然开始和停止。Android 属性动画 框架可以更轻松地实现顺畅过渡。
要使用动画系统,每当属性发生更改时,
视图外观,请勿直接更改属性。而应使用
ValueAnimator
进行更改。在以下示例中,
修改视图中的选定子组件会使整个
视图旋转,使选择指针居中。
ValueAnimator
在数百周期内更改轮替
而不是立即设置新的旋转值。
Kotlin
autoCenterAnimator = ObjectAnimator.ofInt(this, "Rotation", 0).apply { setIntValues(targetAngle) duration = AUTOCENTER_ANIM_DURATION start() }
Java
autoCenterAnimator = ObjectAnimator.ofInt(this, "Rotation", 0); autoCenterAnimator.setIntValues(targetAngle); autoCenterAnimator.setDuration(AUTOCENTER_ANIM_DURATION); autoCenterAnimator.start();
如果您要更改的值是某个基本 View
值
因为视图具有内置的
ViewPropertyAnimator
针对同时播放多个属性的动画进行了优化,如
示例:
Kotlin
animate() .rotation(targetAngle) .duration = ANIM_DURATION .start()
Java
animate().rotation(targetAngle).setDuration(ANIM_DURATION).start();