Android、View视图与坐标系
View的滑动和属性动画
从源码解析View的事件分发机制
View的工作流程
Android自定义view
View的滑动和属性动画
View的滑动
View的滑动是Android实现自定义控件的基础,同时在开发中我们也难免会遇到View的滑动处理。其实不管是哪种滑动方式,其基本思想都是类似的:当点击事件传到View时,系统记下触摸点的坐标,手指移动时系统记下移动后触摸的坐标并算出偏移量,并通过偏移量来修改View的坐标。实现View滑动有很多种方法,在这里主要讲解6种滑动方法,分别是layout()、offsetLeftAndRight()与offsetTopAndBottom()、LayoutParams、动画、scollTo 与 scollBy,以及Scroller。
layout()方法
View进行绘制的时候会调用onLayout()方法来设置显示的位置,因此我们同样也可以通过修改View的left、top、right、bottom这4种属性来控制View的坐标。首先我们要自定义一个View,在onTouchEvent()方法中获取触摸点的坐标,代码如下所示:
public boolean onTouchEvent(MotionEvent event) {
//获取手指触摸点的横坐标和纵坐标
int x =(int) event.getX();
int y =(int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
//计算移动的距离
int offsetX = x - lastX;
int offsetY = y - lastY;
//调用layout方法来重新放置它的位置
layout(getLeft() + offsetX, getTop() + offsetY,
getRight() + offsetX, getBottom() + offsetY);
break;
...
offsetLeftAndRight() 与 offsetTopAndBottom()
这两种方法和layout()方法的效果差不多,其使用方式也差不多。我们将ACTION_MOVE中的代码替换成如下代码:
case MotionEvent.ACTION_MOVE:
//计算移动的距离
int offsetX = x - lastX;
int offsetY = y - lastY;
//对 left 和 right 进行偏移
offsetLeftAndRight(offsetX);
//对 top 和 bottom 进行偏移
offsetTopAndBottom(offsetY);
break;
LayoutParams(改变布局参数)
LayoutParams主要保存了一个View的布局参数,因此我们可以通过LayoutParams来改变View的布局参数从而达到改变View位置的效果。同样,我们将ACTION_MOVE中的代码替换成如下代码:
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)getLayoutParams();
layoutParams.leftMargin = getLeft() + offsetX;
layoutParams.topMargin = getBottom() + offsetY;
setLayoutParams(layoutParams);
因为父控件是 LinearLayout,所以我们用了LinearLayout.LayoutParams。如果父控件是RelativeLayout,则要使用RelativeLayout.LayoutParams。除了使用布局的LayoutParams外,我们还可以用ViewGroup.MarginLayoutParams来实现:
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams)getLayoutParams();
layoutParams.leftMargin = getLeft() + offsetX;
layoutParams.topMargin = getBottom() + offsetY;
setLayoutParams(layoutParams);
scrollTo与scollBy
scrollTo(x,y)表示移动到一个具体的坐标点,而 scrollBy(dx,dy)则表示移动的增量为dx、dy。其中,scollBy最终也是要调用scollTo的。View.java的scollBy和scollTo的源码如下所示:
public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
invalidateParentCaches();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
postInvalidateOnAnimation();
}
}
}
public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}
scollTo、scollBy移动的是View的内容,如果在ViewGroup中使用,则是移动其所有的子View。我们将ACTION_MOVE中的代码替换成如下代码:
((View) getParent()).scrollBy(-offsetX,<