Android中自定义view实现侧滑效果

Android中自定义view实现侧滑效果,第1张

概述效果图:看网上的都是两个view拼接,默认右侧的不显示,水平移动的时候把右侧的view显示出来。但是看最新版QQ上的效果不是这样的,但给人的感觉却很好,所以献丑来一发比较高仿的。

效果图:

看网上的都是两个vIEw拼接,默认右侧的不显示,水平移动的时候把右侧的vIEw显示出来。但是看最新版QQ上的效果不是这样的,但给人的感觉却很好,所以献丑来一发比较高仿的。

知识点:

1、VIEwDragHelper 的用法;
2、滑动冲突的解决;
3、自定义viewgroup。

VIEwDragHelper 出来已经比较久了 相信大家都比较熟悉,不熟悉的话Google一大把这里主要简单用一下它的几个方法

1、tryCaptureVIEw(VIEw child,int pointerID) :确定那个子vIEw可以滑动

2、 getVIEwHorizontalDragRange(VIEw child):用我蹩脚的英语翻译一下是‘返回的是子vIEw在水平方向上可移动的大小,以像素为单位,返回0的时候表示水平方向上不能拖动'

3、clampVIEwpositionHorizontal(VIEw child,int left,int dx):在这里可以对边界进行检查,left和dx分别代表即将移动到的位置

4、onVIEwpositionChanged(VIEw changedVIEw,int top,
int dx,int dy):当要捕获vIEw,由于拖曳或者设定而发生位置变更时回调

它的基本用法是:

public SwipeLayout(Context context,AttributeSet attrs,int defStyle) {    super(context,attrs,defStyle);    init();  }  private voID init() {    vIEwDragHelper = VIEwDragHelper.create(this,callback);  }   public boolean onIntercepttouchEvent(MotionEvent ev) {    boolean result = vIEwDragHelper.shouldIntercepttouchEvent(ev);   }   public boolean ontouchEvent(MotionEvent event) {    vIEwDragHelper.processtouchEvent(event);    return true;  }

1)、在构造方法中创建

2)、在onIntercepttouchEvent 中判断是否拦截

3 )、 在 ontouchEvent出来事件

好了 最不好理解的已经搞定了。接下来看看具体实现:

首先看布局:

<linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID"  androID:layout_wIDth="match_parent"  androID:layout_height="wrap_content"  androID:orIEntation="vertical" >  <scrollvIEwgroup.lly.com.swiplayout.SwipeLayout    androID:ID="@+ID/swipeLayout"    androID:layout_wIDth="match_parent"    androID:layout_height="wrap_content" >    <!-- delete区域的布局 -->    <include layout="@layout/layout_delete" />    <!-- item内容的布局 -->    <include layout="@layout/layout_content" />  </scrollvIEwgroup.lly.com.swiplayout.SwipeLayout></linearLayout>

这个没什么好说的,一个自定义viewgroup包含两个子控件。

接着看看SwipeLayout是怎么实现的:

