为更好说明 代码动态改变view的方式,此处以一个随手指滑动而变化的自定义view的讲解为例
随手指而动,少不了对 onTouchEvent 方法的处理,基本思路为3步:
1.手指摁下的时候,记录当前x,y坐标
2.手指移动后未抬起的时候,获取当前手指处的x,y坐标,算出位移差,给view重新设置位置
3.手指抬起的时候,将当前x,y坐标记录下来
首先自定义 View
@SuppressLint("ClickableViewAccessibility")
public class DragView extends View {
private Context mContext;
private int mLastX;//记录x坐标
private int mLastY;<span style="font-family: Arial, Helvetica, sans-serif;">//记录Y坐标</span>
private int mOfferX;//x位移差
private int mOfferY;//y位移差
private Scroller mScroller;
public DragView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext=context;
initData();
}
然后 重写onTouch方法:
@Override
public boolean onTouchEvent(MotionEvent event) {
int currentX = (int) event.getX();
int currentY = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN://在 MotionEvent.ACTION_DOWN 中记录摁下的坐标
mLastX=currentX;
mLastY=currentY;
break;
case MotionEvent.ACTION_MOVE://在 ACTION_MOVE 后算出 坐标移动差值,重新设置view的位置
mOfferX=currentX-mLastX;
mOfferY=currentY-mLastY;
//当前layout上面添加偏移量
// //第一种方式:<仅当前控件移动>
layout(getLeft()+mOfferX, getTop()+mOfferY, getRight()+mOfferX,getBottom()+mOfferY);
// //第二种方式:<仅当前控件移动>
offsetLeftAndRight(mOfferX);
offsetTopAndBottom(mOfferY);
// //第三种方式:<整个屏幕移动>
((View)getParent()).scrollBy(-mOfferX, -mOfferY);//参考系不同,所以mOfferX,mOfferY为负值
break;
case MotionEvent.ACTION_UP://更新最后的xy坐标记录
//重新设置坐标
mLastX=currentX;
mLastY=currentY;
break;
default:
break;
}
return true;
}
MotionEvent.ACTION_DOWN 和 MotionEvent.ACTION_UP 方法很简单,就是对down和up时的坐标做个记录,下面主要看move方法
首先看位移差的获取:mOfferX=currentX-mLastX
即是move之后的坐标和move之前的坐标差,y坐标的获取也是一样,此处不述
好,现在来看怎么设置view的新位置,view类有一个方法 layout(int l, int t, int r, int b) 来设置 view的位置
layout(getLeft()+mOfferX, getTop()+mOfferY, getRight()+mOfferX,getBottom()+mOfferY);中就是通过获得view之前的位置坐标,然后加上位移差,获得现在的view坐标位置,然后设置给view即可
下面看第二种方法:
offsetLeftAndRight(mOfferX);
offsetTopAndBottom(mOfferY);
其实是第一种方法设置的封装,代码中只需要传入x方向和y方向的位移差,使调用起来更方便
最后看第三种方式:scrollBy(int x, int y)
scrollBy(int x, int y)也为View的公开方法,从源码中可以看出 scrollBy中传入的 x,y为位移差,即代码中的mOfferX mOfferY
但并非直接调用scrollBy 方法就行,因为 scrollBy 方法需要 view 的父 容器 调用,故为((View)getParent()).scrollBy();
当然,最让人无语的是 方法一和方法二中mOfferX mOfferY 都是直接用的,为什么到方法三 中这两个值都为负的,原因就是参考系的不同,方法一和二是以 画板为参考系,方法三是以屏幕为参考系,所以为负数,
急需注意的是:方法一和二挪动的是view本身,方法三挪动的却是整个((View)getParent()).!!!
打个简单的例子,如果 一个布局 RelativeLayout中放了 自定义 view 和一个 button,方法一和二执行的时候会只移动 view,而button不动,而方法三移动的是整个>RelativeLayout ,所以方法三执行的时候,view和 button会一起动,这是需要注意的