2018-03-14 ScrollViewネストされたRecyclerViewの表示とスライドの問題を解決
3948 ワード
変換:https://segmentfault.com/a/1190000011553735
プロジェクトでは、ScrollViewに1つ以上のRecyclerViewを埋め込む必要があることがよくあります.このアプローチは通常、次のような問題を引き起こします.ページスライドカートン ScrollView高さ表示異常 RecyclerViewコンテンツ表示不全 本稿では,上記の問題を多様な方法でそれぞれ解決する.
スライドカートンソリューション
スライドカートンのみの問題がある場合は、次の2つの簡単な方法で迅速に解決できます.
RecyclerViewの内部メソッドの利用
ここで、setHasFixedSize(true)法は、RecyclerViewがadapterの変化の影響を受けずに自身のsizeを固定できるようにする.一方、setNestedScrollingeEnabled(false)メソッドは、RecyclerView内部NestedScrollingChildHelperオブジェクトのsetNestedScrollingeEnabled(false)メソッドをさらに呼び出し、以下のようにします.
さらに、NestedScrollingChildHelperオブジェクトは、以下のようにしてRecyclerViewのネストされたスライド特性をオフにする.
これにより、RecyclerView自身のスライドが制限され、ページ全体のスライドはScrolViewのみで実現され、スライドカートンの問題を解決することができる
LayoutManagerの書き換え
これにより、RecyclerViewの垂直スライドは常にfalseに戻り、同様に自身のスライドを制限することを目的とする
総合的なソリューション
上記の3つの問題を総合的に解決する必要がある場合、以下のような方法を採用することができる.
LinearLayout/RelativeLayoutの挿入
既存のレイアウトにLinearLayout/RelativeLayoutを挿入し、次のレイアウトを形成します.
[画像のアップロードに失敗しました...(image-80 f 23 e-152118125734)]
LayoutManagerの書き換え
この方法の核心思想は,LayoutManagerにおけるonMeasure()メソッドを書き換えることによって,すなわち
RecyclerViewの高さの計算を再実現し、ScrolViewで正確な高さを表現できるようにします.具体的な書き換え方法はこの記事を参考にしてください.
http://www.cnblogs.com/tianzh...
ScrollViewの書き換え
この方法の核心思想は、ScrollViewのonInterceptTouchEvent(MotionEvent ev)メソッドを書き換えることによって、スライドイベントをブロックし、スライドイベントがRecyclerViewに直接伝達されるようにすることであり、具体的な書き換え方法は以下のように参照される.
実際には、ScrolViewにネストされたRecyclerViewによって発生する一連の問題を解決する方法はいくつかありますが、上記の解決方法では、RecyclerViewがページロード中にすべてのコンテンツを一度に表示するため、RecyclerViewのエントリが多すぎると、アプリケーション全体の実行効率に影響を与えます.これに基づいて、この場合、ScrolViewネストされたRecyclerViewのレイアウト方式をできるだけ避ける必要があります.
プロジェクトでは、ScrollViewに1つ以上のRecyclerViewを埋め込む必要があることがよくあります.このアプローチは通常、次のような問題を引き起こします.
スライドカートンソリューション
スライドカートンのみの問題がある場合は、次の2つの簡単な方法で迅速に解決できます.
RecyclerViewの内部メソッドの利用
recyclerView.setHasFixedSize(true);
recyclerView.setNestedScrollingEnabled(false);
ここで、setHasFixedSize(true)法は、RecyclerViewがadapterの変化の影響を受けずに自身のsizeを固定できるようにする.一方、setNestedScrollingeEnabled(false)メソッドは、RecyclerView内部NestedScrollingChildHelperオブジェクトのsetNestedScrollingeEnabled(false)メソッドをさらに呼び出し、以下のようにします.
public void setNestedScrollingEnabled(boolean enabled) {
getScrollingChildHelper().setNestedScrollingEnabled(enabled);
}
さらに、NestedScrollingChildHelperオブジェクトは、以下のようにしてRecyclerViewのネストされたスライド特性をオフにする.
public void setNestedScrollingEnabled(boolean enabled) {
if (mIsNestedScrollingEnabled) {
ViewCompat.stopNestedScroll(mView);
}
mIsNestedScrollingEnabled = enabled;
}
これにより、RecyclerView自身のスライドが制限され、ページ全体のスライドはScrolViewのみで実現され、スライドカートンの問題を解決することができる
LayoutManagerの書き換え
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this) {
@Override
public boolean canScrollVertically() {
return false;
}
};
これにより、RecyclerViewの垂直スライドは常にfalseに戻り、同様に自身のスライドを制限することを目的とする
総合的なソリューション
上記の3つの問題を総合的に解決する必要がある場合、以下のような方法を採用することができる.
LinearLayout/RelativeLayoutの挿入
既存のレイアウトにLinearLayout/RelativeLayoutを挿入し、次のレイアウトを形成します.
[画像のアップロードに失敗しました...(image-80 f 23 e-152118125734)]
LayoutManagerの書き換え
この方法の核心思想は,LayoutManagerにおけるonMeasure()メソッドを書き換えることによって,すなわち
@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
super.onMeasure(recycler, state, widthSpec, heightSpec);
}
RecyclerViewの高さの計算を再実現し、ScrolViewで正確な高さを表現できるようにします.具体的な書き換え方法はこの記事を参考にしてください.
http://www.cnblogs.com/tianzh...
ScrollViewの書き換え
この方法の核心思想は、ScrollViewのonInterceptTouchEvent(MotionEvent ev)メソッドを書き換えることによって、スライドイベントをブロックし、スライドイベントがRecyclerViewに直接伝達されるようにすることであり、具体的な書き換え方法は以下のように参照される.
/**
* Created by YH on 2017/10/10.
*/
public class RecyclerScrollView extends ScrollView {
private int slop;
private int touch;
public RecyclerScrollView(Context context) {
super(context);
setSlop(context);
}
public RecyclerScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
setSlop(context);
}
public RecyclerScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setSlop(context);
}
/**
* intercept
* @param ev
* @return true: onMotionEvent() ,
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// touch
touch = (int) ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
// slop , true
if (Math.abs((int) ev.getRawY() - touch) > slop) return true;
break;
}
return super.onInterceptTouchEvent(ev);
}
/**
* context touch slop ( , )
* @param context ScrollView context
*/
private void setSlop(Context context) {
slop = ViewConfiguration.get(context).getScaledTouchSlop();
}
}
実際には、ScrolViewにネストされたRecyclerViewによって発生する一連の問題を解決する方法はいくつかありますが、上記の解決方法では、RecyclerViewがページロード中にすべてのコンテンツを一度に表示するため、RecyclerViewのエントリが多すぎると、アプリケーション全体の実行効率に影響を与えます.これに基づいて、この場合、ScrolViewネストされたRecyclerViewのレイアウト方式をできるだけ避ける必要があります.