@OverrIDe  protected voID onFinishInflate() {    super.onFinishInflate();    deleteVIEw = getChildAt(0);    contentVIEw = getChildAt(1);  }  @OverrIDe  protected voID onSizeChanged(int w,int h,int olDW,int oldh) {    super.onSizeChanged(w,h,olDW,oldh);    deleteHeight = deleteVIEw.getMeasuredHeight();    deleteWIDth = deleteVIEw.getMeasureDWIDth();    contentWIDth = contentVIEw.getMeasureDWIDth();    screenWIDth = getWIDth();  }  @OverrIDe  protected voID onLayout(boolean changed,int right,int bottom) {    // super.onLayout(changed,left,top,right,bottom);    deleteVIEw.layout(screenWIDth - deleteWIDth,(screenWIDth - deleteWIDth)        + deleteWIDth,deleteHeight);    contentVIEw.layout(0,contentWIDth,deleteHeight);  }

上面代码进行了一些初始化的 *** 作,重点看看onlayout里面的,我们继承的是framelayout 这里先画出来 deleteVIEw并让他在右边,然后在上面改了一层contentVIEw,这样显示的时候只会显示contentVIEw。

接下来看ontouch方法

public boolean ontouchEvent(MotionEvent event) {    //如果当前有打开的,则下面的逻辑不能执行    if(!SwipeLayoutManager.getInstance().isShouldSwipe(this)){      requestdisallowIntercepttouchEvent(true);      return true;    }    switch (event.getAction()) {      case MotionEvent.ACTION_DOWN:        downX = event.getX();        downY = event.getY();        break;      case MotionEvent.ACTION_MOVE:        //1.获取x和y方向移动的距离        float moveX = event.getX();        float moveY = event.getY();        float delatX = moveX - downX;//x方向移动的距离        float delatY = moveY - downY;//y方向移动的距离        if(Math.abs(delatX)>Math.abs(delatY)){          //表示移动是偏向于水平方向,那么应该SwipeLayout应该处理,请求父vIEw不要拦截          requestdisallowIntercepttouchEvent(true);        }        //更新downX,downY        downX = moveX;        downY = moveY;        break;      case MotionEvent.ACTION_UP:        break;    }    vIEwDragHelper.processtouchEvent(event);    return true;  }

上面主要就是对事件冲突的处理,当是水平移动的时候就请求父视图不要拦截。

接下来来重点就来了

private VIEwDragHelper.Callback callback = new VIEwDragHelper.Callback() {    @OverrIDe    public boolean tryCaptureVIEw(VIEw child,int pointerID) {      return child==contentVIEw;    }    @OverrIDe    public int getVIEwHorizontalDragRange(VIEw child) {      return deleteWIDth;    }    @OverrIDe    public int clampVIEwpositionHorizontal(VIEw child,int dx) {      if(child==contentVIEw){        if(left>0)left = 0;        if(left<-deleteWIDth)left = -deleteWIDth;      }      return left;    }    @OverrIDe    public voID onVIEwpositionChanged(VIEw changedVIEw,int dx,int dy) {      super.onVIEwpositionChanged(changedVIEw,dx,dy);      //判断开和关闭的逻辑      if(contentVIEw.getleft()==0 && currentState!=Swipestate.Close){        //说明应该将state更改为关闭        currentState = Swipestate.Close;        //回调接口关闭的方法        if(Listener!=null){          Listener.onClose(getTag());        }        //说明当前的SwipeLayout已经关闭,需要让Manager清空一下        SwipeLayoutManager.getInstance().clearCurrentLayout();      }else if (contentVIEw.getleft()==-deleteWIDth && currentState!=Swipestate.Open) {        //说明应该将state更改为开        currentState = Swipestate.Open;        //回调接口打开的方法        if(Listener!=null){          Listener.onopen(getTag());        }        //当前的Swipelayout已经打开,需要让Manager记录一下下        SwipeLayoutManager.getInstance().setSwipeLayout(SwipeLayout.this);      }    }    @OverrIDe    public voID onVIEwReleased(VIEw releasedChild,float xvel,float yvel) {      super.onVIEwReleased(releasedChild,xvel,yvel);      if(contentVIEw.getleft()<-deleteWIDth/2){        //应该打开        open();      }else {        //应该关闭        close();      }    }  };

上面这段代码里面的方法一开始我们都说过了,在来看下在tryCaptureVIEw中我们让 contentVIEw可以滑动,在getVIEwHorizontalDragRange中却东滑动范围是deleteWIDth,在clampVIEwpositionHorizontal中对边界进行了下限制,在onVIEwpositionChanged中进行状态的更新, 最后在手指抬起的时候让vIEw自动回滚,

 /**   * 打开的方法   */  public voID open() {    vIEwDragHelper.smoothSlIDeVIEwTo(contentVIEw,-deleteWIDth,contentVIEw.gettop());    VIEwCompat.postInvalIDateOnAnimation(SwipeLayout.this);  }  /**   * 关闭的方法   */  public voID close() {    vIEwDragHelper.smoothSlIDeVIEwTo(contentVIEw,contentVIEw.gettop());    VIEwCompat.postInvalIDateOnAnimation(SwipeLayout.this);  };  public voID computeScroll() {    if(vIEwDragHelper.continueSettling(true)){      VIEwCompat.postInvalIDateOnAnimation(this);    }  }

这里注意一定要重写computeScroll方法,不然滑动效果动一下就不动了。

至此这个自定义framelayout就完成了

但是发现一个问题,我们在已经滑动出来的vIEw中上下滑动时,这个vIEw的deleteVIEw还是显示状态,所以还要在activity中处理一下:

 recyVIEw.setonScrollListener(new RecyclerVIEw.OnScrollListener() {      @OverrIDe      public voID onScrollStateChanged(RecyclerVIEw recyclerVIEw,int newState) {        super.onScrollStateChanged(recyclerVIEw,newState);      }      @OverrIDe      public voID onScrolled(RecyclerVIEw recyclerVIEw,int dy) {        super.onScrolled(recyclerVIEw,dy);        if(dy>0 || dy<0){          SwipeLayoutManager.getInstance().closeCurrentLayout();        }      }    });

当这个RecyclerVIEw是上下滑动时,让子vIEw复位。
收工。

ps:本来是在eclipse中ListvIEw中实现的,但是想想Google都已经不支持eclipse了,而ListvIEw也快被RecyclerVIEw代替了,所以最后还是切换到AndroID studio,用RecyclerVIEw实现了一套。

源码地址

以上所述是小编给大家介绍的AndroID中自定义view实现侧滑效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对编程小技巧网站的支持!

总结

以上是内存溢出为你收集整理的Android中自定义view实现侧滑效果全部内容,希望文章能够帮你解决Android中自定义view实现侧滑效果所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1147644.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存