Android进阶练习-自定义视图(3)
2013-03-24 23:35
351 查看
使视图可交互
绘制UI界面只是创建自定义视图中的一部分工作,你还应该去响应用户的输入,并且让这种响应更贴近现实生活,比如现实世界中的一些物理现象,一些人们的行为习惯等等,处理输入手势
像其他的UI框架一样,Android也提供了一个输入事件模型。用户的触摸动作被转化为了一些事件,并且Android会进行事件回调,你可以通过覆写回调方法来处理用户的触屏事件,响应用户进行交互。像触屏事件会回调 onTouchEvent(android.view.MotionEvent) 方法,你只需要覆写它来处理该事件@Override public boolean onTouchEvent(MotionEvent event) { return super.onTouchEvent(event); }
触摸事件本身并不是特别的重要,现代触摸用户界面定义了以手势为主的交互动作,像轻敲、拉、推、抛和放大缩小手势,为了将原始触摸事件转化为手势,Android提供了GestureDetector
类。构建GestureDetector 时需要传递一个实现了
GestureDetector.OnGestureListener
接口的类的实例,如果你不想处理所有的手势,你可以通过继承
GestureDetector.SimpleOnGestureListener类来代替实现
GestureDetector.OnGestureListener
接口
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()方法开始的,如果你从onDown()方法返回false ,那么Android系统会认为你想忽略手势识别剩余的操作,并且
GestureDetector.SimpleOnGestureListener方法将得不到调用,当你确实想忽略整个手势时你可以返回false 。一旦你实现了
GestureDetector.OnGestureListener接口并且创建出来了一个实例,那么你就可以使用你的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 类是处理flywheel-style 抛手势最基本的一个类
调用
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帮我们计算的速率值很准确,但许多的开发者感觉这个速率会让抛动画看起来很快,所以一般来说会把这个速率值缩小4到8倍
调用fling()
方法只是为抛手势建立起了一个物理模型,然后,我们应该每隔一个常规合理的时间来调用Scroller.computeScrollOffset()
更新
Scroller,
computeScrollOffset()方法更新
Scroller对象的内部状态借助于在当前的时间去渲染它和使用物理模型去计算x轴和y轴的坐标,我们可以调用
getCurrX()和getCurrY() 来获取这些值
if (!mScroller.isFinished()) { mScroller.computeScrollOffset(); setPieRotation(mScroller.getCurrY());
}
Scroller为你计算出滚动的位置,但是它并不会自动的把这些位置信息应用到你的视图上,获得和应用新的坐标信息能够让你的滑动看起来顺畅平滑,但这项工作需要你手动来做,有两种方式来做到这点:
1、在调用fling() 后调用postInvalidate() 方法,这样可以迫使视图重绘,这项技术需要你在
onDraw()方法中计算好滚动的偏移量和滚动偏移量每次改变后都要调用
postInvalidate()方法
2、为抛手势设置一个ValueAnimator 播放动画一直到手势结束,并且增加一个监听器,在监听器中调用
addUpdateListener()
来处理滚动动画
提供的例子中使用的是第二种方法,这项技术稍微复杂点,但是它看起来更贴近Android中的动画系统并且不要求潜在的不需要的无效视图,
ValueAnimator在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();
}
}
});
让你的视图中的动画平滑的播放
用户期待一个更现代的UI,在不同的状态间转换平滑。UI元素的淡入淡出,让用户动作的开始和结束过渡的尽量平滑,在Android3.0以上版本,可以很简单的做到这些。使用Android的动画系统,即使是一个属性的改变也会影响到视图的显示效果,不要直接的去改变属性。可以使用
ValueAnimator来代替这种改变
mAutoCenterAnimator = ObjectAnimator.ofInt(PieChart.this, "PieRotation", 0); mAutoCenterAnimator.setIntValues(targetAngle); mAutoCenterAnimator.setDuration(AUTOCENTER_ANIM_DURATION); mAutoCenterAnimator.start();
如果你想改变的是视图基础属性的值,制作动画就更简单了,因为视图提供了一个内置的ViewPropertyAnimator 类
,并且这个类同时优化了动画的多个属性
animate().rotation(targetAngle).setDuration(ANIM_DURATION).start();
相关文章推荐
- Android进阶练习-自定义视图(2)
- Android进阶练习-自定义视图实战之刷新等待进度条
- Android进阶练习-自定义视图(1)
- Android中自定义视图View之---进阶篇(Canvas的使用)
- Android自定义组件系列【5】——进阶实践(1)
- (转)android UI进阶之自定义组合控件
- Android 高手进阶之自定义View,自定义属性(带进度的圆形进度条)
- Android 高手进阶之自定义View,自定义属性(带进度的圆形进度条)
- Android中级进阶三 自定义Android标题栏
- Android进阶之自定义view(四)
- Android中自定义视图View之---前奏篇
- android进阶之自定义view(文字圆形边框)
- ANDROID自定义视图——onMeasure,MeasureSpec源码 流程 思路详解
- android构建自定义的视图组件
- Android学习系列(3)--App自动更新之自定义进度视图和内部存储
- android自定义视图之扇形标签栏
- 创建Material Design风格Android应用--自定义阴影和裁剪视图
- android自定义视图属性学习
- Android 自定义View进阶