ViewPager
viewpager有一个setPageTransformer(),主要是用在viewpager在滑动时的回调,第一个参数一般为true。它的参数为PageTransformer变量。
PageTransformer
它是一个接口,里面的方法只有一个transformPage(View view,float position)。参数含义分别是:当前的view,以及该view在viewpager中的位置。不同的view,position的值是不同的。
停止滑动后,显示在屏幕中的view的position为0。往左滑时,该view的position会随着滑动的移动而逐渐降低到-1;往后滑时,position会随着滑动逐渐增加到1。position的值大于1,或者小于-1,那么该position已经不可见。
viewpager会保留当前屏幕,左边及右边一共3个view。超出1,那就代表该view是右边往右,小于-1就代表该view是左边往左。示例如下:
@Override
public void transformPage(View page, float position) {
if(position < -1){//超出屏幕
page.setScaleY(1);
}else if(position < 0){//当前的左边控件 [-1,0] 越往左滑,position值越小
page.setScaleY(1-Math.abs(position));
}else if(position <=1 ){//当前的右边控件,[0,1]越往左滑,Position值越小
float value = 1-Math.abs(position);
page.setScaleY(value);
page.setScaleX(value);
page.setAlpha(value);
page.setTranslationX(page.getWidth() * -position);
}else{
page.setScaleY(1);
}
}
3d旋转
@Override
public void transformPage(View page, float position) {
if(-1 <= position && position <= 0){
page.setPivotX(page.getWidth());
page.setPivotY(page.getHeight() / 2.0f);
page.setRotationY(position * 90);
}else if(position <= 1){
page.setPivotX(0);
page.setPivotY(page.getHeight() / 2.0f);
page.setRotationY(90 * position);
}
}
这里面在设置旋转的中心点时,用的是getWidth,而不是getRight。因为getRight指的是view在它的父view中的位置,对于非第一个view来说,getRight得到的值远远大于它的右边框。因此,这里面使用getWidth才能达到左view绕右边框旋转的目的。
ViewPager的adapter
该adapter除了明着要求重写的两个方法,还需要重写
public void destroyItem(ViewGroup container, int position, Object object)<pre name="code" class="java">public Object instantiateItem(ViewGroup container, int position)
一个简单的示例为:
@Override
public int getCount() {
return 4;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View)object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
TextView t = new TextView(MainActivity.this);
t.setText(position+"");
t.setBackgroundColor(Color.BLUE);
container.addView(t);
return t;
}
OnPageChangeListener
单说onPageScrolled()方法。它的第一个参数为当前屏幕中最左边一个子View的position,从第一页滑动到第二页时值为0,从第二页滑动到第一页时,值还是0.
它的第二个参数是从0到1之间变化的。从第一页到第二页时,从0到1; 从第二页到第一页时,值从1到0 。因此,可以通过判断它的值是否大于0.5知道当前是左滑还是右滑。
示例
随着ViewPager的滑动,某一滑块还根据移动,并不是等ViewPager停止后,滑块才移动。代码如下:
public class MainActivity extends Activity {
private float mPreOffset;
private boolean isFirst = true;
private int mLastPosition;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DisplayMetrics m = new DisplayMetrics();
final View cursor = findViewById(R.id.cursor);
getWindowManager().getDefaultDisplay().getMetrics(m);
final int width = m.widthPixels/4;
final ViewPager pager = (ViewPager)findViewById(R.id.viewpager);
pager.setAdapter(new PagerAdapter() {
@Override
public int getCount() {
return 4;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View)object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
TextView t = new TextView(MainActivity.this);
t.setText(position+"");
t.setBackgroundColor(Color.BLUE);
container.addView(t);
return t;
}
});
pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
/**
* 从第一页滑动到第二页,positionOffset从0到1,position一直为0
* 从第二页滑动到第一页,position为0,positionOffset从1到0
* 也就是说position始终是屏幕左边的view
*/
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
LogUtils.e(position+"--->"+positionOffset+"--->"+positionOffsetPixels);
if(positionOffset > 0) {
if(isFirst || mLastPosition != position){
if(positionOffset > 0.5){
mPreOffset = 1;
}else{
mPreOffset = 0;
}
isFirst = false;
mLastPosition = position;
}
cursor.setTranslationX(cursor.getTranslationX()+(positionOffset - mPreOffset) * width);
mPreOffset = positionOffset;
}
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
if(state == ViewPager.SCROLL_STATE_IDLE){
isFirst = true;
}
}
});
}
}
使用isFirst是为了保证在每一次滑动时,只初始化一次mPreOffset。
通过mPreOffset与positionOffset的差值,计算出本次应该移动的距离。从第一页到第二页时,mPreOffset应该为0,相反为1。
使用mLastPosition是为了保证在极端情况下出现不正常现象。如在第二页时,开始稍微向右滑,此时mPreOffset应该是接近于0;然后往左滑,使第一页稍微出现一点,此时的positionOffset应该接近于1,这样一相减,导致了滑块在x轴上出现大幅度的移动。