国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android中自定義view實(shí)現(xiàn)側(cè)滑效果

2019-12-12 04:32:16
字體:
供稿:網(wǎng)友

效果圖:

看網(wǎng)上的都是兩個(gè)view拼接,默認(rèn)右側(cè)的不顯示,水平移動(dòng)的時(shí)候把右側(cè)的view顯示出來。但是看最新版QQ上的效果不是這樣的,但給人的感覺卻很好,所以獻(xiàn)丑來一發(fā)比較高仿的。

知識(shí)點(diǎn):

1、ViewDragHelper 的用法;
2、滑動(dòng)沖突的解決;
3、自定義viewgroup。

ViewDragHelper 出來已經(jīng)比較久了 相信大家都比較熟悉,不熟悉的話google一大把這里主要簡單用一下它的幾個(gè)方法

1、tryCaptureView(View child, int pointerId) :確定那個(gè)子view可以滑動(dòng)

2、 getViewHorizontalDragRange(View child):用我蹩腳的英語翻譯一下是‘返回的是子view在水平方向上可移動(dòng)的大小,以像素為單位,返回0的時(shí)候表示水平方向上不能拖動(dòng)'

3、clampViewPositionHorizontal(View child, int left, int dx):在這里可以對邊界進(jìn)行檢查,left和dx分別代表即將移動(dòng)到的位置

4、onViewPositionChanged(View changedView, int left, int top,
int dx, int dy):當(dāng)要捕獲view,由于拖曳或者設(shè)定而發(fā)生位置變更時(shí)回調(diào)

它的基本用法是:

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)、在構(gòu)造方法中創(chuàng)建

2)、在onInterceptTouchEvent 中判斷是否攔截

3 )、 在 onTouchEvent出來事件

好了 最不好理解的已經(jīng)搞定了。接下來看看具體實(shí)現(xiàn):

首先看布局:

<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區(qū)域的布局 -->    <include layout="@layout/layout_delete" />    <!-- item內(nèi)容的布局 -->    <include layout="@layout/layout_content" />  </scrollviewgroup.lly.com.swiplayout.SwipeLayout></LinearLayout>

這個(gè)沒什么好說的,一個(gè)自定義viewgroup包含兩個(gè)子控件。

接著看看SwipeLayout是怎么實(shí)現(xiàn)的:

