将自定义视图设为互动式

试用 Compose 方式
Jetpack Compose 是推荐在 Android 设备上使用的界面工具包。了解如何在 Compose 中使用布局。

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

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

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

本页将演示如何使用 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;
}

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