Android View的滑动

view的位置参数

view的位置中,经常会碰到几个获取位置参数方法,如getX(),getScrollXgetLeft()等,在View绘制过程中,其位置是由四个顶点来决定,其分别是top,left,right,bottom,但需的注意的一点是:其位置是相对于父容器,而不是相对于屏幕的,就如下图:
这里写图片描述
在获取view的宽和高,通常会调用getWidth()getHeight()两个方法,从源码来看便知道有如下关系:
width=right-left
height=bottom-top
在android3.0以后,android就增加了属性动画,其属性动画会影响view的本身位置等属性,但view动画是不会影响view的本身位置属性,它仅会影响到其的内容的位置变化。在Vie中,有几个重要的位置记录参数,x,y,translationX,translationY,其中xy是view左上角的坐标(其坐标也是相对于父容器),而translationXtranslationY是View左上角相对于父容器的偏移量,但其两个默认都是零。
那么getX()getY()跟上面几个参数有如何关系,看如下android源码:

/**
 * A Property wrapper around the <code>x</code> functionality handled by the
 * {@link View#setX(float)} and {@link View#getX()} methods.
 */
public static final Property<View, Float> X = new FloatProperty<View>("x") {
    @Override
    public void setValue(View object, float value) {
        object.setX(value);
    }

    @Override
    public Float get(View object) {
        return object.getX();
    }
};

/**
 * Sets the visual x position of this view, in pixels. This is equivalent to setting the
 * {@link #setTranslationX(float) translationX} property to be the difference between
 * the x value passed in and the current {@link #getLeft() left} property.
 *
 * @param x The visual x position of this view, in pixels.
 */
public void setX(float x) {
    setTranslationX(x - mLeft);
}

/**
 * The visual x position of this view, in pixels. This is equivalent to the
 * {@link #setTranslationX(float) translationX} property plus the current
 * {@link #getLeft() left} property.
 *
 * @return The visual x position of this view, in pixels.
 */
@ViewDebug.ExportedProperty(category = "drawing")
public float getX() {
    return mLeft + getTranslationX();
}

因此便知其换算关系:getX()=x=left+translationX,getY()=y=top+translationY,因此在view动画的平移过程中,并不会影响top,left,right,bottom的值,而是改变translationX,translatinY的值。
我们知道我们最常用的一种滑动实现是使用Scroller,scrollTo,scrollBy等组合,在这些实现当中,有两个重要位置信息参数就是mScrollXmScrollY,其默认都是零.其mScrollX代表View左边缘和View内容左边缘在水平方向的距离,而mScrollY代表View上边缘和View内容上边缘在竖直方向的距离,其关系如图:
这里写图片描述
其换算关系:mScrollX=View左边缘-View内容左边缘,mScrollY=View上边缘-View内容上边缘,因此要让View组件相对于View内容从左到右滑动,那么设置mScrollX为负数,即可调用scrollTo(负数,0)scrollBy(负数,0),同理,要让View组件相对于View内容从下到上滑动,那么设置mScrollY为负数,即可调用scrollTo(0,负数)scrollBy(0,负数).

MotionEvent的位置参数

在android点击触发事件中,我们经常会碰到四个方法,getX(),getY(),getRawX(),getRawY(),那么getX()getRawX()有什么区别呢?
其中getX()是相对于View本身位置而言,而getRawX()是相对于屏幕而言,同理getY()getRawY()也一样,具体区别如图:
这里写图片描述

实践demo:

我就实现一个listView的侧滑删除功能来作为这次学习成果,以下是核心代码:

//slide logic
public boolean onSlide(MotionEvent event){
       switch (event.getAction()){
           case MotionEvent.ACTION_DOWN:
               stopScroll();
               mDownX=(int)event.getX();
               break;
           case MotionEvent.ACTION_MOVE:
               int dis=(int)(mDownX-event.getX());
               //when mBackGroundView has been opened and user slide this item again.
               if(state== STATE_OPEN){
                   dis+=mBackGroundView.getWidth()*mSwipeDirection;
               }
               swipe(dis);
               break;
           case MotionEvent.ACTION_UP:
               int halfWith=0;
               //whether distance of item's slide is beyond its half.
               if(mSwipeDirection==DIRECTION_LEFT){
                   halfWith=mContentView.getWidth()-mBackGroundView.getLeft();
               }else if(mSwipeDirection==DIRECTION_RIGHT){
                   halfWith=mBackGroundView.getWidth()+mBackGroundView.getLeft();
               }
               if(Math.abs(halfWith)>(mBackGroundView.getWidth()>>1)&&!isAutoSpringBack){
                   smoothOpenItem();
               }else{
                   smoothCloseItem();
                   return false;
               }
               break;
       }
       return true;
   }
  //using layout() method to implement slide
   private void swipe(int dis){
        if(!mSwipEnable){
            return;
        }
        //whether user is silding the item.
        if(Math.signum(dis)!=mSwipeDirection){
            dis=0;
        }else if(Math.abs(dis)> mBackGroundView.getWidth()){
            dis=mBackGroundView.getWidth()*mSwipeDirection;
        }
        mContentView.layout(-dis, mContentView.getTop(),
                mContentView.getWidth() -dis, getMeasuredHeight());
        if (mSwipeDirection == DIRECTION_LEFT) {
            mBackGroundView.layout(mContentView.getWidth() - dis, mBackGroundView.getTop(),
                    mContentView.getWidth() + mBackGroundView.getWidth() - dis,
                    mBackGroundView.getBottom());
        } else {
            mBackGroundView.layout(-mBackGroundView.getWidth() - dis, mBackGroundView.getTop(),
                    - dis, mBackGroundView.getBottom());
        }
    }

    /**
    * when {@link #smoothCloseItem()} or {@link #smoothOpenItem()} is called,it will be invoked.
    *
    * @see #smoothCloseItem()
    * @see #smoothOpenItem()
    */
   @Override
   public void computeScroll() {
       if (state == STATE_OPEN) {
           if (mOpenScroller.computeScrollOffset()) {
               swipe(mOpenScroller.getCurrX()*mSwipeDirection);
               postInvalidate();
           }else{
               if(mOnSlideStopCallBack !=null&&isCallStopCallBack){
                   isCallStopCallBack=false;
                   mOnSlideStopCallBack.openStop(this,position);
               }
           }
       } else {
           if (mCloseScroller.computeScrollOffset()) {
               swipe((mBaseX - mCloseScroller.getCurrX())*mSwipeDirection);
               postInvalidate();
           }else {
               if(mOnSlideStopCallBack !=null&&isCallStopCallBack){
                   isCallStopCallBack=false;
                   mOnSlideStopCallBack.closeStop(this,position);
               }
           }
       }
   }

效果:
这里写图片描述
Demo地址:https://github.com/scau-beyondboy/SlideItemToDelete

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值