将自定义视图设为互动式

试用 Compose 方式
Jetpack Compose 是推荐在 Android 设备上使用的界面工具包。了解如何在 Compose 中使用布局。
<ph type="x-smartling-placeholder"></ph> 手势 →

绘制界面只是创建自定义视图的一个部分。您还需要 让视图以与 模拟真实世界的动作。

让应用中的对象表现得像真实对象一样。例如, 由于对象 在现实生活中不能这样做而是将图片从一个位置移到 另一个。

用户可以在界面中感受到甚至微妙的行为或感觉,并对 模仿现实世界的细微差别。例如,当用户快滑界面对象时, 让他们在开始时产生一种惯性,使运动延迟末尾 让他们感受到这种动量会将物体超出 快速滑动。

本页将演示如何使用 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() 消息开头。如果您退回 falseonDown()起,为 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() 指定起始速度以及最小和最大 xy 即 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;
}
<ph type="x-smartling-placeholder">

调用 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();