2つのサイディング-いいえ、4方向

Android ViewPagerでの画面スライドに関するHabréの記事で、 ViewPagerIndicatorが複数回出会った。 4方向のスライドオプションを提供したい。







少し前までは、左、右、上下の4つの方向に画面スライドを作成する必要がありました。 インターネットでの検索で良い結果が得られなかったか、見た目がひどかったかもしれません。 結局、私は自分が必要なことをすることにしました。



ゼロから始めたのではなく、ここにあるRealViewSwitcherからの水平スライドの実装が基本でしたと言わなければなりません。

したがって、実装全体は、ViewGroupを継承するTwoDirectionsViewSwitcherクラスに配置されます。 必要な機能を実装するには、基本クラスの次のメソッドをオーバーライドするだけで十分です。



onMeasureメソッドは、将来の画面の寸法を設定します。



protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
      
      







OnLayoutは画面を表示し、実際に画面を行に分割します(行数はコンストラクターに渡されます)。



 protected void onLayout(boolean changed, int l, int t, int r, int b)
      
      







アプリケーションコンテキストが転送されるコンストラクター自体と、画面の一般的なリストを分割する必要がある行数:



 public TwoDirectionsViewSwitcher(Context context, int rows)
      
      







onTouchEvent画面タッチを処理するための次の主要なメソッド:



 public boolean onTouchEvent(MotionEvent ev)
      
      







最後に、子画面のcomputeScrollスクロールメソッド:

 public void computeScroll()
      
      







次に、クラスのいくつかの主要なメソッドについて詳しく説明します。 OnLayoutメソッド。



ここではすべてが簡単です。ネストされたループは行数で実装され、後続の画面ごとにオフセットが設定されます。



より洗練されたメソッドは、 onTouchEventスクリーンタッチハンドラーです。



ここでは、標準実装とはほとんど異なりません;さまざまなタイプのアクションが処理されます:



イベントハンドラーMotionEvent.ACTION_DOWでは、画面上の移動の開始の事実が決定され、画面の現在のXおよびY位置が設定され、スクロールの開始の兆候が設定されます。



MotionEvent.ACTION_MOVEハンドラーは、画面による変位を処理します(変位がViewConfiguration.get(getContext())メソッドによって返される値を超えた場合。GetScaledTouchSlop()値)。XおよびYに沿ったスクロール値が計算され、移動方向は軸に沿った変位の絶対値によって決定されます。



  //   X final int deltaX = (int) (mLastMotionX - x); //   Y final int deltaY = (int) (mLastMotionY - y); mLastMotionX = x; mLastMotionY = y; //  View     final int scrollX = getScrollX(); final int scrollY = getScrollY(); //   ,     if (Math.abs(deltaX) > Math.abs(deltaY) && isMoveBegin) { isMoveBegin = false; isXMove = true; isYMove = false; } else if (Math.abs(deltaX) < Math.abs(deltaY) && isMoveBegin) { isMoveBegin = false; isXMove = false; isYMove = true; } //     if (isXMove) { if (deltaX < 0) { if (scrollX > 0) { scrollBy(Math.max(-scrollX, deltaX), 0); } } else if (deltaX > 0) { final int availableToScroll = getChildAt(getChildCount() / mRows -1).getRight() - scrollX - getWidth(); if (availableToScroll > 0) { scrollBy(Math.min(availableToScroll, deltaX), 0); } } } //     else if (isYMove) { if (deltaY < 0) { if (scrollY > 0) { scrollBy(0, Math.max(-scrollY, deltaY)); } } else if (deltaY > 0) { final int availableToScroll = getChildAt(getChildCount() - 1).getBottom() - scrollY - getHeight(); if (availableToScroll > 0) { scrollBy(0, Math.min(availableToScroll, deltaY)); } } } } break;
      
      







さらに、軸に沿った直交移動のために、3つの変数isXMove、isYMove、isMoveBeginが導入されています。 最後は、MotionEvent.ACTION_DOWNを処理するときに当てはまります。



次に、いくつかのユーティリティメソッドを使用して実際に画面をスクロールします。



MotionEvent.ACTION_UPハンドラーは、画面のスクロールを完了し、作業変数をリセットします。 画面が半分以上移動した場合、次の画面にスクロールします。それ以外の場合、古い画面は元の位置に戻ります。



また、クラスのインスタンスを作成するときに、最初の画面ではなく、任意の画面に移動する必要がある瞬間についても説明したいと思います。 これを行うために、コンストラクターが作成されました。

  public TwoDirectionsViewSwitcher(Context context, int rows, int currentScreen) { super(context); mCurrentScreen = currentScreen; mRows = rows; init(); }
      
      





onMeasureメソッドは、最初の開始時に、最初に設定された位置が処理されます。

  if (mFirstLayout) { int row = mCurrentScreen / (getChildCount() / mRows); int cell = mCurrentScreen % (getChildCount() / mRows); scrollTo(cell * width, row * height); mFirstLayout = false; }
      
      





もちろん、このクラスは完全なふりをするわけではありません。たとえば、画面レイアウトを変更する処理を実装する価値があります(ランドスケープモードで正しく動作します)。私が実際に開発した機能-4つの方向に移動します。



使用例を含む完全なプロジェクトコードは、github TwoDirectionsViewSwitcherで公開されています。



All Articles