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);
        }
    }
}

并且效果很好,正如上面链接中的深度页面转换器动画所示。

但是,它目前的工作方式是右边的视图总是低于左边的视图。当您向右滚动时,视图来自下方。向左滚动使当前视图位于新视图下方,新视图滑入顶部。

我想做的是让当前视图始终位于顶部,并让新视图(左或右)从后面/下面进入。

我试过添加

view.bringToFront();

if(position <= 0)块,但没有任何变化。我也试过添加

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

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

一切都无济于事。这些与我能找到的类似 SO 帖子所采用的方法相同,但它们都接受了答案和评论,说它们有效。但我的没有!

无论滑动方向如何,如何让当前视图始终成为最顶层视图?

编辑 1 - 附加细节

正如评论中提到的,我需要知道是否向右或向左滑动以获得相同的动画。

ViewPager 只有三个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和是PagerAdapterthird中的类型和设置: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(即三个的中间视图)始终位于顶部。我什至尝试了一个通用的

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 的子视图的绘制顺序。由于我只有三个视图,所以我只需要担心案例 0-2。

无论您最后绘制哪个视图(在我的情况下,第二个/中间视图),都将是顶视图。

方法参数int i是绘图迭代,它去

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

并返回绘图顺序。

因此,只需选择您希望绘制视图的顺序,然后就可以了。

请注意,这只适用于将一个视图放在顶部。如果您有三个以上的视图,或者总是希望当前视图位于顶部,则必须找到其他方法来动态更改顶视图。

编辑 - 附加信息

如果您覆盖,如果您的ViewPager破坏了屏幕外视图getChildDrawingOrder,您可能会收到nullpointerexceptions。如果视图数量较少,可以添加:

viewPager.setOffscreenPageLimit(2);

其中参数是您拥有的视图数,减 1。这将防止这些视图被破坏。

于 2015-11-24T05:54:31.323 回答
0

你可以设置:

mViewPager.setPageTransformer(false, new DepthPageTransformer());
于 2017-07-20T05:39:11.000 回答
0

对于那些正在寻找动态尺寸的人,我已经找到了后 KitKat 版本的解决方案。基本上我所做的是增加当前中心视图的高度。(我仍在为棒棒糖前的解决方案工作)

这是我的代码,将 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 回答