Android自定义控件学习(六)-------使视图互动

使视图互动

绘制用户界面只是创建自定义视图的一部分。您还需要使您的视图以与您模拟的真实世界动作非常相似的方式响应用户输入。对象应始终以与真实对象相同的方式进行操作。例如,图像不应该立即跳出存在,并在其他地方重新出现,因为现实世界中的物体不会这样做。相反,图像应该从一个地方移动到另一个地方。

用户还会感觉到界面中的微妙行为或感觉,并对模仿真实世界的微妙事物做出最佳反应。例如,当用户投掷UI对象时,他们应该在开始时感觉到摩擦,从而延迟运动,然后在最后感觉到运动超出投掷的动量。

本课程演示如何使用Android框架的功能将这些现实世界的行为添加到自定义视图中。

处理输入手势

和许多其他UI框架一样,Android支持输入事件模型。用户操作转换为触发回调的事件,您可以覆盖回调来自定义应用程序对用户的响应方式。Android系统中最常见的输入事件是触摸,触发onTouchEvent(android.view.MotionEvent)。重写此方法来处理事件:

 @Override
   public boolean onTouchEvent(MotionEvent event) {
    return super.onTouchEvent(event);
   }

触摸事件本身并不是特别有用。现代触摸UI定义了手势方面的交互,例如点击,拉动,推动,抛掷和缩放。为了将原始触摸事件转换为手势,Android提供了GestureDetector。
GestureDetector通过传入一个实现的类的实例来构造一个GestureDetector.OnGestureListener。如果您只想处理几个手势,则可以扩展GestureDetector.SimpleOnGestureListener而不是实现GestureDetector.OnGestureListener 接口。例如,这段代码创建了一个扩展GestureDetector.SimpleOnGestureListener和覆盖的类onDown(MotionEvent)。

class mListener extends GestureDetector.SimpleOnGestureListener {
   @Override
   public boolean onDown(MotionEvent e) {
       return true;
   }
}
mDetector = new GestureDetector(PieChart.this.getContext(), new mListener());

无论您是否使用GestureDetector.SimpleOnGestureListener,您都必须执行onDown()返回的 方法true。这一步是必要的,因为所有手势都以onDown()消息开头 。如果返回false的onDown(),因为 GestureDetector.SimpleOnGestureListener确实,系统会假设你要忽略手势的其余部分,以及其他方法 GestureDetector.OnGestureListener永远不会被调用。您应该返回唯一的一次false由onDown() 是,如果你真的想忽略的整个姿态。一旦你实现GestureDetector.OnGestureListener 并创建了一个实例GestureDetector,你可以使用你GestureDetector的解释你接收到的触摸事件onTouchEvent()。

@Override
public boolean onTouchEvent(MotionEvent event) {
   boolean result = mDetector.onTouchEvent(event);
   if (!result) {
       if (event.getAction() == MotionEvent.ACTION_UP) {
           stopScrolling();
           result = true;
       }
   }
   return result;
}

当您传递onTouchEvent()一个触摸事件时,它不会将其识别为手势的一部分,它会返回false。然后您可以运行自己的自定义手势检测代

创造物理上合理的运动

手势是控制触摸屏设备的强大方式,但除非它们产生物理上合理的结果,否则它们可能是违反直觉的,难以记忆。这方面的一个很好的例子就是挥动手势,用户在屏幕上快速移动手指然后举起手指。如果用户界面通过在投掷方向上快速移动来响应,则该姿势是有意义的,然后放慢,就好像用户已经推动飞轮并将其设置为旋转。但是,模拟飞轮的感觉并不是微不足道的。要使飞轮模型正常工作,需要大量的物理和数学知识。幸运的是,Android提供了辅助类来模拟这个和其他行为。该Scroller班级是处理飞轮式抛动手势的基础。要开始投掷,请fling()用起始速度和投掷的最小和最大x和y值进行调用。对于速度值,您可以使用为您计算的值GestureDetector。

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
   mScroller.fling(currentX, currentY, velocityX / SCALE, velocityY / SCALE, minX, minY, maxX, maxY);
   postInvalidate();
}

注意:虽然计算的速度 GestureDetector在物理上是准确的,但许多开发人员认为使用此值会使得动画动画速度过快。通常将x和y的速度除以4到8的因子。
这个呼吁fling()建立了手势的物理模型。之后,您需要定期Scroller拨打电话进行更新Scroller.computeScrollOffset()。通过读取当前时间并使用物理模型计算当时的x和y位置来computeScrollOffset()更新Scroller对象的内部状态。调用getCurrX()并getCurrY()检索这些值。
大多数视图直接传递Scroller对象的x和y位置 scrollTo()。PieChart示例稍有不同:它使用当前的滚动y位置来设置图表的旋转角度。

if (!mScroller.isFinished()) {
    mScroller.computeScrollOffset();
    setPieRotation(mScroller.getCurrY());
}

该Scroller级计算滚动位置给你,但它不会自动应用这些位置你的看法。确保您经常获得并应用新坐标以使滚动动画看起来平滑是您的责任。有两种方法可以做到这一点:

调用postInvalidate()后调用 fling(),以强制重绘。这种技术要求您计算滚动偏移量onDraw() 并在postInvalidate()每次滚动偏移量更改时调用。
设置一个ValueAnimator动画的持续时间,并添加一个侦听器来处理动画更新通过调用addUpdateListener()。
PieChart示例使用第二种方法。这种技术的设置稍微复杂一些,但它与动画系统的关系更密切,不需要潜在的不必要的视图无效。缺点是ValueAnimator 在API级别11之前不可用,所以此技术不能用于运行Android版本低于3.0的设备。

注意:您可以ValueAnimator在针对较低API级别的应用程序中使用。您只需确保在运行时检查当前API级别,并在当前级别小于11时省略对视图动画系统的调用。

mScroller = new Scroller(getContext(), null, true);
       mScrollAnimator = ValueAnimator.ofFloat(0,1);
       mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
           @Override
           public void onAnimationUpdate(ValueAnimator valueAnimator) {
               if (!mScroller.isFinished()) {
                   mScroller.computeScrollOffset();
                   setPieRotation(mScroller.getCurrY());
               } else {
                   mScrollAnimator.cancel();
                   onScrollFinished();
               }
           }
       });

让你的转换顺利

用户期望现代用户界面能够在状态之间平滑过渡。UI元素淡入淡出而不是出现和消失。动作顺利开始和结束,而不是突然开始和停止。Android 3.0中引入的Android 属性动画框架使平滑过渡变得简单。

要使用动画系统,只要属性发生变化而影响视图外观,请不要直接更改属性。相反,使用ValueAnimator来进行更改。在以下示例中,修改PieChart中当前选定的饼图切片会导致整个图表旋转,以便选择指针位于所选切片的中心。ValueAnimator改变几百毫秒周期的旋转,而不是立即设置新的旋转值。

mAutoCenterAnimator = ObjectAnimator.ofInt(PieChart.this, "PieRotation", 0);
mAutoCenterAnimator.setIntValues(targetAngle);
mAutoCenterAnimator.setDuration(AUTOCENTER_ANIM_DURATION);
mAutoCenterAnimator.start();

如果要更改的值是基本View属性之一,则动画更容易,因为Views具有内置功能,ViewPropertyAnimator该功能已针对多个属性的同时动画进行了优化。例如:

animate().rotation(targetAngle).setDuration(ANIM_DURATION).start();
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值