Android官方开发文档Training系列课程中文版:创建自定义View之View的交互

简介: 写在前面的话:这一章很有价值,想要提升安卓知识的一定要读一读。不做安卓的也可以得到其它方面的提升。原文地址:http://android.xsoftlab.net/training/custom-views/making-interactive.htmlUI的绘制只是自定义View的一部分。

写在前面的话:这一章很有价值,想要提升安卓知识的一定要读一读。不做安卓的也可以得到其它方面的提升。

原文地址:http://android.xsoftlab.net/training/custom-views/making-interactive.html

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定义了一些交互手势,比如双击、下拉、上推、快速滑动以及缩放等等。为了将原始触摸事件转换为手势,Android提供了GestureDetector

构造GestureDetector需要传递一个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接口,你都需要实现一个返回true的onDown()方法。这一步是必须的,因为所有的手势都是从onDown()方法开始的。如果你在onDown()方法中返回了false,那么系统会认为你想忽略这次事件,并且其它的相关方法都不会被调用。如果你真的想要忽略整个手势事件,那么在onDown()方法中返回false是唯一的一种方式。一旦实现了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,这样你就可以运行自定义的手势识别代码了。

创建物理模拟手势

手势是用来控制触摸屏设备的一种强大方式,除非它们提供了物理模拟效果,否则它们可能是违反直觉的、难以记住的。一个好的示例就是飞速滑动手势:当用户快速的在屏幕上滑动手指时,手指突然离开了屏幕,就会触发这种手势。如果UI在同一方向上继续滑动然后慢慢的减速,这时就会给用户造成一种感觉:仿佛在操作一个飞轮一样。

不管怎样,模拟飞轮这种感觉并不是没有价值的。为了正确模拟这种感觉,需要很多的物理及数学运算。幸运的是,Android为此提供了辅助类。Scroller是一个专门用来处理这种飞轮感觉手势的辅助类。

为了启动滑动,需要以一个初始速度值及其它相关速度参数调用fling()。有关速度值,你可以通过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();
}

Note: 尽管GestureDetector计算到的这个速度值在物理上很精确,但是很多开发者感觉使用这个值来启动滑动还是太快了。通常会在4到8之间取一个系数来减小x和y。

先调用fling()为滑动手势设置物理模型。然后你需要定期调用Scroller.computeScrollOffset()来更新ScrollercomputeScrollOffset()通过读取当前的时间以及使用物理模型来计算x及y的位置来更新Scroller对象的内部状态。通过调用getCurrX()getCurrY()来接收这些值。

很多View将Scroller对象的x,y的位置值直接传递给scrollTo()。饼图示例在这里有些小小的不同:它使用当前滑动的y的位置来设置饼图的旋转角度:

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

Scroller会为你计算滑动的位置,但是它不会自动的将这些值应用到你的View中。为了使View的滑动效果更佳平滑,获得并应用这些值是需要你去做的。有两种方式可以实现:

在饼图示例中使用了第二种方案。这项技术在设置上稍微的有些复杂,但是它的工作过程与动画系统更为接近,并且不会请求不必要的更新。它的缺点是在API 11之前ValueAnimator并不适用,所以这项技术在Android 3.0之前不可以使用。

Note: ValueAnimator在API 11之前并不可用,但是你仍然还可以在API 11之前使用。你只需要确保在运行时检查当前的API等级,并且在等级低于11时不调用View动画就可以。

       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中出现的property animation framework使平滑转场更加简便。

每次属性的变更都会影响View的外观,所以不要直接更改它们的属性。相反,可以使用ValueAnimator来做出变更。在下面的示例中,修改当前所选择的扇形图会使整个饼图发生旋转,所以选择的这个点在饼图中看起来是居正中的。ValueAnimator更改旋转用了数百毫秒的时间。

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

如果你想更改View的基础属性,那么这项事情就更容易了,因为View有一个内置的View属性动画框架ViewPropertyAnimator,它专门用来同时作用多个属性,比如:

animate().rotation(targetAngle).setDuration(ANIM_DURATION).start();
目录
相关文章
|
3月前
|
安全 API Android开发
Android网络和数据交互: 解释Retrofit库的作用。
Android网络和数据交互: 解释Retrofit库的作用。
39 0
|
3月前
|
Android开发 容器
Android UI设计: 什么是View和ViewGroup?
Android UI设计: 什么是View和ViewGroup?
36 0
|
4月前
|
XML API Android开发
Android 自定义View 之 圆环进度条
Android 自定义View 之 圆环进度条
|
10天前
|
Android开发 开发者
Android网络和数据交互: 请解释Android中的AsyncTask的作用。
Android's AsyncTask simplifies asynchronous tasks for brief background work, bridging UI and worker threads. It involves execute() for starting tasks, doInBackground() for background execution, publishProgress() for progress updates, and onPostExecute() for returning results to the main thread.
10 0
|
10天前
|
网络协议 安全 API
Android网络和数据交互: 什么是HTTP和HTTPS?在Android中如何进行网络请求?
HTTP和HTTPS是网络数据传输协议,HTTP基于TCP/IP,简单快速,HTTPS则是加密的HTTP,确保数据安全。在Android中,过去常用HttpURLConnection和HttpClient,但HttpClient自Android 6.0起被移除。现在推荐使用支持TLS、流式上传下载、超时配置等特性的HttpsURLConnection进行网络请求。
10 0
|
1月前
|
移动开发 JavaScript Android开发
Android与Html5交互
Android与Html5交互
|
2月前
|
XML Android开发 数据格式
安卓和webview交互
安卓和webview交互
25 0
|
3月前
|
JSON Java Android开发
Android网络和数据交互: 请解释Android中的JSON解析库,如Gson。
Android网络和数据交互: 请解释Android中的JSON解析库,如Gson。
24 0
|
3月前
|
存储 前端开发 测试技术
Android 官方架构中的 UseCase 该怎么写?
Android 官方架构中的 UseCase 该怎么写?
66 0
|
4月前
|
XML API Android开发
Android 自定义View 之 Dialog弹窗
Android 自定义View 之 Dialog弹窗