您的位置:首页 > 移动开发 > Android开发

android自定义view之(三) Making the View Interactive

2015-06-15 15:42 791 查看
Drawing a UI is only one part of creating a custom view. You also need to make your view respond to user input in a way that closely resembles the real-world action you’re mimicking. Objects should always act in the same way that real objects do. For example, images should not immediately pop out of existence and reappear somewhere else, because objects in the real world don’t do that. Instead, images should move from one place to another.

绘制UI只是自定义view的一部分,你还需要让你的view用某种方式响应用户输入就像你在模仿真实动作。

对象要想真正的对象在动一样,比如,图片不能立即弹出,然后再某处重复出现,因为现实中对象不会那么做。

Users also sense subtle behavior or feel in an interface, and react best to subtleties that mimic the real world. For example, when users fling a UI object, they should sense friction at the beginning that delays the motion, and then at the end sense momentum that carries the motion beyond the fling.

用户也感觉微妙的表现或者感受一个界面,并对模仿现实世界的细微之处反应强烈。

例如,当用户fling(迅速滑动)一个对象时,应该在开始时感到摩擦带来的阻力,在结束时感到fling带动的动力。应该在滑动开始与结束的时候给用户一定的反馈。

This lesson demonstrates how to use features of the Android framework to add these real-world behaviors to your custom view.

这节课描述使用android 框架的这些特性添加这些真实表现到你的自定义view中。

Handle Input Gestures 处理手势输入

Like many other UI frameworks, Android supports an input event model. User actions are turned into events that trigger callbacks, and you can override the callbacks to customize how your application responds to the user. The most common input event in the Android system is touch, which triggers onTouchEvent(android.view.MotionEvent). Override this method to handle the event:

像其他一些UI框架一样,Android支持 一个用户输入事件模型。用户的动作变成事件,触发了回调。你可以重写回调方法自定义你的程序如何响应用户。 android系统中最常用的输入事件是touch事件,触发了

onTouchEvent(android.view.MotionEvent) 方法,重写这个方法处理事件:

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


Touch events by themselves are not particularly useful. Modern touch UIs define interactions in terms of gestures such as tapping, pulling, pushing, flinging, and zooming. To convert raw touch events into gestures, Android provides GestureDetector.

Touch事件本身没有特别的用处。想在的touch UI根据手势比如 tapping,pulling,pushing,flinging,zooming定义了交互。为了把原生的touch事件转换成gestures,android提供了 GestureDetector。

Construct a )GestureDetector by passing in an instance of a class that implements GestureDetector.OnGestureListener. If you only want to process a few gestures, you can extend GestureDetector.SimpleOnGestureListener instead of implementing the GestureDetector.OnGestureListener interface. For instance, this code creates a class that extends GestureDetector.SimpleOnGestureListener and overrides onDown(MotionEvent).

通过传入GestureDetector.OnGestureListener的一个实例构建一个GestureDetector。如果你只是想要处理几种gestures(手势操作)你可以继承GestureDetector.SimpleOnGestureListener,而不用实现GestureDetector.OnGestureListener接口。例如,下面的代码创建一个继承GestureDetector.SimpleOnGestureListener的类,并重写onDown(MotionEvent))。

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


Whether or not you use GestureDetector.SimpleOnGestureListener, you must always implement an onDown() method that returns true. This step is necessary because all gestures begin with an onDown() message. If you return false from onDown(), as GestureDetector.SimpleOnGestureListener does, the system assumes that you want to ignore the rest of the gesture, and the other methods of GestureDetector.OnGestureListener never get called. The only time you should return false from onDown() is if you truly want to ignore an entire gesture. Once you’ve implemented GestureDetector.OnGestureListener and created an instance of GestureDetector, you can use your GestureDetector to interpret the touch events you receive in onTouchEvent().

不管你是否使用GestureDetector.SimpleOnGestureListener, 你必须总是实现onDown()方法,并返回true。这一步是必须的,因为所有的gestures都是从onDown()开始的。如果你在onDown()里面返回false,系统会认为你想要忽略后续的gesture,那么GestureDetector.OnGestureListener的其他回调方法就不会被执行到了。一旦你实现了GestureDetector.OnGestureListener并且创建了GestureDetector的实例, 你可以使用你的GestureDetector来中止你在onTouchEvent里面收到的touch事件。

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


When you pass onTouchEvent() a touch event that it doesn’t recognize as part of a gesture, it returns false. You can then run your own custom gesture-detection code.

当你传递一个touch事件到onTouchEvent()时,若这个事件没有被辨认出是何种gesture,它会返回false。你可以执行自定义的gesture-decection代码。

Create Physically Plausible Motion 创建基本合理的物理运动

Gestures are a powerful way to control touchscreen devices, but they can be counterintuitive and difficult to remember unless they produce physically plausible results. A good example of this is the fling gesture, where the user quickly moves a finger across the screen and then lifts it. This gesture makes sense if the UI responds by moving quickly in the direction of the fling, then slowing down, as if the user had pushed on a flywheel and set it spinning.

Gestures是控制触摸设备的一种强有力的方式,但是除非你能够产出一个合理的触摸反馈,否则将是违反用户直觉的。一个很好的例子是fling手势,用户迅速的在屏幕上移动手指然后抬手离开屏幕。这个手势应该使得UI迅速的按照fling的方向进行滑动,然后慢慢停下来,就像是用户旋转一个飞轮一样。

However, simulating the feel of a flywheel isn’t trivial. A lot of physics and math are required to get a flywheel model working correctly. Fortunately, Android provides helper classes to simulate this and other behaviors. The Scroller class is the basis for handling flywheel-style fling gestures.

To start a fling, call fling() with the starting velocity and the minimum and maximum x and y values of the fling. For the velocity value, you can use the value computed for you by GestureDetector.

