在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();
  }
}
以上,希望给大伙提供思路,起到抛砖引玉的作用。

更多相关文章

  1. Android(安卓)studio断点调试(全在这里)
  2. Android(安卓)View事件分发、拦截、消费机制
  3. Android开发 - 获取Android设备的唯一标识码(Android(安卓)6.0或
  4. 【转载】Andoid Studio-android开发02-第一个程序-调试-运行方法
  5. Android(安卓)NDK 开发 —— 从 Assets 文件夹加载图片并上传纹
  6. ListView去掉分割线
  7. [转]Android蓝牙开发浅谈
  8. Android界面绘制_canvas解析
  9. Android(安卓)Studio—— jni初体验(一)

随机推荐

  1. Linux/Android——input系统之 kernel层
  2. 利用Android中的SQLite进行CRUD
  3. Android属性之build.prop,及property_get/
  4. Android实现书籍翻页效果--扩展版
  5. Android基础入门教程——1.2.2 使用Andro
  6. 安卓selector使用方法
  7. 如何给你的Android(安卓)安装文件(APK)瘦身
  8. android中的UI控制(一)
  9. Android(安卓)如何使用GPU硬件加速
  10. Android(安卓)动态logo bootanimation.zi