ScrollView嵌套 ListView、RecyclerView、GridView 、WebView 出現(xiàn)的高度顯示問題

ScrollView-Nested-Problems點(diǎn)擊打開鏈接

解決Android中出現(xiàn)ScrollView嵌套 ListView、RecyclerView、GridView 、WebView出現(xiàn)的高度問題。

開篇語:最近開始想寫一些技術(shù)總結(jié)了,一方面分享給其他同學(xué),另一方面也作為自己的技術(shù)積累。 今天我分享的是日常遇到的問題,ScrollView組件里面嵌套GridView、WebView、ListView等本身具有滑動(dòng)的組件時(shí),所引發(fā)的高度顯示不全的問題。

對(duì)于GridView、WebView、ListView這三類組件來說,大家都知道通常情況下這三類組件本身是具有滑動(dòng)特性的,其實(shí)際占用的高度也只是屏幕內(nèi)顯示的高度,當(dāng)嵌套在ScrollView組件里時(shí)就造成了沖突。 所以解決的思路可以從其onMeasure方法入手,onMeasure方法是重寫自定義View中用到的一個(gè)非常重要的方法,onMeasure方法的作用就是計(jì)算出自定義View的寬度和高度,這個(gè)計(jì)算的過程參照父布局給出的大小,以及自己特點(diǎn)算出結(jié)果。onMeasure方法是在父視圖計(jì)算子視圖大小時(shí)被調(diào)用的,其中的細(xì)節(jié)就不在此詳細(xì)講述。

@Override?

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {??

? int mExpandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);? ? ? ?super.onMeasure(widthMeasureSpec, mExpandSpec);

}

上面方法的2個(gè)參數(shù),來自于父視圖發(fā)過來給子視圖的限制條件,這涉及到一個(gè)知識(shí)點(diǎn)MeauseSpec這個(gè)類.

一.MeasureSpec的構(gòu)成

MeasureSpec代表一個(gè)32位的int值,前倆位代表SpecMode,后30位代表SpecSize.其中:SpecMode代表測(cè)量的模式,SpecSize值在某種測(cè)量模式下的規(guī)格大小。

共有三種測(cè)量模式:

1.EXACTLY: 父容器已經(jīng)檢測(cè)出子View所需要的精確大小,這個(gè)時(shí)候view的大小即為SpecSize的大小,他對(duì)應(yīng)于布局參數(shù)中的MATCH_PARENT,或者精確大小值;

2.AT_MOST: 父容器指定了一個(gè)大小,即SpecSize,子view的大小不能超過這個(gè)SpecSize的大??;

3.UNSPECIFIED: 父容器對(duì)子View的大小沒有任何要求,子View想多大都可以。

二.如何創(chuàng)建MeasureSpec MeasureSpec內(nèi)部提供了創(chuàng)建MeasureSpec的方法:

public static int makeMeasureSpec(int size, int mode) {

? ? ? ? if (sUseBrokenMakeMeasureSpec) {

? ? ? ? ? ? return size + mode;

? ? ? ? } else {

? ? ? ? ? ? return (size & ~MODE_MASK) | (mode & MODE_MASK);

? ? ? ? }

? ? }

private static final int MODE_SHIFT = 30;

private static final int MODE_MASK = 0x3 << MODE_SHIFT; 二進(jìn)制 1100....00 32位

public static final int UNSPECIFIED = 0 << MODE_SHIFT; ? 二進(jìn)制 0000....00 32位

public static final int EXACTLY ? ? = 1 << MODE_SHIFT; ? 二進(jìn)制 0100....00 32位

public static final int AT_MOST = 2 << MODE_SHIFT; 二進(jìn)制 1000....00 32位

MeasureSpec代表一個(gè)32位的int值,前倆位代表SpecMode,后30位代表SpecSize.通過巧妙的位運(yùn)算,即可通過MeasureSpec來得到SpecSize,SpecMode.

public static int getMode(int measureSpec) {

? ? ? ? return (measureSpec & MODE_MASK);?

? ? ? } ? public static int getSize(int measureSpec) {

? ? ? ? return (measureSpec & ~MODE_MASK);

? ? }

對(duì)于RecyclerView來說,重寫onMeasure()方法就不管用了。

1.一種解決辦法是在RecyclerView的外部套上一層RelativeLayout

<RelativeLayout

? ? ? android:layout_width="match_parent"

? ? ? android:layout_height="wrap_content"

? ? ? android:descendantFocusability="blocksDescendants">

android:descendantFocusability屬性的值有三種:

beforeDescendants:viewgroup會(huì)優(yōu)先其子類控件而獲取到焦點(diǎn)

blocksDescendants:viewgroup會(huì)覆蓋子類控件而直接獲得焦點(diǎn)

afterDescendants:viewgroup只有當(dāng)其子類控件不需要獲取焦點(diǎn)時(shí)才獲取焦點(diǎn)

但是這個(gè)方案recyclerView時(shí)有卡頓的問題 原因還是滑動(dòng)沖突的問題,可以重寫LinearLayoutManager,設(shè)置讓其不可滑動(dòng),外部滑動(dòng)靠ScrollView,這樣就解決了滑動(dòng)時(shí)卡頓的問題

代碼如下: public class ScrollLinearLayoutManager extends LinearLayoutManager { private boolean isScrollEnabled = true;

? ? public ScrollLinearLayoutManager(Context context) {

? ? ? ? super(context);

? ? }

? ? public ScrollLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {

? ? ? ? super(context, orientation, reverseLayout);

? ? }

? ? public ScrollLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {

? ? ? ? super(context, attrs, defStyleAttr, defStyleRes);

? ? }

? ? public void setScrollEnabled(boolean flag) {

? ? ? ? this.isScrollEnabled = flag;

? ? }

? ? @Override

? ? public boolean canScrollVertically() {

? ? ? ? return isScrollEnabled && super.canScrollVertically();

? ? }

}

簡(jiǎn)單使用: ScrollLinearLayoutManager scrollLinearLayoutManager = new ScrollLinearLayoutManager(this);

scrollLinearLayoutManager.setScrollEnabled(false);

mRecyclerView.setLayoutManager(scrollLinearLayoutManager);

2.完美方案是這樣的:首先在xml布局中將你的ScrollView替換成android.support.v4.widget.NestedScrollView,并在java代碼中設(shè)置recyclerView.setNestedScrollingEnabled(false);

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容