0

私は実装しているこの例をモデルにした ViewPager を持っていますViewPager.PageTransformer:

public class DepthPageTransformer implements ViewPager.PageTransformer {
    private static final float MIN_SCALE = 0.75f;

    public void transformPage(View view, float position) {    
        if (position < -1) { // [-Infinity,-1)
            view.setAlpha(0);
        } else if (position <= 0) { // [-1,0]

            view.setAlpha(1);
            view.setTranslationX(0);
            view.setScaleX(1);
            view.setScaleY(1);

        } else if (position <= 1) { // (0,1]

            view.setAlpha(1 - position);
            view.setTranslationX(view.getWidth() * -position);
            float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position));
            view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);

        } else { // (1,+Infinity]
            view.setAlpha(0);
        }
    }
}

上記のリンクに示されているDepth Page Transformerアニメーションに示されているように、うまく機能します。

ただし、現在の動作方法では、右側のビューは常に左側のビューの下にあります。右にスクロールすると、下からのビューが表示されます。左にスクロールすると、現在のビューが新しいビューの下に移動し、新しいビューが上にスライドします。

私がやりたいのは、現在のビューを常に上にして、新しいビュー (左または右) を後ろ/下から表示することです。

追加してみました

view.bringToFront();

ブロックに追加しif(position <= 0)ますが、何も変わりません。私も追加しようとしました

view.bringToFront();
view.invalidate();

view.bringToFront();
((View)view.getParent()).invalidate();

すべて役に立たない。これらは、私が見つけることができる同様の SO 投稿で採用されているのと同じアプローチですが、それらはすべて、機能するという回答とコメントを受け入れています。しかし、私のものはそうではありません!

スワイプの方向に関係なく、現在のビューを常に一番上のビューにするにはどうすればよいですか?

編集 1 - 追加の詳細

コメントで述べたように、同じアニメーションを両方向に動かすには、右にスワイプするか左にスワイプするかを知る必要があります。

ViewPager には3 つのビューしかなく、この投稿VerticalViewPagerに基づいてとして表示されます。

PageTransformer 内には、次のものがあります。

    @Override
    public void transformPage(View view, float position) {

        if (position < -1) { // [-Infinity,-1)
            view.setAlpha(0);
        }
        else if(position <= 0){
            if(view == first){
                view.setAlpha(1 - Math.abs(position));
                view.setTranslationX(view.getWidth() * -position);
                view.setTranslationY(0);
                float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position));
                view.setScaleX(scaleFactor);
                view.setScaleY(scaleFactor);
            }else if(view == second){
                view.setAlpha(1);
                view.setTranslationX(view.getWidth() * -position);
                float yPosition = position * view.getHeight();
                view.setTranslationY(yPosition);
            }else if(view == third){
                // Never happen
            }
        }
        else if (position <= 1) { // [0,1]
            if(view == first){
                // Never happen
            }else if(view == second){
                view.setAlpha(1);
                view.setTranslationX(view.getWidth() * -position);
                float yPosition = position * view.getHeight();
                view.setTranslationY(yPosition);
            }else if(view == third){
                view.setAlpha(1 - position);
                view.setTranslationX(view.getWidth() * -position);
                view.setTranslationY(0);
                float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position));
                view.setScaleX(scaleFactor);
                view.setScaleY(scaleFactor);
            }
        } else { // (1,+Infinity]
            view.setAlpha(0);
        }

    }

ここfirstで、secondとはPagerAdapter 内でthird型および設定されます。View

@Override
public View instantiateItem(ViewGroup container, int position) {
    if(position == 0){
        ... stuff ...
        vvp.first = img;
        ... stuff ...
    }else if(position == 1){
        ... stuff ...
        vvp.second = img;
        ... stuff ...
    }else if(position == 2){
        ... stuff ...
        vvp.third = img;
        ... stuff ...
    }
}

一緒に少しハックされていますが、うまく機能し、私が探している機能を正確に取得します. 機能していないことを除いbringToFrontて。transformPageしかし、元の投稿のコードを使用しても、この編集のより包括的なバージョンを使用しても機能しません。

second常に一番上に表示する方法 (つまり、3 つの中央のビュー)を作成する方法がまだわかりません。ジェネリックも試しました

second.bringToFront();

メソッドの先頭にありますが、まだ何もありません。

編集2

試してみview.setZ()ましたが、次のエラーが発生しました。

java.lang.NoSuchMethodError: android.view.View.setZ

だから、その選択肢もアウトです。

編集 3 - 解決策

この問題に対する私の解決策については、以下の回答を参照してください (を使用getChildDrawingOrder)。

そうは言っても、私はまだbringToFront仕事に取り掛かることができず、あなたがそれを理解できれば、喜んであなたの答えを選択されたものとして選択します.

よろしくお願いします。

4

3 に答える 3

1

とった!同じ問題に遭遇した場合...

カスタムクラスがあります:

public class VerticalViewPager extends ViewPager

transformPageこれは、メソッドを実装するクラスと同じです。ViewPager のコンストラクター内から、次のように設定します。

setChildrenDrawingOrderEnabled(true);

これは、次のメソッドをオーバーライドするために必要です。

@Override
protected int getChildDrawingOrder(int childCount, int i) {
    switch(i){
        case 0: return 1;
        case 1: return 2;
        case 2: return 0;
    }

    return super.getChildDrawingOrder(childCount, i);
}

このメソッドを使用すると、ViewPager の子ビューが描画される順序を選択できます。ビューが 3 つしかないので、ケース 0 から 2 だけを気にする必要があります。

最後に描いたビュー(私の場合は 2 番目/中央のビュー) がトップ ビューになります。

メソッドの引数int iは、描画の繰り返しです。

for(i = 0; i < childCount; i++)

描画順序を返します。

したがって、ビューを描画する順序を選択して、それを実行してください。

これは、1 つのビューを一番上に配置する場合にのみ機能することに注意してください。3 つ以上のビューがある場合、または現在のビューを常に一番上に表示したい場合は、トップ ビューを動的に変更する別の方法を見つける必要があります。

編集 - 追加情報

をオーバーライドすると、ViewPager がオフスクリーン ビューを破棄すると、nullpointerexceptions が発生する可能getChildDrawingOrder性があります。ビューの数が少ない場合は、次を追加できます。

viewPager.setOffscreenPageLimit(2);

ここで、引数はビューの数から 1 を引いたものです。これにより、それらのビューが破棄されるのを防ぐことができます。

于 2015-11-24T05:54:31.323 に答える
0

動的なサイズを探している人のために、キットカット後のバージョンの解決策を見つけました。基本的に私がしたことは、現在の中央ビューの標高を上げることです。(私はまだロリポップ前のソリューションに取り組んでいます)

これが私のコードです。OnPageChangeListener を ViewPager に設定し、OnPageSelected メソッドで

     @Override public void onPageSelected(int position) {

      //Counter for loop
      int count = 0;
      int PAGER_LOOP_THRESHOLD = 2;
      if (position >= PAGER_LOOP_THRESHOLD) {
        count = position - PAGER_LOOP_THRESHOLD;
      }
      do {
        Fragment fragment = (Fragment) adapter.instantiateItem(pager, count);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
            && fragment.getView() != null) {

          //If it's current center position, increase view's elevation. Otherwise, we reduce elevation
          if (count == position) {
            fragment.getView().setElevation(8.0f);
          }
          else {
            fragment.getView().setElevation(0.0f);
          }
        }
        count++;
      } while (count < position + PAGER_LOOP_THRESHOLD);
    }
于 2016-06-03T10:26:20.300 に答える