Android自定义View教程(三)

创建view的交互性

绘制UI只是创建自定义view的一部分。你也需要让你的view对用户的输入做出反馈。对象需要像真实的事物一样作出反应。举个例子,图片不能再某个地方突然就弹出来,因为在真实的世界中,对象不是那么做的。相对地,图片需要从一个地方移动到另一个地方。

UI应该能够感知到细微地行为方式,并且模仿出真实世界中的最佳反馈方式。举个例子,当用户快速滑动UI对象的时候,他们在最开始的时候应该感知到有一种摩擦力使动作延迟了,最后感知到有一股惯性动量将这个动作滑动起来。

这篇教程将会展示如何使用Android的框架特性去添加一个真实世界的行为去到你的自定义View当中。

处理输入手势

和很多其他的UI框架一样,Android提供了一个输入事件模型。用户的动作都将会被转化为一个事件触发回调,并且你就可以覆写这些回调来自定义你的应用如何来反馈对象。在Android系统中最常见的输入事件就是touch,这将会触发onTouchEvent(android.view.MotionEvent)。覆写这个方法来处理事件:

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

触摸事件本身来说不是十分有用的。现代的触摸UI交互称之为手势。比如说:tapping, pulling, pushing, flinging, and zooming,为了将这些未处理过的触摸事件进行转化,使之成为手势,Android提供了GestureDetector这个类。

在一个实例类中构造一个GestureDetector,可以实现以下:

GestureDetector.OnGestureListener 假如你只想处理一小部分手势,你可以继承这个
来替代实现
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(MotionEvent)方法,并且在方法中返回true。这一步骤是必须的,所有的手势都是以onDown(MotionEvent)开始的。假如你返回了false,就如在GestureDetector.OnGestureListener中那样,那么系统就假定你想要忽略剩下的所有手势,那么GestureDetector.OnGestureListener中的其他方法都永远都不会调用。只有一种情况你应该返回返回false,那就是你真的是想忽略整个手势的。一旦你实现了GestureDetector.OnGestureListener,并且创建了GestureDetector的实例,你就能在onTouchEvent()中使用GestureDetector来声明触摸事件。

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

当一个触摸事件被传递到onTouchEvevnt()中时,它并没有意识到自己是手势的一部分,所以它返回了false。现在,你能够运行你自己的自定义手势代码了。

创建仿真动作

手势是一个用来控制触摸屏设备的强大方法,但是他们可能会违反直觉感知,并且很难被记住。除非他们产出一个仿真结果。一个很好的例子是fling手势,这是用来描述用户在屏幕上快速移动手指,然后离开屏幕。这个手势意味着UI反馈是否能快速地在fling的方向上移动,然后速度慢慢下降,就好像用户推动一个飞轮,然后使它旋转。

然而,模拟出一种飞轮的感觉并不简单。需要很多的物理以及数学知识来使飞轮模型正确工作。幸运的是,Android提供了辅助类来模拟这个和其他的行为。Scroll类是处理飞轮类型fling的基类。

开始进行fling,调用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计算出来的是很精确的,很多开发者会感觉到使用这个值会使fling动画过快了。一般而言,我们都将X,Y方向的速度分开,速度为4-8。

调用fling()方法给fling手势设置了物理模型,在这之后,你需要更新Scroller,这时候在一个常规间隔内调用方法:Scroller.computeScrollOffset()Scroller.computeScrollOffset()更新了Scroller对部状态,更新的原理为读取当前时间,并且使用物理模型来计算出x,y方向上的位置。调用getCurrX()以及 getCurrY()来检索这些值。

大多数的View直接在X,Y位置上执行ScrollerscrollTo()方法。然而,PieChart 这个例子有些不同,它使用了当前滚动Y位置来设定旋转角。

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

Scroller这个类为你计算滚动的位置,但是它并不自动地将其这些位置应用你的views中去。确保你能得到并且应用这些新坐标,然后让滑动看起来尽可能地顺滑,这就是开发者的责任了。以下有两个方法可以做到这样:

  • 在调用了fling()方法后调用postInvalidate()方法,这是为了强制重绘。这种技术需要你在onDraw()中计算出滚动的偏移量,然后在每次偏移量改变的时候调用postInvalidate()
  • 设置属性动画让fling在一段时间内动画过渡,然后添加监听器来执行动画的更新。在这里使用到了addUpdateListener()

PieChart 这个例子使用了第二种方法。这种技术稍微有些复杂,但是它与动画系统结合得更加紧密,并且不需要可能不是必须的view。缺点是属性动画在API 11以下是不能够使用的,因此这项技术不能在运行Android3.0以下的设备中使用。

需要注意的是:属性动画不能在API 11以下使用,但是你依然可以在低于此版本的应用中使用,你只需要保证检查在当前的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能够在状态转化期间更加顺滑。UI元素在进和出的时候淡出,而不出突然出现,突然消失。动作顺滑地开始,结束,而不是突然地开始,停止。Android动画框架,包含Android 3.0 ,在这一方面能很简单实现。

在任何性质改变影响到你的view的外观的时候,使用动画系统,不要立即就改变内容,而是使用属性动画来改变。在接下来的例子中,使用了动画:

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

假如你想改变的是view的某一个基类属性值,使用动画会更加简单,因为这些views都有有内建的属性动画。举个例子:

animate().rotation(targetAngle).setDuration(ANIM_DURATION).start()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值