Android-VerticalViewPagerネストRecyclerViewスライド処理
6944 ワード
この会社に入る前に、垂直方向と水平方向のスライドページをめくる機能が必要だと製品が提案したが、垂直方向は次のページに引き上げるしかない.実はこの機能は以前の兄弟たちが実現したが、彼の実現方式が優雅ではないことを考慮すると、後期バージョンの反復に不利であることから、この機能を再実現した.以前の兄弟たちはRecyclerViewでViewPagerをネストする方式で処理していたが、RecyclerViewのitemは2番目から空白を表示していたが、具体的な原因は分からず、多重化に関係していると推定され、知っている友人が注意できる.ここではVerticalViewPager+RecyclerViewネスト方式を使用しており、UIの更新と再描画が容易です.外部のViewPagerとRecyclerViewは画面いっぱいでページをめくる効果があるからです.コードは多くなく、思想を理解し、イベントを明確に判断し、分割することが肝心です.
では、本題に入ります.gif図を使って、縦方向から下へスライドしてページをめくる+水平ページをめくる必要があることを明らかにしましょう.
NestViewPager.gif
次のようになります.
VerticalViewPagerを無効にする上から前のページのイベントへ
1)垂直方向のViewPagerはVerticalViewPagerで、下から上へページをめくることができます.VerticalViewPagerが上から下へスライドするジェスチャーが失効しても、dispatchTouchEventを書き換えることで、以下のように制御できます.
2)VerticalViewPager+RecyclerViewでイベント競合が発生する場合は、水平方向にスライドするイベントをRecyclerView、すなわちRecyclerView内部に渡すだけでdispatchTouchEvent()メソッド内でgetParent()を通過する.requestDisallowInterceptTouchEvent(true)は、親コントロールが親コントロールをブロックするイベントを自分で処理するように制御します.垂直方向にスライドするイベントはVerticalViewPagerに渡されます.すなわち、onInterceptTouchEvent()メソッドで直接return trueを自分の処理に渡します.
VerticalViewPagerは、垂直方向イベントをサブViewにブロックし、自分で処理します.
RecyclerView親コントロールの水平方向のイベントをサブコントロールに渡す処理を処理しない
3)このコードは私はRecyclerViewで処理することを選択していません.そのルートレイアウトに置いて、どの場所を置くかは必要に応じて決められます.以下のようにします.
以上で目的の効果が得られるので、簡単そうですね.最後にイベント分析をまとめます:1.内部RecyclerViewでdispatchTouchEvent()で水平スライドイベントを取得します. 2.外部VerticalViewPagerでonInterceptTouchEvent()で垂直方向スライドイベントを取得します. 3.外部VerticalViewPagerでは、dispatchTouchEvent()では、前のページのジェスチャーイベントをドロップダウンして処理しません.
イベント競合を解決する鍵は、イベントの配布を分析し、いつどのコントロールがどのジェスチャーを処理するかを分析することが第一の前提です.もちろん、イベントの配布についても深く理解しなければなりません.
VerticalViewPagerソースコードstackoverflowコードからgithub:NestViewPagerにアップロードされました
では、本題に入ります.gif図を使って、縦方向から下へスライドしてページをめくる+水平ページをめくる必要があることを明らかにしましょう.
NestViewPager.gif
次のようになります.
VerticalViewPagerを無効にする上から前のページのイベントへ
1)垂直方向のViewPagerはVerticalViewPagerで、下から上へページをめくることができます.VerticalViewPagerが上から下へスライドするジェスチャーが失効しても、dispatchTouchEventを書き換えることで、以下のように制御できます.
private int xDispatchLast;
private int yDispatchLast;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "xLastDown:" + xInterceptLast);
Log.d(TAG, "yLastDown:" + yInterceptLast);
xDispatchLast = (int) ev.getX();
yDispatchLast = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
final int curX = (int) ev.getX();
final int curY = (int) ev.getY();
Log.d(TAG, "curXMove:" + curX);
Log.d(TAG, "curYMove:" + curY);
int xDiff = curX - xDispatchLast;
int yDiff = curY - yDispatchLast;
int xAbsDiff = Math.abs(xDiff);
int yAbsDiff = Math.abs(yDiff);
Log.d(TAG, "xDiffMove:" + xDiff);
Log.d(TAG, "yDiffMove:" + yDiff);
if (yAbsDiff > xAbsDiff && yDiff > 0) {// , ViewPager ,
Log.d(TAG, "dispatchTouchEvent");
return true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
xDispatchLast = (int) ev.getX();
yDispatchLast = (int) ev.getY();
Log.d(TAG, "xLastUp:" + xDispatchLast);
Log.d(TAG, "yLastUp:" + yDispatchLast);
break;
}
return super.dispatchTouchEvent(ev);
}
2)VerticalViewPager+RecyclerViewでイベント競合が発生する場合は、水平方向にスライドするイベントをRecyclerView、すなわちRecyclerView内部に渡すだけでdispatchTouchEvent()メソッド内でgetParent()を通過する.requestDisallowInterceptTouchEvent(true)は、親コントロールが親コントロールをブロックするイベントを自分で処理するように制御します.垂直方向にスライドするイベントはVerticalViewPagerに渡されます.すなわち、onInterceptTouchEvent()メソッドで直接return trueを自分の処理に渡します.
VerticalViewPagerは、垂直方向イベントをサブViewにブロックし、自分で処理します.
private int xInterceptLast;
private int yInterceptLast;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "xLastDown:" + xInterceptLast);
Log.d(TAG, "yLastDown:" + yInterceptLast);
xInterceptLast = (int) ev.getX();
yInterceptLast = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
final int curX = (int) ev.getX();
final int curY = (int) ev.getY();
Log.d(TAG, "curXMove:" + curX);
Log.d(TAG, "curYMove:" + curY);
int xDiff = curX - xInterceptLast;
int yDiff = curY - yInterceptLast;
int xAbsDiff = Math.abs(xDiff);
int yAbsDiff = Math.abs(yDiff);
Log.d(TAG, "xDiffMove:" + xDiff);
Log.d(TAG, "yDiffMove:" + yDiff);
if (yAbsDiff > xAbsDiff && yDiff <= 0) {// , ViewPager , ViewPager
Log.d(TAG, "onInterceptTouchEvent");
return true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
xInterceptLast = (int) ev.getX();
yInterceptLast = (int) ev.getY();
Log.d(TAG, "xLastUp:" + xInterceptLast);
Log.d(TAG, "yLastUp:" + yInterceptLast);
break;
}
boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
swapXY(ev); // return touch coordinates to original reference frame for any child views
return intercepted;
}
RecyclerView親コントロールの水平方向のイベントをサブコントロールに渡す処理を処理しない
3)このコードは私はRecyclerViewで処理することを選択していません.そのルートレイアウトに置いて、どの場所を置くかは必要に応じて決められます.以下のようにします.
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "xLastDown:" + xLast);
Log.d(TAG, "yLastDown:" + yLast);
xLast = (int) ev.getX();
yLast = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
final int curX = (int) ev.getX();
final int curY = (int) ev.getY();
Log.d(TAG, "curXMove:" + curX);
Log.d(TAG, "curYMove:" + curY);
int xDiff = curX - xLast;
int yDiff = curY - yLast;
int xAbsDiff = Math.abs(xDiff);
int yAbsDiff = Math.abs(yDiff);
Log.d(TAG, "xDiffMove:" + xDiff);
Log.d(TAG, "yDiffMove:" + yDiff);
if (yAbsDiff < xAbsDiff || (yAbsDiff > xAbsDiff && yDiff > 0)) {//
Log.d(TAG, "requestDisallowInterceptTouchEvent");
getParent().requestDisallowInterceptTouchEvent(true);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
getParent().requestDisallowInterceptTouchEvent(false);
xLast = (int) ev.getX();
yLast = (int) ev.getY();
Log.d(TAG, "xLastUp:" + xLast);
Log.d(TAG, "yLastUp:" + yLast);
break;
}
return super.dispatchTouchEvent(ev);
}
以上で目的の効果が得られるので、簡単そうですね.最後にイベント分析をまとめます:1.内部RecyclerViewでdispatchTouchEvent()で水平スライドイベントを取得します. 2.外部VerticalViewPagerでonInterceptTouchEvent()で垂直方向スライドイベントを取得します. 3.外部VerticalViewPagerでは、dispatchTouchEvent()では、前のページのジェスチャーイベントをドロップダウンして処理しません.
イベント競合を解決する鍵は、イベントの配布を分析し、いつどのコントロールがどのジェスチャーを処理するかを分析することが第一の前提です.もちろん、イベントの配布についても深く理解しなければなりません.
VerticalViewPagerソースコードstackoverflowコードからgithub:NestViewPagerにアップロードされました