ViewGroup嵌套RecyclerView設(shè)置點擊事件無響應(yīng)的解決

在使用ViewGroup派生類(LinearLayout兑牡、RelativeLayout等)嵌套RecyclerView酵镜,給ViewGroup設(shè)置點擊事件后,你會發(fā)現(xiàn)點擊RecyclerView的部分無響應(yīng)點擊事件氏义。
比如下面的示例布局文件:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:id="@+id/ll"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <RecyclerView
            android:id="@+id/rv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>

    </LinearLayout>
</FrameLayout>

MainActivity.java文件代碼如下:

package com.axen.module.activity;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Toast;

import com.axen.module.R;

public class MainActivity extends AppCompatActivity {

    private LinearLayout ll;
    private RecyclerView rv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ll = findViewById(R.id.ll);
        rv = findViewById(R.id.rv);
        ll.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 點擊在RecyclerView的區(qū)域?qū)o法響應(yīng)點擊事件
                Toast.makeText(MainActivity.this, "我點擊了LinearLayout", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

從網(wǎng)上尋求解答究西,發(fā)現(xiàn)大部分的博客提供的解決辦法都是在父布局添加屬性android:descendantFocusability="blocksDescendants"
或者給控件設(shè)置android:focusable="false"之類的窗慎,但是經(jīng)過實踐證明這樣做沒有效果。
另外一個辦法是重寫RecyclerView的onTouchListener事件:

package com.axen.module.activity;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Toast;

import com.axen.module.R;

public class MainActivity extends AppCompatActivity {

    private LinearLayout ll;
    private RecyclerView rv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ll = findViewById(R.id.ll);
        rv = findViewById(R.id.rv);
        ll.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 點擊在RecyclerView的區(qū)域?qū)o法響應(yīng)點擊事件
                Toast.makeText(MainActivity.this, "我點擊了LinearLayout", Toast.LENGTH_SHORT).show();
            }
        });
        rv.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { 
                    Toast.makeText(MainActivity.this, "我點擊了LinearLayout", Toast.LENGTH_SHORT).show();
                }
                return false;
            }
        });
    }
}

通過此方法可以實現(xiàn)響應(yīng)點擊效果卤材,但是onTouch事件包含了許多操作遮斥,直接重寫,可能會導(dǎo)致一系列問題扇丛,因此也不推薦使用該方法术吗。
后來在閱讀稀土掘金《LinearLayout包裹RecycleView點擊事件不響應(yīng)》一文中找到了解決辦法,原來帆精,在RecyclerView的onTouchEvent和onInterceptTouchEvent事件中较屿,存在一個名為mLayoutFrozen的布爾值變量,當(dāng)這個變量的值為true時实幕,RecyclerView就不會攔截點擊事件了吝镣,下面是RecyclerView的關(guān)鍵源碼:

public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild2 {
    ....
    @Override
    public boolean onTouchEvent(MotionEvent e) {
        if (mLayoutFrozen || mIgnoreMotionEventTillDown) {
            return false;
        }
        ...
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent e) {
        if (mLayoutFrozen) {
            // When layout is frozen,  RV does not intercept the motion event.
            // A child view e.g. a button may still get the click.
            return false;
        }
      ...
    }
}

要設(shè)置mLayoutFrozen的值堤器,可通過setLayoutFrozen方法實現(xiàn):

