三个男躁一个女,国精产品一区一手机的秘密,麦子交换系列最经典十句话,欧美 国产 综合 欧美 视频

          1. <cite id="c4hlc"><rp id="c4hlc"><form id="c4hlc"></form></rp></cite>

                • 登錄注冊寫文章
                  首頁下載APP會員IT技術

                  ScrollView嵌套ScrollView的滑動沖突

                  HWilliamgo

                  ScrollView嵌套ScrollView的滑動沖突

                  結論: 在自定義控件中如下重寫onInterceptTouchEvent就告訴所有父View:不要攔截事件,讓我消費?。?/strong>

                      @Override
                      public boolean onInterceptTouchEvent(MotionEvent ev) {
                          getParent().requestDisallowInterceptTouchEvent(true);
                          return super.onInterceptTouchEvent(ev);
                      }
                  

                  這是一個從源碼角度分析滑動沖突的原因
                  以及在源碼中理解為何能解決滑動沖突

                  這是MainActivity主界面的布局內容:



                  xml:

                  <?xml version="1.0" encoding="utf-8"?>
                  <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
                      xmlns:app="http://schemas.android.com/apk/res-auto"
                      xmlns:tools="http://schemas.android.com/tools"
                      android:layout_width="match_parent"
                      android:layout_height="match_parent"
                      tools:context="com.solory.learnview.MainActivity">
                      <LinearLayout
                          android:layout_width="match_parent"
                          android:layout_height="wrap_content"
                          android:orientation="vertical">
                          <Button
                              android:id="@+id/btn"
                              android:layout_width="wrap_content"
                              android:layout_height="wrap_content"
                             android:layout_margin="8dp" />
                          <ImageView
                              android:id="@+id/imageView"
                              android:layout_width="105dp"
                              android:layout_height="86dp"
                              android:layout_margin="8dp"
                              app:srcCompat="@mipmap/ic_launcher_round" />
                          <TextView
                              android:layout_width="wrap_content"
                              android:layout_height="wrap_content"
                              android:text="@string/article_1"
                              android:textSize="36sp" />
                          <ScrollView
                              android:layout_width="match_parent"
                              android:layout_height="80dp"
                              android:background="@color/colorPrimary">
                              <TextView
                                  android:layout_width="match_parent"
                                  android:layout_height="wrap_content"
                                  android:text="@string/article_2" />
                          </ScrollView>
                      </LinearLayout>
                  </ScrollView>
                  

                  MainActivity不用動。

                  跑起來:

                  外面的ScrollView正常滑動,但是里面的那個ScrollView動不了。

                  直接給出解決方案再看如何解決:

                  新建一個類繼承ScrollView

                  public class MyScrollView extends ScrollView {
                      public MyScrollView(Context context) {
                          this(context,null);
                      }
                      public MyScrollView(Context context, AttributeSet attrs) {
                          this(context, attrs,0);
                      }
                      public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
                          super(context, attrs, defStyleAttr);
                      }
                      @Override
                      public boolean onInterceptTouchEvent(MotionEvent ev) {
                          //關鍵點在這 
                          getParent().requestDisallowInterceptTouchEvent(true);
                          return super.onInterceptTouchEvent(ev);
                      }
                  }
                  

                  buildProject,然后在xml中將里面的ScrollView修改成這個MyScrollView。

                  ...
                  <com.solory.learnview.MyScrollView
                      android:layout_width="match_parent"
                      android:layout_height="80dp"
                      android:background="@color/colorPrimary">
                      <TextView
                          android:layout_width="match_parent"
                          android:layout_height="wrap_content"
                          android:text="@string/article_2" />
                  </com.solory.learnview.MyScrollView>
                  ...
                  

                  跑起來:

                  問題解決。

                  那么現在研究為什么,為什么在重寫的onInterceptTouchEvent(MotionEvent ev)中神奇的一句代碼
                  getParent().requestDisallowInterceptTouchEvent(true);就把問題解決了?

                  好了。跟著我的思路來。

                  • 先看ScollView源碼中的onInterceptTouchEvent:

                     @Override
                    public boolean onInterceptTouchEvent(MotionEvent ev) {
                        /*
                         * 這個方法決定了我們是否要攔截這個事件。
                         * 如果我們返回true, onMotionEvent方法將被調用,
                         * 我們將在那執行實際的滾動操作。
                         */
                    
                        /*
                        * 最常見的情況:用戶在拖拽中。
                        * 他在動他的手指。我們想要截取這個
                        * 事件.
                        */
                        final int action = ev.getAction();
                        if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {
                            return true;
                        }
                    
                        if (super.onInterceptTouchEvent(ev)) {
                            return true;
                        }
                    
                        /*
                         * 如果我們不能滾動,不要試圖截取觸摸。
                         */
                        if (getScrollY() == 0 && !canScrollVertically(1)) {
                            return false;
                        }
                        ...
                        ...
                        ...
                    

                    清晰明了,干凈簡單,后面還有一大段代碼,就不放了。這里一進來就是一個判斷,如果進來的是ACTION_MOVE, 那么直接返回true,直接攔截,那么后面就沒他的子View什么事了(不懂的話去看一下ViewGroup的dispatchTouchEvent方法),event被傳入他自己的onTouchEvent中去進行滾動操作了。

                  • 那么我們一開始內部的ScrollView滑動沒有響應的原因就是,那時候手指是在滑動的,一直不斷傳入ACTION_MOVE, 所以event一直被外部的ScrollView在如上的操作中攔截了。

                  • 意思就是只要你手指在ScrollView上滑動,ScrollView內部的子View就永遠接收不到任何事件,就是永遠無響應。


                  沖突的原因明白了,現在看如何解決的

                  • 回頭看MyScrollView是如何解決的:

                    @Override
                    public boolean onInterceptTouchEvent(MotionEvent ev) {
                        getParent().requestDisallowInterceptTouchEvent(true);
                        return super.onInterceptTouchEvent(ev);
                    }
                    

                    意思就是取得父類,然后請求父類不攔截TouchEvent的意思。

                    首先getParent就是返回父類,在這里是返回的那個LinearLayout,然后點requestDisallowInterceptTouchEvent進去看,發現是一個叫做ViewParent的接口中的抽象方法,


                    注釋的英文:

                    當一個子View不想要他的父View和它的祖先View們攔截觸摸事件的時候。調用該方法
                    他的父View應該將該方法接著向上傳遞給每一個祖先View們。
                    
                  • 抽象方法的話,看一下是誰實現了,因為繼承的ScrollView,所以先看對應的ScrollView中的實現

                    //-----ScrollView中
                        @Override
                    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
                        if (disallowIntercept) {
                        //我也不知道這個方法干嘛的,反正不影響整體思路,先跳過。
                            recycleVelocityTracker();
                        }
                        //無論如何,都會執行父類的該方法。
                        super.requestDisallowInterceptTouchEvent(disallowIntercept);
                    }
                    
                  • 那么我們查看父類中的實現,ViewGroup中:

                    //-----ViewGroup中
                        @Override
                    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
                    
                        if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
                            // We're already in this state, assume our ancestors are too
                            return;
                        }
                    
                        if (disallowIntercept) {
                            mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
                        } else {
                            mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
                        }
                    
                        // Pass it up to our parent
                        if (mParent != null) {
                            mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
                        }
                    }
                    

                    意思就是將自己的FLAG更改,變成disallowIntercept,并且遞歸,只要有父View, 就把父View的FLAG同樣設置。

                  • 大意為,設置了這個方法,MyScrollView就通過遞歸,告訴了他的父View和向上的所有祖先View:統統不要攔截事件!交給我來!

                  • 那這個FLAG是在哪里發揮作用?當然是在ViewGroup的dispatchTouchEvent(MotionEvent event)內部,并且用一個if條件先于onInterceptMotionEvent(MotionEvent event)來判斷
                    圖片為證:


                  摸了摸老夫的胡須,嗯...,說的真好啊~

                  但是!

                  //-----MyScrollView中
                  @Override
                      public boolean onInterceptTouchEvent(MotionEvent ev) {
                          getParent().requestDisallowInterceptTouchEvent(true);
                          return super.onInterceptTouchEvent(ev);
                      }
                  

                  這段代碼的getParent().requestDisallowInterceptTouchEvent(true);能執行到的前提是MyScrollView能執行onInterceptTouchEvent,也就是能執行dispatchTouchEvent,可是事件早都被外層的ScrollView攔截了,你還怎么獲取父類然后請求不要攔截TouchEvent?
                  當時我在這里思考了蠻久的, 那么我們返回到ScrollView的onInterceptTouchEvent里去看吧

                       @Override
                      public boolean onInterceptTouchEvent(MotionEvent ev) {
                          final int action = ev.getAction();
                          if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {
                              return true;
                          }
                          if (super.onInterceptTouchEvent(ev)) {
                              return true;
                          }
                          if (getScrollY() == 0 && !canScrollVertically(1)) {
                              return false;
                          }
                          ...
                          ...
                          ...
                  

                  他只攔截ACTION_MOVE,不攔截ACTION_DOWN,所以當ACTION_DOWN的那一次事件還是可以傳到下面的子View去的,而利用這一點,MyScrollView利用第一次觸碰那唯一的一次event,將他FLAG給改了,事件就可以順利地傳遞到MyScrollView了~

                  總結:

                  • 在自定義控件中重寫onInterceptTouchEvent就告訴所有父View:不要攔截事件,讓我消費??!
                    @Override
                    public boolean onInterceptTouchEvent(MotionEvent ev) {
                        getParent().requestDisallowInterceptTouchEvent(true);
                        return super.onInterceptTouchEvent(ev);
                    }
                    
                  ?著作權歸作者所有,轉載或內容合作請聯系作者
                  平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

                  推薦閱讀更多精彩內容

                  • Android View的事件分發機制與滑動沖突解決方案
                    在Android開發中,如果是一些簡單的布局,都很容易搞定,但是一旦涉及到復雜的頁面,特別是為了兼容小屏手機而使用...
                    閑庭閱讀 3,572評論 0贊 16
                  • <<Android 開發藝術探索>> Chapter 3
                    View的事件體系 View的基礎 view位置參數View的位置主要由它的四個頂點來決定,分別對應于View的四...
                    MZzF2HC閱讀 530評論 0贊 2
                  • EditText與scrollview的滑動沖突
                    ScrollView為什么會出現嵌套EditText出現滑動事件沖突呢?相信你會有這種疑問,我們來看這么一種情況:...
                    wintersweett閱讀 1,412評論 0贊 0
                  • Android Touch事件分發機制詳解之由點擊引發的戰爭
                    更多分享:http://www.cherylgood.cn 之前我們在Scroller的使用詳解中,在onMeas...
                    Angels_安杰閱讀 3,137評論 3贊 10
                  • Android滑動沖突解決方式(下拉刷新上拉加載更多,適配RecyclerView/ListV...
                    一、Android事件的分發機制 這里需要了解下Andorid事件的分發機制。事件分發一般是針對一組事件,即ACT...
                    huisonma閱讀 2,356評論 0贊 1
                  評論19
                  贊42
                  42贊43贊
                  贊賞
                  手機看全文

                  感谢您访问我们的网站,您可能还对以下资源感兴趣:

                  三个男躁一个女
                  久久久久久久精品99国产国产精 荡货夹的这么紧欠c调教视频 成人做爰黄aa片啪啪声 少妇高潮久久久久久精品一
                  主站蜘蛛池模板: 丹寨县| 昭觉县| 湘西| 定襄县| 新干县| 江阴市| 锡林郭勒盟| 长宁区| 红桥区| 丰台区| 蚌埠市| 樟树市| 巴东县| 太湖县| 牡丹江市| 桦甸市| 涿州市| 辛集市| 财经| 玛多县| 长寿区| 江永县| 常熟市| 靖州| 汝城县| 夏河县| 蕲春县| 巨野县| 葫芦岛市| 刚察县| 桓台县| 抚顺市| 浦北县| 龙江县| 温宿县| 台南县| 辰溪县| 临泽县| 高唐县| 阜新| 天长市|
                  <thead id="ffuqh"></thead>

                • <cite id="ffuqh"><track id="ffuqh"></track></cite>

                  1. <sub id="ffuqh"></sub>
                    <legend id="ffuqh"><track id="ffuqh"></track></legend>
                    <blockquote id="ffuqh"></blockquote>