我在this示例之后建立了一个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();
一切都无济于事。我可以找到similar SO posts所采用的相同方法,但所有这些方法都接受了答案和评论,说它们有效。但我的不是!
如何将当前视图始终作为最顶层视图,无论滑动方向如何?
编辑1 - 附加详细信息
正如评论中所提到的,我需要知道是向左还是向左滑动以获得同样的动画。
ViewPager只有三个视图,它们显示为基于this帖子的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
和third
的类型为View
并设置在PagerAdapter中:
@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
工作,并且如果你能弄明白的话,我会乐意选择你的答案。
提前再次感谢。
答案 0 :(得分: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++)
并返回绘图顺序。
因此,只需选择您希望绘制视图的顺序,然后选择它。
请注意,这仅适用于将一个视图置于顶部。如果您有三个以上的观看次数,或者总是希望当前观看次数最多,那么您必须找到一些其他方式来动态更改顶部视图。
编辑 - 附加信息
如果您覆盖getChildDrawingOrder
,则可能会在ViewPager破坏屏幕外视图时收到 nullpointerexceptions 。如果您的观看次数很少,可以添加:
viewPager.setOffscreenPageLimit(2);
其中参数是您拥有的视图数量减去1.这将防止这些视图被破坏。
答案 1 :(得分: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);
}
答案 2 :(得分:0)
你可以设置:
mViewPager.setPageTransformer(false, new DepthPageTransformer());