public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild2 {
    ....
    /**
     * Enable or disable layout and scroll.  After <code>setLayoutFrozen(true)</code> is called,
     * Layout requests will be postponed until <code>setLayoutFrozen(false)</code> is called;
     * child views are not updated when RecyclerView is frozen, {@link #smoothScrollBy(int, int)},
     * {@link #scrollBy(int, int)}, {@link #scrollToPosition(int)} and
     * {@link #smoothScrollToPosition(int)} are dropped; TouchEvents and GenericMotionEvents are
     * dropped; {@link LayoutManager#onFocusSearchFailed(View, int, Recycler, State)} will not be
     * called.
     *
     * <p>
     * <code>setLayoutFrozen(true)</code> does not prevent app from directly calling {@link
     * LayoutManager#scrollToPosition(int)}, {@link LayoutManager#smoothScrollToPosition(
     * RecyclerView, State, int)}.
     * <p>
     * {@link #setAdapter(Adapter)} and {@link #swapAdapter(Adapter, boolean)} will automatically
     * stop frozen.
     * <p>
     * Note: Running ItemAnimator is not stopped automatically,  it's caller's
     * responsibility to call ItemAnimator.end().
     *
     * @param frozen   true to freeze layout and scroll, false to re-enable.
     */
    public void setLayoutFrozen(boolean frozen) {
        if (frozen != mLayoutFrozen) {
            assertNotInLayoutOrScroll("Do not setLayoutFrozen in layout or scroll");
            if (!frozen) {
                mLayoutFrozen = false;
                if (mLayoutWasDefered && mLayout != null && mAdapter != null) {
                    requestLayout();
                }
                mLayoutWasDefered = false;
            } else {
                final long now = SystemClock.uptimeMillis();
                MotionEvent cancelEvent = MotionEvent.obtain(now, now,
                        MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
                onTouchEvent(cancelEvent);
                mLayoutFrozen = true;
                mIgnoreMotionEventTillDown = true;
                stopScroll();
            }
        }
    }
}

閱讀注釋會發(fā)現(xiàn)昆庇,在使用setAdapter方法的時候,mLayoutFrozen這個變量的值會默認(rèn)設(shè)置為false:

public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild2 {
    ....
    /**
     * Set a new adapter to provide child views on demand.
     * <p>
     * When adapter is changed, all existing views are recycled back to the pool. If the pool has
     * only one adapter, it will be cleared.
     *
     * @param adapter The new adapter to set, or null to set no adapter.
     * @see #swapAdapter(Adapter, boolean)
     */
    public void setAdapter(Adapter adapter) {
        // bail out if layout is frozen
        setLayoutFrozen(false);
        setAdapterInternal(adapter, false, true);
        processDataSetCompletelyChanged(false);
        requestLayout();
    }
}

因此在setAdapter之后闸溃,調(diào)用setLayoutFrozen將mLayoutFrozen的值設(shè)置為true整吆,就能夠解決父布局事件不響應(yīng)的問題。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末辉川,一起剝皮案震驚了整個濱河市表蝙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌乓旗,老刑警劉巖府蛇,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異屿愚,居然都是意外死亡汇跨,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門妆距,熙熙樓的掌柜王于貴愁眉苦臉地迎上來穷遂,“玉大人,你說我怎么就攤上這事娱据◎胶冢” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長忌穿。 經(jīng)常有香客問我抒寂,道長,這世上最難降的妖魔是什么掠剑? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任蓬推,我火速辦了婚禮,結(jié)果婚禮上澡腾,老公的妹妹穿的比我還像新娘沸伏。我一直安慰自己,他們只是感情好动分,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布毅糟。 她就那樣靜靜地躺著,像睡著了一般澜公。 火紅的嫁衣襯著肌膚如雪姆另。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天坟乾,我揣著相機與錄音迹辐,去河邊找鬼。 笑死甚侣,一個胖子當(dāng)著我的面吹牛明吩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播殷费,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼印荔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了详羡?” 一聲冷哼從身側(cè)響起仍律,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎实柠,沒想到半個月后水泉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡窒盐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年草则,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片登钥。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡畔师,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出牧牢,到底是詐尸還是另有隱情看锉,我是刑警寧澤姿锭,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站伯铣,受9級特大地震影響呻此,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜腔寡,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一焚鲜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧放前,春花似錦忿磅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至似扔,卻和暖如春吨些,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背炒辉。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工豪墅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人黔寇。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓偶器,卻偏偏與公主長得像,于是被迫代替她去往敵國和親啡氢。 傳聞我的和親對象是個殘疾皇子状囱,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容