但是模拟这个飞轮的感觉并不简单,要想得到正确的飞轮模型,需要大量的物理,数学知识。幸运的是,Android有提供帮助类来模拟这些物理行为。Scroller是控制飞轮式的fling的基类。

要启动一个fling,需调用fling(),并传入启动速率、x、y的最小值和最大值,对于启动速度值,可以使用GestureDetector计算得出。

[code]@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();
}


Note: Although the velocity calculated by GestureDetector is physically accurate, many developers feel that using this value makes the fling animation too fast. It’s common to divide the x and y velocity by a factor of 4 to 8.

Note: 尽管速率是通过GestureDetector来计算的,许多开发者感觉使用这个值使得fling动画太快。通常把x与y设置为4到8倍的关系。

The call to fling() sets up the physics model for the fling gesture. Afterwards, you need to update the Scroller by calling Scroller.computeScrollOffset() at regular intervals. computeScrollOffset() updates the Scroller object’s internal state by reading the current time and using the physics model to calculate the x and y position at that time. Call getCurrX() and getCurrY() to retrieve these values.

Most views pass the Scroller object’s x and y position directly to scrollTo(). The PieChart example is a little different: it uses the current scroll y position to set the rotational angle of the chart.

调用fling())时会为fling手势设置物理模型。然后,通过调用定期调用 Scroller.computeScrollOffset())来更新Scroller。computeScrollOffset())通过读取当前时间和使用物理模型来计算x和y的位置更新Scroller对象的内部状态。调用getCurrX())和getCurrY())来获取这些值。

大多数view通过Scroller对象的x,y的位置直接到scrollTo()),PieChart例子稍有不同,它使用当前滚动y的位置设置图表的旋转角度。

[code]if (!mScroller.isFinished()) {
    mScroller.computeScrollOffset();
    setPieRotation(mScroller.getCurrY());
}
``
The Scroller class computes scroll positions for you, but it does not automatically apply those positions to your view. It's your responsibility to make sure you get and apply new coordinates often enough to make the scrolling animation look smooth. There are two ways to do this:
Scroller 类会为你计算滚动位置,但是他不会自动把哪些位置运用到你的view上面。你有责任确保View获取并运用到新的坐标。你有两种方法来实现这件事情:`
1. Call postInvalidate() after calling fling(), in order to force a redraw. This technique requires that you compute scroll offsets in onDraw() and call postInvalidate() every time the scroll offset changes.
2. Set up a ValueAnimator to animate for the duration of the fling, and add a listener to process animation updates by calling addUpdateListener().
1. 在调用fling()之后执行postInvalidate(), 这是为了确保能强制进行重画。这个技术需要每次在onDraw里面计算过scroll offsets(滚动偏移量)之后调用postInvalidate()。
2. 使用ValueAnimator在fling是展现动画,并且通过调用addUpdateListener()增加对fling过程的监听。
The PieChart example uses the second approach. This technique is slightly more complex to set up, but it works more closely with the animation system and doesn't require potentially unnecessary view invalidation. The drawback is that ValueAnimator is not available prior to API level 11, so this technique cannot be used on devices running Android versions lower than 3.0.

Note: ValueAnimator isn't available prior to API level 11, but you can still use it in applications that target lower API levels. You just need to make sure to check the current API level at runtime, and omit the calls to the view animation system if the current level is less than 11.
这个PieChart 的例子使用了第二种方法。这个方法使用起来会稍微复杂一点,但是它更有效率并且避免了不必要的重画的view进行重绘。缺点是ValueAnimator是从API Level 11才有的。因此他不能运用到3.0的系统之前的版本上。

Note: ValueAnimator虽然是API 11才有的,但是你还是可以在最低版本低于3.0的系统上使用它,做法是在运行时判断当前的API Level,如果低于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();

}

}

});

[code]##Make Your Transitions Smooth 使过渡平滑
Users expect a modern UI to transition smoothly between states. UI elements fade in and out instead of appearing and disappearing. Motions begin and end smoothly instead of starting and stopping abruptly. The Android property animation framework, introduced in Android 3.0, makes smooth transitions easy.

To use the animation system, whenever a property changes that will affect your view's appearance, do not change the property directly. Instead, use ValueAnimator to make the change. In the following example, modifying the currently selected pie slice in PieChart causes the entire chart to rotate so that the selection pointer is centered in the selected slice. ValueAnimator changes the rotation over a period of several hundred milliseconds, rather than immediately setting the new rotation value.
用户期待一个UI之间的切换是能够平滑过渡的。UI元素需要做到渐入淡出来取代突然出现与消失。Android从3.0开始有提供property animation framework,用来使得平滑过渡变得更加容易。

使用这套动画系统时,任何时候属性的改变都会影响到你的视图,所以不要直接改变属性的值。而是使用ValueAnimator来实现改变。在下面的例子中,在PieChart 中更改选择的部分将导致整个图表的旋转,以至选择的进入选择区内。ValueAnimator在数百毫秒内改变旋转量,而不是突然地设置新的旋转值。


mAutoCenterAnimator = ObjectAnimator.ofInt(PieChart.this, “PieRotation”, 0);

mAutoCenterAnimator.setIntValues(targetAngle);

mAutoCenterAnimator.setDuration(AUTOCENTER_ANIM_DURATION);

mAutoCenterAnimator.start();

“`

If the value you want to change is one of the base View properties, doing the animation is even easier, because Views have a built-in ViewPropertyAnimator that is optimized for simultaneous animation of multiple properties. For example:

如果你想改变的是view的某些基础属性,你可以使用ViewPropertyAnimator ,它能够同时执行多个属性的动画。

animate().rotation(targetAngle).setDuration(ANIM_DURATION).start();
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: