前言:师兄让我先试手一下完成蘑菇街index页面,在做到实现“根据图片高度动态改变ViewPager高度”时,我遇到了选择viewpager api的问题,然后自己试着对此进行了一点总结。
首先我根据师兄的提示使用了PageTransformer
这个接口,但是发现用它写出来的效果会有一些细微的bug,其本身对用户体验的影响很小,但我想试试用另外一个接口OnPageChangeListener
然后最终实现了相同的效果。
这里先对比一下两个接口内的方法
public void transformPage(View view, float position)
它只有这一个方法,如下:
这个方法的参数有两个view
和position
,这个方法中的view指的是viewpager的直接操作的view,而position指的是相对于当前页面的位置:
position取值范围(-∞,+∞)当前值大于0且正在增大,说明这个page正在向右滑,若大于0切正在减小说明正在向左滑,小于0的情况同理。
PageTransformer
这个借口是viewpager的内部类,实现这个借口的方法后,使用 :
mViewPager.setPageTransformer(true, new ZoomOutPageTransformer());
可以为每个item
设置基于position变化的效果。
由于viewpager这个viewgroup的特殊性,它只会存当前页面加左右两个页面,共三个页面,所以当我们滑动页面时,如果在transformPage
里log输出position
,我们实际上能有同时收到3个item返回的position,不过因为他们位置的不同,position的变化范围不同,因此也较容易区分。
再观察transformPage
这个方法,参数里只有view这个参数能获得当前item相对于adapter的位置,当我们要根据每个item的自身特性去做动画时,可以用ViewGroup中的getChildAt()方法来获得当前的View,用viewpager的方法getCurrentItem()来获得当前的item位于index的位置。
这个方法的的返回值是当前的“趋势页面”,简言之就是你手指离开屏幕后viewpager停留的那个页面,此方法如下:
它返值回的是一个 int的值。
这个方法返回index里a位置的view,由于viewpager只缓存三个页面,所以单数一般不会大于2,若要取当前页面,则分情况:
a=0:getChildAt(0);
a>0: getChildAt(1);
此接口内有三个方法
1.public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
2.public void onPageSelected(int position);
3.public void onPageScrollStateChanged(int state);
其中第一个方法所提供的参数最为丰富
第一个参数,position
,代表当前正在显示的第一个页面的索引,如果positionOffset不等于0,那么第position+1个页面将被显示。
第二个参数,positionOffset
,代表position页面的偏移,取值范围是[0,1)。这是一个偏移百分比,类似于transformPage()中的position,但是有区别。
第三个参数,positionOffsetPixels
,和第二个意义差不多,只不过单位是像素,偏移的像素值。
当我用log输出position 和getCurrentItem()的值时,发现如下:
上图是我在向右滑动ViewPager时log出的内容:可以发现一个规律:getCurrentItem()的返回值变为1时,position还是0。
上图是我在向左滑动ViewPager时log出的内容:position是0时,getCurrentItem()的返回值还是1,后变为0。
即,getCurrentItem()的返回值是当你手指离开屏幕时会做一判断,页面“即将“停留在第几页,则手指离开的一瞬间返回值为该页的索引。position则是当你向左滑动时,开始滑动的一瞬间就会将position
置为(滑动前position)-1
;向右滑动则会当页面完全填充viewpager时将position
置为(滑动前position)+1
。
下面的代码是我实现能屈能伸ViewPager使用的OnPageChangeListener接口:
ViewPager.OnPageChangeListener listener = new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
Log.e("---viewpager", "position:" + position + "--getCurrentItem:" + mViewPager.getCurrentItem());
if (mViewPager.getChildAt(1) != null) {
// ((RelativeLayout) mViewPager.getChildAt(1)).getChildAt(0).getHeight();
LinearLayout.LayoutParams ls = (LinearLayout.LayoutParams) mViewPager.getLayoutParams();
ls.height = (int) (heights[position] - (Math.abs(positionOffset) * (heights[position]
- heights[position + 1])));
mViewPager.setLayoutParams(ls);
float sc = positionOffset * ((float) heights[position + 1] / (float) heights[position] - 1) + 1;
if (position < mImageViews.size() - 1) {
if (heights[position] < heights[position + 1]) {
float scale = ((float) ls.height) / heights[position];
mImageViews.get(position).setScaleX(scale);
mImageViews.get(position).setScaleY(1);
scale = heights[position + 1] / (float) ls.height;
mImageViews.get(position + 1).setScaleX(1);
mImageViews.get(position + 1).setScaleY(scale);
// mImageViews.get(position + 1).getDrawable().setBounds(new Rect(0,top,ls.width,bottom));
} else {
float scale = ((float) ls.height) / heights[position + 1];
mImageViews.get(position + 1).setScaleX(scale);
mImageViews.get(position + 1).setScaleY(1);
scale = heights[position] / (float) ls.height;
mImageViews.get(position).setScaleX(1);
mImageViews.get(position).setScaleY(scale);
// mImageViews.get(position).getDrawable().setBounds(new Rect(0,top,ls.width,bottom));
}
}
//
}
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
};
总结:根据上面的分析,我们应该可以得出胡结论:当我们需求的viewpager的变化与当面page的属性无关(即无论当前是第几个页面我们总是做相同的变换)时用PageTransformer较方便;当viewpager的变化与当前page有关时用
OnPageChangeListener较方便;