最近有用到ViewPager的翻页动画,结合无限循环后,发现有一些坑需要填,这里就稍微整理下
先建一个Activity,很简单 只有4个按钮,分别对应四个效果,前两个为非无限循环模式,后两个为伪无限循环模式(坑就是在这里,稍后说明), 先贴代码
package com.example.viewpagertransformer;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.RotatePagerTransformer).setOnClickListener(this);
findViewById(R.id.ZoomPagerTransformer).setOnClickListener(this);
findViewById(R.id.LoopRotatePagerTransformer).setOnClickListener(this);
findViewById(R.id.LoopZoomPagerTransformer).setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.RotatePagerTransformer:
RotatePagerTransformer();
break;
case R.id.ZoomPagerTransformer:
ZoomPagerTransformer();
break;
case R.id.LoopRotatePagerTransformer:
LoopRotatePagerTransformer();
break;
case R.id.LoopZoomPagerTransformer:
LoopZoomPagerTransformer();
break;
}
}
/**
* 旋转式翻页
*/
private void RotatePagerTransformer() {
startActivity(new Intent(this, ViewPagerTransformerActivity.class));
}
/**
* 缩放式翻页
*/
private void ZoomPagerTransformer() {
startActivity(new Intent(this, ViewPagerTransformerActivity.class).putExtra("type", 1));
}
/**
* 循环旋转式翻页
*/
private void LoopRotatePagerTransformer() {
startActivity(new Intent(this, ViewPagerTransformerActivity.class).putExtra("type", 2));
}
/**
* 循环缩放式翻页
*/
private void LoopZoomPagerTransformer() {
startActivity(new Intent(this, ViewPagerTransformerActivity.class).putExtra("type", 3));
}
}
对应布局文档
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<Button
android:id="@+id/RotatePagerTransformer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="旋转式翻页" />
<Button
android:id="@+id/ZoomPagerTransformer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="缩放式翻页" />
<Button
android:id="@+id/LoopRotatePagerTransformer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="循环旋转式翻页" />
<Button
android:id="@+id/LoopZoomPagerTransformer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="循环缩放式翻页" />
</LinearLayout>
很简单 4个按钮 对应4个翻页效果 , 再贴出动效的activity ,这里为了节省代码量 就整合在一起了 ,有注释说明
package com.example.viewpagertransformer;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
/**
* @author: xiewenliang
* @Filename:
* @Description:
* @Copyright: Copyright (c) 2017 Tuandai Inc. All rights reserved.
* @date: 2017/4/12 10:24
*/
public class ViewPagerTransformerActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final int type = getIntent().getIntExtra("type", 0);
setContentView(R.layout.viewpager_transformer_layout);
ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
viewPager.setPageTransformer(true, getPageTransformer());
viewPager.setOffscreenPageLimit(6);
viewPager.setAdapter(new PagerAdapter() {
@Override
public int getCount() {
return type > 1 ? Integer.MAX_VALUE : 20;//type大余1 为伪无限循环
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view.equals(object);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView imageView = new ImageView(container.getContext());
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getResources().getDimensionPixelOffset(R.dimen.dp_100));
imageView.setLayoutParams(lp);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setAdjustViewBounds(true);
imageView.setImageResource(getResId(position));
container.addView(imageView);
return imageView;
}
private int getResId(int position) {
switch (position % 5 + 1) {
case 1:
return R.drawable.p001;
case 2:
return R.drawable.p002;
case 3:
return R.drawable.p003;
case 4:
return R.drawable.p004;
case 5:
return R.drawable.p005;
default:
return R.drawable.p001;
}
}
});
if (type > 1) {
viewPager.setCurrentItem(Integer.MAX_VALUE / 2);
}
}
private ViewPager.PageTransformer getPageTransformer() {
int type = getIntent().getIntExtra("type", 0);
ViewPager.PageTransformer pageTransformer;
if (type == 0 || type == 2) {
// type为0 或者2 为上下翻页动画
pageTransformer = new ViewPager.PageTransformer() {
private float margin = getResources().getDimension(R.dimen.dp_10);
@Override
public void transformPage(View page, float position) {
page.setTranslationY(-position * margin);
if (position >= -1.0f && position <= 0.0f) {
// 控制左侧滑入或者划出View相对X坐标为0
page.setTranslationX(-page.getWidth() * (position));
// 旋转
page.setPivotX(0);
page.setPivotY(0);
page.setRotation(-90f * position);
} else if (position > 0.0f) {
// 控制右侧滑入或者划出控制View相对X坐标为0
page.setTranslationX(-page.getWidth() * (position));
page.setPivotX(0);
page.setPivotY(0);
page.setRotation(0f);
} else {
// 控制左侧其它缓存View旋转状态固定
page.setPivotX(0);
page.setPivotY(0);
page.setRotation(90f);
}
}
};
} else {
// type 为1或者3为缩放翻页动画
pageTransformer = new ViewPager.PageTransformer() {
@Override
public void transformPage(View page, float position) {
if (position >= -1.0f && position <= 0.0f) {
// 控制左侧滑入或者划出View缩放比例
page.setScaleX(1 + position * 0.1f);
page.setScaleY(1 + position * 0.2f);
} else if (position > 0.0f && position <= 1.0f) {
// 控制右侧滑入或者划出View缩放比例
page.setScaleX(1 - position * 0.1f);
page.setScaleY(1 - position * 0.2f);
} else {
// 控制其它View缩放比例
page.setScaleX(0.9f);
page.setScaleY(0.8f);
}
}
};
}
return pageTransformer;
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:gravity="center"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="30dp" />
</LinearLayout>
本类 关键代码就在于获取PageTransformer动效对象,该对象中,关键就再于position的值的范围
当position在-1到0之间 代表的就是 向左滑动viewpager时 左侧滑出的那个Pager 或者向右滑动ViewPager时 左侧滑入的那个pager,
当position在0到1之间 代表的就是 向左滑动viewpager时 右侧滑入的那个pager 或者向右滑动viewpager时 右侧滑出的那个pager,
当position小于1 代表的是当前pager的左侧pager 当 position大于1时代表的就是当前viewpager右侧范围的pager (都需排除正在滑入和滑出的两个pager)
搞清楚了这些position代表的含义,自定义动画就会简单很多了,
这里还有一点也需要说明下 关于pager相对位置问题,正常情况下 pager的X轴坐标会随着滑动 实时变化,在做一些动画需求的时候 需要固定住pager在X轴的位置 使每个pager不再按照顺序在X轴平铺开来,而是要重叠起来,就比如本Demo的第一种效果,旋转翻页式效果 ,这时可以使用page.setTranslationX(-page.getWidth() * (position))来抵消pager在横向位置的移动 , 好了 下面贴上前两种效果的图片
接下来说说遇到的坑, 在做viewpager无限循环的时候 有两种模式 ,第一种模式 是在首尾各添加两张图片(具体的大家自行搜索),排列顺序大改就是 34123412 实际如果向左滑动 到顺序第二张 即4这张 这时 会主动跳转到 倒数第3张 也是4这张 如果是向左滑动到倒数第二张 即1这张 会主动跳转到顺序第3张 从而达到伪无限循环模式
第二种模式 也就是我上面用到的模式 定义item为整型最大值 定位到折中点,实现伪无限循环
这里 遇到的坑就是第一种模式, 该模式下 会出现直接跳转 达到无限循环 ,直接跳转时 由于之前的pager已经被回收 会造成左右pager以及当前pager直接重构 从而不执行自定义动画PageTransformer(该动画 只有在滑动,或者setCurrentItem(positon,true)第二个参数为true的时候才会执行),也就造成pager页面直接按照原始值(未缩放或者平移之类的动画效果)显示,目前没有很有效的办法, 所以这里可以考虑第二种无限循环模式