在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(); 

   } 

 }

以上,希望给大伙提供思路,起到抛砖引玉的作用。