1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務(wù)時(shí)間:8:30-17:00
      你可能遇到了下面的問題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
      深入淺析Android中的NestedScrolling滑動(dòng)機(jī)制

      深入淺析Android中的NestedScrolling滑動(dòng)機(jī)制?針對(duì)這個(gè)問題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡(jiǎn)單易行的方法。

      創(chuàng)新互聯(lián)建站,是成都地區(qū)的互聯(lián)網(wǎng)解決方案提供商,用心服務(wù)為企業(yè)提供網(wǎng)站建設(shè)、成都app軟件開發(fā)成都小程序開發(fā)、系統(tǒng)定制網(wǎng)站設(shè)計(jì)和微信代運(yùn)營服務(wù)。經(jīng)過數(shù)十多年的沉淀與積累,沉淀的是技術(shù)和服務(wù),讓客戶少走彎路,踏實(shí)做事,誠實(shí)做人,用情服務(wù),致力做一個(gè)負(fù)責(zé)任、受尊敬的企業(yè)。對(duì)客戶負(fù)責(zé),就是對(duì)自己負(fù)責(zé),對(duì)企業(yè)負(fù)責(zé)。

      1,如今NestedScrolling運(yùn)用到很多地方了,要想好看一點(diǎn)的滑動(dòng)變換,基本上就是使用這個(gè)來完成的,讓我們來簡(jiǎn)單的了解一下。

      2,NestedScrolling機(jī)制能夠讓父View和子View在滾動(dòng)式進(jìn)行配合,其基本流程如下:

      • 當(dāng)子view開始滾動(dòng)之前,可以通知父View,讓其先于自己進(jìn)行滾動(dòng);
      • 子View自己進(jìn)行滾動(dòng);
      • 子view滾動(dòng)之后,還可以通知父view繼續(xù)滾動(dòng)。

      而要實(shí)現(xiàn)這樣的交互機(jī)制,首先父view要實(shí)現(xiàn)NestedScrollingParent接口,而子View需要實(shí)現(xiàn)N恩斯特大S從rollingChild接口,在這套機(jī)制中子View是發(fā)起者,父view是接受回調(diào)并做出響應(yīng)的。

      一下是幾個(gè)關(guān)鍵的類和接口

      //主要接口
      NestedScrollingChild
      NestedScrollingParent
      
      //幫助類
      NestedScrollingChildHelper
      NestedScrollingParentHelper 
      

      一些新的系統(tǒng)View已經(jīng)幫我們實(shí)現(xiàn)了以上兩個(gè)接口,也就是說他們是支持NestedScrolling,例如:

      NestedScrollView已經(jīng)實(shí)現(xiàn)了NestedScrollingChild和NestedScrollingParent兩個(gè)接口

      RecycleView已經(jīng)實(shí)現(xiàn)了NestedScrollingChild

      CoordinatorLayout實(shí)現(xiàn)了NestedScrollingParent

      NestedScrollingChild接口

      //開始、停止嵌套滾動(dòng)
      
      public boolean startNestedScroll(int axes); public void stopNestedScroll();
      
      //觸摸滾動(dòng)相關(guān)
      
      public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow);
      
      public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow);
      
      //慣性滾動(dòng)相關(guān) public boolean dispatchNestedPreFling(float velocityX, float velocityY);
      
      public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed); 
      
      public boolean startNestedScroll(int axes);

      開啟嵌套滾動(dòng)流程(實(shí)際上是進(jìn)行了一些嵌套滾動(dòng)前準(zhǔn)備工作)。

      當(dāng)找到了能夠配合當(dāng)前子view進(jìn)行嵌套滾動(dòng)的父view時(shí),返回值為true(Returns:true if a cooperative parent was found and nested scrolling has been enabled for the current gesture)。

      public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow);

      在子view自己進(jìn)行滾動(dòng)之前調(diào)用此方法,詢問父view是否要在子view之前進(jìn)行滾動(dòng)。

      此方法的前兩個(gè)參數(shù)用于告訴父View此次要滾動(dòng)的距離;而第三第四個(gè)參數(shù)用于子view獲取父view消費(fèi)掉的距離和父view位置的偏移量。

      第一第二個(gè)參數(shù)為輸入?yún)?shù),即常規(guī)的函數(shù)參數(shù),調(diào)用函數(shù)的時(shí)候我們需要為其傳遞確切的值。而第三第四個(gè)參數(shù)為輸出參數(shù),調(diào)用函數(shù)時(shí)我們只需要傳遞容器(在這里就是兩個(gè)數(shù)組),在調(diào)用結(jié)束后,我們就可以從容器中獲取函數(shù)輸出的值。

      如果parent消費(fèi)了一部分或全部距離,則此方法返回true。

      復(fù)制代碼 代碼如下:

      public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow);

      在子view自己進(jìn)行滾動(dòng)之后調(diào)用此方法,詢問父view是否還要進(jìn)行余下(unconsumed)的滾動(dòng)。

      前四個(gè)參數(shù)為輸入?yún)?shù),用于告訴父view已經(jīng)消費(fèi)和尚未消費(fèi)的距離,最后一個(gè)參數(shù)為輸出參數(shù),用于子view獲取父view位置的偏移量。

      返回值:(翻譯出來可能有歧義,直接放原文)true if the event was dispatched, false if it could not be dispatched.

      public void stopNestedScroll();

      最后,stopNestedScroll()方法與startNestedScroll(int axes)對(duì)應(yīng),用于結(jié)束嵌套滾動(dòng)流程;而慣性滾動(dòng)相關(guān)的兩個(gè)方法與觸摸滾動(dòng)相關(guān)的兩個(gè)方法類似,這里不再贅述。

      NestedScrollingParent接口概述

      //當(dāng)開啟、停止嵌套滾動(dòng)時(shí)被調(diào)用
      
      public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes);
      
      public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes);
      
      public void onStopNestedScroll(View target);
      
      //當(dāng)觸摸嵌套滾動(dòng)時(shí)被調(diào)用
      
      public void onNestedPreScroll(View target, int dx, int dy, int[] consumed);
      
      public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed);
      
      //當(dāng)慣性嵌套滾動(dòng)時(shí)被調(diào)用
      
      public boolean onNestedPreFling(View target, float velocityX, float velocityY);
      
      public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed); 
      
      

      從命名可以看出,這幾個(gè)都是回調(diào)方法。當(dāng)調(diào)用NestedScrollingChild中的方法時(shí),NestedScrollingParent中與之相對(duì)應(yīng)的方法就會(huì)被回調(diào)。方法之間的具體對(duì)應(yīng)關(guān)系如下:

      深入淺析Android中的NestedScrolling滑動(dòng)機(jī)制

      從上面的接口還有方法我們可以得出一些簡(jiǎn)單的流程

      • 調(diào)用child的startNestedScroll()來發(fā)起嵌套滑動(dòng)流程(實(shí)質(zhì)上是尋找能夠配合child進(jìn)行嵌套滾動(dòng)的parent)。parent的onStartNestedScroll()會(huì)被調(diào)用,若此方法返回true,則OnNestScrollAccepted()也會(huì)被調(diào)用。
      • chuld每次滾動(dòng)前,可以先詢問parent是否要滾動(dòng),即調(diào)用dispatchNestedScroll(),這時(shí)可以回調(diào)到parent的OnNestedPreScroll(),parent可以在這個(gè)回調(diào)中先于child滾動(dòng)。
      • dispatchNestedPreScroll()之后,child可以進(jìn)行自己的滾動(dòng)操作。

      3,自定義NestedScrolling控件

      先看一下效果

      深入淺析Android中的NestedScrolling滑動(dòng)機(jī)制

      先看一下布局文件activity_main.xml

      <?xml version="1.0" encoding="utf-8"?>
      
      
      
       
      
       
      
       
      
        
      
       
      
        
      
       
      
        
      
       
      
         
      
        
      
       
      
       
      
      

      布局文件只是簡(jiǎn)單的嵌套,MyNestedScrollParent繼承Linearlayout,并實(shí)現(xiàn)NestedScrollingParent接口,MyNestedScrollChild同理,先來看看MyNestedScrollChild這個(gè)類吧。

      MyNestedScrollChild.java

      package com.qianmo.mynestedscrolling.view;
      import android.content.Context;
      import android.os.Build;
      import android.support.annotation.RequiresApi;
      import android.support.v4.view.NestedScrollingChild;
      import android.support.v4.view.NestedScrollingChildHelper;
      import android.support.v4.view.ViewCompat;
      import android.util.AttributeSet;
      import android.view.MotionEvent;
      import android.widget.LinearLayout;
      
      public class MyNestedScrollChild extends LinearLayout implements NestedScrollingChild {
      
       private NestedScrollingChildHelper mNestedScrollingChildHelper;
      
       private final int[] offset = new int[2]; //偏移量
      
       private final int[] consumed = new int[2]; //消費(fèi)
      
       private int lastY;
      
       private int showHeight; 
      
       public MyNestedScrollChild(Context context) {
      
        super(context);
      
       }
      
       public MyNestedScrollChild(Context context, AttributeSet attrs) {
      
        super(context, attrs);
      
       }
       @Override
      
       protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
      
        //第一次測(cè)量,因?yàn)椴季治募懈叨仁莣rap_content,因此測(cè)量模式為atmost,即高度不超過父控件的剩余空間
      
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
      
        showHeight = getMeasuredHeight();
      
       
      
        //第二次測(cè)量,對(duì)稿哦度沒有任何限制,那么測(cè)量出來的就是完全展示內(nèi)容所需要的高度
      
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
      
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
      
       }
       @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
      
       @Override
      
       public boolean onTouchEvent(MotionEvent event) {
      
        switch (event.getAction()) {
      
         //按下
      
         case MotionEvent.ACTION_DOWN:
      
          lastY = (int) event.getRawY();
      
          break;
      
         //移動(dòng)
      
         case MotionEvent.ACTION_MOVE:
      
          int y = (int) (event.getRawY());
      
          int dy = y - lastY;
      
          lastY = y;
      
          if (startNestedScroll(ViewCompat.SCROLL_AXIS_HORIZONTAL)
      
            && dispatchNestedPreScroll(0, dy, consumed, offset)) //如果找到了支持嵌套滑動(dòng)的父類,父類進(jìn)行了一系列的滑動(dòng)
      
          {
      
           //獲取滑動(dòng)距離
      
           int remain = dy - consumed[1];
      
           if (remain != 0) {
      
            scrollBy(0, -remain);
      
           }
      
       
      
          } else {
      
           scrollBy(0, -dy);
      
          }
      
          break;
      
        }
      
       
      
        return true;
      
       }
      
       //限制滾動(dòng)范圍
      
       @Override
      
       public void scrollTo(int x, int y) {
      
        int maxY = getMeasuredHeight() - showHeight;
      
        if (y > maxY) {
      
         y = maxY;
      
        }
      
        if (y < 0) {
      
         y = 0;
      
        }
      
        super.scrollTo(x, y);
      
       }
       //初始化helper對(duì)象
      
       private NestedScrollingChildHelper getScrollingChildHelper() {
      
        if (mNestedScrollingChildHelper == null) {
      
         mNestedScrollingChildHelper = new NestedScrollingChildHelper(this);
      
         mNestedScrollingChildHelper.setNestedScrollingEnabled(true);
      
        }
      
        return mNestedScrollingChildHelper;
      
       }
       //實(shí)現(xiàn)一下接口
      
       @Override
      
       public void setNestedScrollingEnabled(boolean enabled) {
      
        getScrollingChildHelper().setNestedScrollingEnabled(enabled);
      
       }
       @Override
      
       public boolean isNestedScrollingEnabled() {
      
        return getScrollingChildHelper().isNestedScrollingEnabled();
      
       }
      
       @Override
      
       public boolean startNestedScroll(int axes) {
      
        return getScrollingChildHelper().startNestedScroll(axes);
      
       }
      
       @Override
      
       public void stopNestedScroll() {
      
        getScrollingChildHelper().stopNestedScroll();
      
       }
      
       @Override
      
       public boolean hasNestedScrollingParent() {
      
        return getScrollingChildHelper().hasNestedScrollingParent();
      
       }
       @Override
      
       public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
      
        return getScrollingChildHelper().dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
      
       }
       @Override
      
       public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
      
        return getScrollingChildHelper().dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
      
       }
       @Override
      
       public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
      
        return getScrollingChildHelper().dispatchNestedFling(velocityX, velocityY, consumed);
      
       }
      
       @Override
      
       public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
      
        return getScrollingChildHelper().dispatchNestedPreFling(velocityX, velocityY);
      
       }
      } 

      主要是在OnTouchEvent中先后調(diào)用了startNestedScroll()和dispatchNestedPreScroll()方法,在借助helper來完成NestedScrollingParent接口方法

      MyNestedScrollParent.java

      package com.qianmo.mynestedscrolling.view;
      import android.content.Context;
      import android.support.v4.view.NestedScrollingParent;
      import android.support.v4.view.NestedScrollingParentHelper;
      import android.util.AttributeSet;
      import android.view.View;
      import android.view.ViewTreeObserver;
      import android.widget.ImageView;
      import android.widget.LinearLayout;
      import android.widget.TextView;
      
      /**
      
       * Created by wangjitao on 2017/2/14 0014.
       * 嵌套滑動(dòng)機(jī)制父View
       */
      public class MyNestedScrollParent extends LinearLayout implements NestedScrollingParent {
      
       private ImageView img;
      
       private TextView tv;
      
       private MyNestedScrollChild myNestedScrollChild;
      
       private NestedScrollingParentHelper mNestedScrollingParentHelper;
      
       private int imgHeight;
      
       private int tvHeight;
      
       
      
       public MyNestedScrollParent(Context context) {
      
        super(context);
      
       }
      
       
      
       public MyNestedScrollParent(Context context, AttributeSet attrs) {
      
        super(context, attrs);
      
        init();
      
       }
      
       
      
       private void init() {
      
        mNestedScrollingParentHelper = new NestedScrollingParentHelper(this);
      
       }
      
       
      
       //獲取子view
      
       @Override
      
       protected void onFinishInflate() {
      
        img = (ImageView) getChildAt(0);
      
        tv = (TextView) getChildAt(1);
      
        myNestedScrollChild = (MyNestedScrollChild) getChildAt(2);
      
        img.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
      
         @Override
      
         public void onGlobalLayout() {
      
          if (imgHeight <= 0) {
      
           imgHeight = img.getMeasuredHeight();
      
          }
      
         }
      
        });
      
        tv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
      
         @Override
      
         public void onGlobalLayout() {
      
          if (tvHeight <= 0) {
      
           tvHeight = tv.getMeasuredHeight();
      
          }
      
         }
      
        });
      
       }
      
       
       
      
       //在此可以判斷參數(shù)target是哪一個(gè)子view以及滾動(dòng)的方向,然后決定是否要配合其進(jìn)行嵌套滾動(dòng)
      
       @Override
      
       public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
      
        if (target instanceof MyNestedScrollChild) {
      
         return true;
      
        }
      
        return false;
      
       }
      
       @Override
      
       public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
      
        mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, nestedScrollAxes);
      
       }
       @Override
      
       public void onStopNestedScroll(View target) {
      
        mNestedScrollingParentHelper.onStopNestedScroll(target);
      
       }
      
       //先于child滾動(dòng)
      
       //前3個(gè)為輸入?yún)?shù),最后一個(gè)是輸出參數(shù)
      
       @Override
      
       public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
      
        if (showImg(dy) || hideImg(dy)) {//如果需要顯示或隱藏圖片,即需要自己(parent)滾動(dòng)
      
         scrollBy(0, -dy);//滾動(dòng)
      
         consumed[1] = dy;//告訴child我消費(fèi)了多少
      
        }
      
       }
      
       //后于child滾動(dòng)
      
       @Override
      
       public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
       }
      
      
       //返回值:是否消費(fèi)了fling
      
       @Override
      
       public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
      
        return false;
      
       }
      
       //返回值:是否消費(fèi)了fling
      
       @Override
      
       public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
      
        return false;
      
       }
       @Override
      
       public int getNestedScrollAxes() {
      
        return mNestedScrollingParentHelper.getNestedScrollAxes();
      
       }
       //下拉的時(shí)候是否要向下滾動(dòng)以顯示圖片
      
       public boolean showImg(int dy) {
      
        if (dy > 0) {
      
         if (getScrollY() > 0 && myNestedScrollChild.getScrollY() == 0) {
      
          return true;
      
         }
      
        }
      
       
      
        return false;
      
       }
      
       //上拉的時(shí)候,是否要向上滾動(dòng),隱藏圖片
      
       public boolean hideImg(int dy) {
      
        if (dy < 0) {
      
         if (getScrollY() < imgHeight) {
      
          return true;
      
         }
      
        }
      
        return false;
      
       }
      
      
       //scrollBy內(nèi)部會(huì)調(diào)用scrollTo
      
       //限制滾動(dòng)范圍
      
       @Override
      
       public void scrollTo(int x, int y) {
      
        if (y < 0) {
      
         y = 0;
      
        }
      
        if (y > imgHeight) {
      
         y = imgHeight;
      
        }
      
       
      
        super.scrollTo(x, y);
      
       }
      
      } 
      
      

      MyNestedScrollParent主要是實(shí)現(xiàn)一下功能

      ①、在onStartNestedScroll()中判斷參數(shù)target是哪一個(gè)子view以及滾動(dòng)的方向,然后決定是否要配合其進(jìn)行嵌套滾動(dòng)

      ②、在onNestedPreScroll()中獲取需要滾動(dòng)的距離,根據(jù)情況決定自己是否要進(jìn)行滾動(dòng),最后還要將自己滾動(dòng)消費(fèi)掉的距離存儲(chǔ)在consumed數(shù)組中回傳給child

      就這樣基本實(shí)現(xiàn)了,很簡(jiǎn)單有沒有,再看看我們接下來要實(shí)現(xiàn)的效果,如圖:

      深入淺析Android中的NestedScrolling滑動(dòng)機(jī)制

      關(guān)于深入淺析Android中的NestedScrolling滑動(dòng)機(jī)制問題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識(shí)。


      本文題目:深入淺析Android中的NestedScrolling滑動(dòng)機(jī)制
      文章分享:http://ef60e0e.cn/article/ipgoch.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        汾西县| 汝阳县| 崇义县| 陕西省| 东港市| 吴江市| 定陶县| 天祝| 柘荣县| 多伦县| 衡水市| 张家界市| 达尔| 泸定县| 金塔县| 渭源县| 湛江市| 金平| 兴城市| 无锡市| 航空| 常宁市| 丰都县| 清徐县| 商城县| 荆州市| 来凤县| 宣武区| 长治县| 平远县| 邳州市| 凌海市| 福海县| 元朗区| 彭州市| 疏勒县| 湖州市| 陵川县| 马关县| 平昌县| 西乡县|