在Android中,会遇到一个view随着手指滑动的需求,之前写了一篇仿IOS的圆圈的文章,今天用多种方法实现view的移动,思路一致,都是通过触摸事件获取到手指在屏幕上的坐标,然后想办法改变view的位置。
上一篇中技术就是用的第一种方法layout(),
public class DrView extends View{
private int lastX;
private int lastY;
public DrView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public boolean onTouchEvent(MotionEvent event) {
//获取到手指处的横纵坐标
int x = (int) event.getX();
int y = (int) event.getY();
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
//计算移动的距离
int offX = x - lastX;
int offY = y - lastY;
//调用layout方法来重新放置它的位置
DrView.this.layout(getLeft()+offX, getTop()+offY,
getRight()+offX , getBottom()+offY);
break;
}
return true;
}
}
这个是之前的简写版,这一篇主要讲原理;
第二种是根据LayoutParams来确定位置,我们在代码中new一个控件时,会用到LayoutParams,现在,移动位置时,也可以使用
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
int offX = x - lastX;
int offY = y - lastY;
ViewGroup.MarginLayoutParams lp =
(MarginLayoutParams) getLayoutParams();
lp.leftMargin = getLeft()+offX;
lp.topMargin = getTop()+offY;
setLayoutParams(lp);
break;
}
return true;
}
第三种方法是用View提供的api来实现,offsetLeftAndRight() offsetTopAndBottom()这两个方法是对左右和上下移动的api封装,传入的就是偏移量,是View提供的
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
int offX = x - lastX;
int offY = y - lastY;
offsetLeftAndRight(offX);
offsetTopAndBottom(offY);
break;
}
return true;
}
这种写法相对简单,但这两个方法不常见,新手一般都不知道这个方法。
以上三个方法,前两种比较好理解,第三种是View提供的方法,记住api的功能就好。
View本身也有移动的api,比如scrollTo()和scrollBy(),之前的文章也有介绍,这里也可以使用这两个方法来控制View。但这个一般是移动控件的父容器,来带动里面的控件移动。
第四种,sceollTo(x,y)传入的是移动的终点坐标,如此,可以使用把手指的移动时坐标传进去
public boolean onTouchEvent(MotionEvent event) {
//获取到手指处的横坐标和纵坐标
int x = (int) event.getX();
int y = (int) event.getY();
switch(event.getAction()){
case MotionEvent.ACTION_MOVE:
((View) getParent()).scrollTo(x,y);
break;
}
return true;
}
第五种,用scrollBy(dx,dy),传入的是移动的增量。类似上面的,但由于是移动父容器带动自容器移动,所以自身往右移动时,父容器也往右移动,实际上屏幕往左,所以值要取个相反数。
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
int offX = x - lastX;
int offY = y - lastY;
((View) getParent()).scrollBy(-offX,- offY);
break;
}
return true;
}
第六种,使用辅助类Scroller,老三步
初始化mSc = new Scroller(context)
重写computeScroll()方法,实现模拟滑动。
public void computeScroll() {
super.computeScroll();
if(mScroller.computeScrollOffset()){
((View)getParent()).scrollTo(mSc.getCurrX(),mSc.getCurrY());
}
invalidate();
}
开启模拟过程,
startScroll(int startX,int startY, int dx,int dy,int duration)
startScroll(int startX,int startY,int dx,int dy)
以下四句参考网上其他文献,:
1.computeScrollOffset方法判断是否完成了整个滑动,返回为true,没有完成,否则则完成滑动。
2.getCurrY()以及getCurrX()获得的是当前现在的滑动坐标。
3.最后必须要用invalidate方法来刷新。因为computeScroll方法不会自动调用,
4.在startScroll中,偏移量跟使用scrollBy方法中的偏移量用法是一样的,即也必须填写你实际想要移动距离的相反数。也就是你实际想让它偏移一个正值,这里就填写它相应的负值,如果想偏移一个负值,这里就填写相应的正值!
因为Scroller定义的坐标轴,x轴向左为正,y轴向上为正。
public class DrView extends View{
private int lastX;
private int lastY;
private Scroller mSc;
public DrView(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
}
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
int offX = x - lastX;
int offY = y - lastY;
View viewGroup = (View) getParent();
((View) getParent()).scrollBy(-offX,- offY);
break;
case MotionEvent.ACTION_UP:
View viewGroup = (View) getParent();
//开启滑动,让其回到原点
mSc.startScroll(viewGroup.getScrollX(),
viewGroup.getScrollY(),
-viewGroup.getScrollX() ,-viewGroup.getScrollY());
break;
}
return true;
}
public void computeScroll() {
super.computeScroll();
if(mSc.computeScrollOffset()) {
((View)getParent()).scrollTo(mSc.getCurrX(),
mSc.getCurrY());
}
invalidate();
}
}
以上,希望给大伙提供思路,起到抛砖引玉的作用。