@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 left, int top, int right,              int bottom) {    // super.onLayout(changed, left, top, right, bottom);    deleteView.layout(screenWidth - deleteWidth, 0, (screenWidth - deleteWidth)        + deleteWidth, deleteHeight);    contentView.layout(0, 0, contentWidth, deleteHeight);  }

上面代碼進(jìn)行了一些初始化的操作,重點(diǎn)看看onlayout里面的,我們繼承的是framelayout 這里先畫出來 deleteView并讓他在右邊,然后在上面改了一層contentView,這樣顯示的時(shí)候只會(huì)顯示contentView。

接下來看ontouch方法

public boolean onTouchEvent(MotionEvent event) {    //如果當(dāng)前有打開的,則下面的邏輯不能執(zhí)行    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方向移動(dòng)的距離        float moveX = event.getX();        float moveY = event.getY();        float delatX = moveX - downX;//x方向移動(dòng)的距離        float delatY = moveY - downY;//y方向移動(dòng)的距離        if(Math.abs(delatX)>Math.abs(delatY)){          //表示移動(dòng)是偏向于水平方向,那么應(yīng)該SwipeLayout應(yīng)該處理,請求父view不要攔截          requestDisallowInterceptTouchEvent(true);        }        //更新downX,downY        downX = moveX;        downY = moveY;        break;      case MotionEvent.ACTION_UP:        break;    }    viewDragHelper.processTouchEvent(event);    return true;  }

上面主要就是對事件沖突的處理,當(dāng)是水平移動(dòng)的時(shí)候就請求父視圖不要攔截。

接下來來重點(diǎn)就來了

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 left, int dx) {      if(child==contentView){        if(left>0)left = 0;        if(left<-deleteWidth)left = -deleteWidth;      }      return left;    }    @Override    public void onViewPositionChanged(View changedView, int left, int top,                     int dx, int dy) {      super.onViewPositionChanged(changedView, left, top, dx, dy);      //判斷開和關(guān)閉的邏輯      if(contentView.getLeft()==0 && currentState!=SwipeState.Close){        //說明應(yīng)該將state更改為關(guān)閉        currentState = SwipeState.Close;        //回調(diào)接口關(guān)閉的方法        if(listener!=null){          listener.onClose(getTag());        }        //說明當(dāng)前的SwipeLayout已經(jīng)關(guān)閉,需要讓Manager清空一下        SwipeLayoutManager.getInstance().clearCurrentLayout();      }else if (contentView.getLeft()==-deleteWidth && currentState!=SwipeState.Open) {        //說明應(yīng)該將state更改為開        currentState = SwipeState.Open;        //回調(diào)接口打開的方法        if(listener!=null){          listener.onOpen(getTag());        }        //當(dāng)前的Swipelayout已經(jīng)打開,需要讓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){        //應(yīng)該打開        open();      }else {        //應(yīng)該關(guān)閉        close();      }    }  };

上面這段代碼里面的方法一開始我們都說過了,在來看下在tryCaptureView中我們讓 contentView可以滑動(dòng),在getViewHorizontalDragRange中卻東滑動(dòng)范圍是deleteWidth,在clampViewPositionHorizontal中對邊界進(jìn)行了下限制,在onViewPositionChanged中進(jìn)行狀態(tài)的更新, 最后在手指抬起的時(shí)候讓view自動(dòng)回滾,

 /**   * 打開的方法   */  public void open() {    viewDragHelper.smoothSlideViewTo(contentView,-deleteWidth,contentView.getTop());    ViewCompat.postInvalidateOnAnimation(SwipeLayout.this);  }  /**   * 關(guān)閉的方法   */  public void close() {    viewDragHelper.smoothSlideViewTo(contentView,0,contentView.getTop());    ViewCompat.postInvalidateOnAnimation(SwipeLayout.this);  };  public void computeScroll() {    if(viewDragHelper.continueSettling(true)){      ViewCompat.postInvalidateOnAnimation(this);    }  }

這里注意一定要重寫computeScroll方法,不然滑動(dòng)效果動(dòng)一下就不動(dòng)了。

至此這個(gè)自定義framelayout就完成了

但是發(fā)現(xiàn)一個(gè)問題,我們在已經(jīng)滑動(dòng)出來的view中上下滑動(dòng)時(shí),這個(gè)view的deleteView還是顯示狀態(tài),所以還要在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 dx, int dy) {        super.onScrolled(recyclerView, dx, dy);        if(dy>0 || dy<0){          SwipeLayoutManager.getInstance().closeCurrentLayout();        }      }    });

當(dāng)這個(gè)RecyclerView是上下滑動(dòng)時(shí),讓子view復(fù)位。
收工。

ps:本來是在eclipse中l(wèi)istview中實(shí)現(xiàn)的,但是想想google都已經(jīng)不支持eclipse了,而listview也快被RecyclerView代替了,所以最后還是切換到Android studio,用RecyclerView實(shí)現(xiàn)了一套。

源碼地址

以上所述是小編給大家介紹的Android中自定義view實(shí)現(xiàn)側(cè)滑效果,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對武林網(wǎng)網(wǎng)站的支持!

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 台南县| 黄大仙区| 武冈市| 巴彦淖尔市| 武汉市| 嵊泗县| 措勤县| 霍州市| 翁牛特旗| 丰县| 昌宁县| 余江县| 盐亭县| 九寨沟县| 汽车| 丹巴县| 潢川县| 南川市| 新建县| 桓仁| 利津县| 即墨市| 荣昌县| 家居| 双牌县| 伊宁市| 泰来县| 樟树市| 静海县| 西吉县| 黄梅县| 汉中市| 武强县| 富民县| 长岛县| 抚州市| 琼结县| 桂林市| 凤台县| 砀山县| 永丰县|