Unity3D特效百例 | 案例项目实战源码 | Android-Unity实战问题汇总 |
---|---|---|
游戏脚本-辅助自动化 | Android控件全解手册 | 再战Android系列 |
Scratch编程案例 | 软考全系列 | Unity3D学习专栏 |
蓝桥系列 | ChatGPT和AIGC |
专注于Android/Unity和各种游戏开发技巧,以及各种资源分享(网站、工具、素材、源码、游戏等)
有什么需要欢迎底部卡片私我,交流让学习不再孤单。
你是不是觉得 ViewPager 默认的切换效果有些平淡?其实,我们可以定制 ViewPager 的页面切换效果。定制 ViewPager 的页面切换效果,只需用到 ViewPager 的一个方法setPageTransformer(boolean reverseDrawingOrder, @Nullable PageTransformer transformer)
,实现一个接口 PageTransformer
。
包含 ViewPager2 ,大概看了下源码,动画是由ViewPager2.PageTransformer,其实跟ViewPager.PageTransformer接口一致。
这个接口主要为:
public interface PageTransformer {
void transformPage(@NonNull View page, float position);
}
其中存在两个参数,比较不好理解,第一个参数page我们可以理解为我们即将要转换的对象,而对于position,我刚开始的理解为page的的当前的位置index,当看到postion是float的时候,我想我猜错了。
虽然我不知道这个position是什么意思,给的解释也是模棱两可的,然后我就打log记录这个position值,大致得出这样的结论:
大致的viewpager效果如下图:
那么在滑动的过程中:
前一个view的position变化 | 当前view的position变化 | 后一个view的position变化 | |
---|---|---|---|
当前view右滑时 | -1 ----> 0 | 0-------->1 | 1 ----> +∞ |
当前view左滑时 | -∞ ----> -1 | 0 -----> -1 | 1 ------->0 |
我们用动图模拟一下此时的三个view的position的动态变化:
当我们向右移动时:
当我们向左移动时:
我们模拟viewpager的滑动,此时可以看到三个position的趋势与上表是一致的,因此对于这个position我可以这样解释:
当前我们的viewpager存在一个currentItem,就是当前的current position位置,我们记录此时的坐标轴为0,那么向右移动时,前一个view的position也是像右移动的,只是它的坐标是由-1慢慢变大到0的,这种position的值是一个相对值,是相对于当前curerntItem的坐标位置的相对值;同理右边的view也会向右移动,只是它的相对值由1慢慢变得无限大。
同理,我们往左滑动时,这个position也是一个有方向的相对值。
还记得我们比较喜欢设置viewpager.setOffscreenPageLimit
,它的意思就是屏幕之外的view保留几个,我们也称之为缓存view,其实这个limit的个数limitN
与viewpager应该保持view的Count
的关系为:
Count = limitN * 2 + 1
即需要viewPager保存(limitN * 2 + 1)个缓存状态view。为什么扯到这个东西呢?很简单,如果我们将setOffscreenPageLimit
设置为2,那么
void transformPage(@NonNull View page, float position);
这个方法中将会有5中不同的数据回调,分别是:
我们做个测试,将view加上id:
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
ImageView iv = new ImageView(getApplicationContext());
iv.setScaleType(ImageView.ScaleType.FIT_XY);
// 将id设置为 10000 + 当前的position
iv.setId(10000 + position);
ImageUtils.loadImage(imageList.get(position),iv);
container.addView(iv);
return iv;
}
然后我们在滑动的时候,打印一下日志:
@Override
public void transformPage(@NonNull View page, float position) {
Log.e("TAG", "page:" + page.getId() + "," + position);
}
我们看到的确存在5个类型的page值,说明我们的推断是正确的。
clipChildren属性表示是否限制子控件在该容器所在的范围内,clipChildren属性配合layout_gravity属性,可以用来设置多余部分的显示位置,我这里举一个简单的例子,比如喜马拉雅FM这个应用的首页:
大家注意看这个应用底部导航栏中中间一个是要比另外四个高的,这种效果很多人就会想到使用一个RelativeLayout布局来实现,其实不用那么麻烦,这种效果一个clipChildren属性就能实现,示例Demo如下:
代码:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:clipChildren="false" tools:context="org.lenve.clipchildren.MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="48dp" android:layout_alignParentBottom="true" android:background="#03b9fc" android:orientation="horizontal"> <ImageView android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:src="@mipmap/ic_launcher"/> <ImageView android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:src="@mipmap/ic_launcher"/> <ImageView android:layout_width="0dp" android:layout_height="72dp" android:layout_gravity="bottom" android:layout_weight="1" android:src="@mipmap/ic_launcher"/> <ImageView android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:src="@mipmap/ic_launcher"/> <ImageView android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:src="@mipmap/ic_launcher"/> </LinearLayout></RelativeLayout>
大家看只需要在根节点添加clipChildren属性,然后在第三个ImageView上添加layout_gravity属性即可,layout_gravity属性值为bottom表示控件大小超出后控件底部对齐。效果如下:
OK,上面是对clipChildren属性一个简单介绍,算是一个铺垫,接下来我们来看看ViewPager。
那么在这之前,我想先介绍一个属性,那就是clipToPadding,这个属性是什么意思呢?它表示是否允许ViewGroup在ViewGroup的padding中进行绘制,默认情况下该属性的值为true,即不允许在ViewGroup的padding中进行绘制。那如果我设置了false呢?我们来看看:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="org.lenve.myviewpagercards2.MainActivity"> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="200dp" android:clipToPadding="false" android:paddingBottom="24dp" android:paddingLeft="48dp" android:paddingRight="48dp" android:paddingTop="24dp"></android.support.v4.view.ViewPager></RelativeLayout>
ViewPager的Adapter如下:
public class MyAdapter extends PagerAdapter { private List<Integer> list; private Context context; public MyAdapter(Context context, List<Integer> list) { this.context = context; this.list = list; } @Override public int getCount() { return list.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Object instantiateItem(ViewGroup container, int position) { ImageView iv = new ImageView(context); iv.setImageResource(list.get(position)); container.addView(iv); return iv; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); }}
Activity中的代码:
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager); List<Integer> list = new ArrayList<>(); list.add(R.drawable.p001); list.add(R.drawable.p002); list.add(R.drawable.p003); list.add(R.drawable.p004); list.add(R.drawable.p005); MyAdapter adapter = new MyAdapter(this, list); viewPager.setAdapter(adapter); viewPager.setPageMargin(20);
显示效果如下:
OK,那这个clipToPadding属性是我们在一个页面中显示多个ViewPager item的第二种方式。这个CardView式的ViewPager我们就使用这种方式来实现。先来看看效果图:
整体思路和上文其实是一致的,我们来看看activity的布局:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="org.lenve.myviewpagercards2.MainActivity"> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="300dp" android:clipToPadding="false" android:paddingBottom="24dp" android:paddingLeft="80dp" android:paddingRight="80dp" android:paddingTop="24dp"></android.support.v4.view.ViewPager></RelativeLayout>
ViewPager中每一个item的布局:
<?xml version="1.0" encoding="utf-8"?><android.support.v7.widget.CardView android:id="@+id/cardview" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" app:cardCornerRadius="10dp"> <RelativeLayout android:layout_width="match_parent" android:layout_height="300dp"> <TextView android:id="@+id/tv" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerInParent="true" android:gravity="center" android:text="我是一个TextView"/> <Button android:layout_width="96dp" android:layout_height="36dp" android:textColor="#ffffff" android:layout_below="@id/tv" android:layout_centerHorizontal="true" android:layout_marginTop="12dp" android:background="@color/colorAccent" android:text="我是一个按钮"/> </RelativeLayout></android.support.v7.widget.CardView>
Adapter:
public class MyAdapter extends PagerAdapter { private List<Integer> list; private Context context; private LayoutInflater inflater; public MyAdapter(Context context, List<Integer> list) { this.context = context; this.list = list; inflater = LayoutInflater.from(context); } @Override public int getCount() { return list.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Object instantiateItem(ViewGroup container, int position) { View view = inflater.inflate(R.layout.vp_item, container, false); container.addView(view); return view; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); }}
Activity中的代码:
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager); List<Integer> list = new ArrayList<>(); list.add(R.drawable.p001); list.add(R.drawable.p002); list.add(R.drawable.p003); list.add(R.drawable.p004); list.add(R.drawable.p005); MyAdapter adapter = new MyAdapter(this, list); viewPager.setAdapter(adapter); viewPager.setPageMargin((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, getResources().getDisplayMetrics())); viewPager.setPageTransformer(false, new ScaleTransformer(this));
最后再来看看我们定义的PageTransformer:
public class ScaleTransformer implements ViewPager.PageTransformer { private Context context; private float elevation; public ScaleTransformer(Context context) { this.context = context; elevation = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, context.getResources().getDisplayMetrics()); } @Override public void transformPage(View page, float position) { if (position < -1 || position > 1) { } else { if (position < 0) { ((CardView) page).setCardElevation((1 + position) * elevation); } else { ((CardView) page).setCardElevation((1 - position) * elevation); } } }}
很简单,我只是对CardView的阴影做了处理 ,其他属性都没改,这样就有了我们刚才看到的效果。
其实就是水平缩放效果。在页面滑动时,
左边页面 position < 0,右边页面 position > 0;
左边页面以页面右边缘为缩放中心,右边页面以左边缘为缩放中心。
代码如下所示:
/**
* 手风琴效果(水平方向缩放)
*/
public class AccordionTransformer implements ViewPager.PageTransformer {
@Override
public void transformPage(@NonNull View page, float position) {
if (position < 0f) {
page.setPivotX(page.getWidth());
page.setScaleX(1f + position * 0.5f);
} else if (position < 1f) {
page.setPivotX(0f);
page.setScaleX(1f - position * 0.5f);
}
}
}
代码如下所示:
/**
* 下弧形切换效果
*/
public class ArcDownTransformer implements ViewPager.PageTransformer {
private static final float DEF_MAX_ROTATE = 12.0f;
private float mMaxRotate = DEF_MAX_ROTATE;
@Override
public void transformPage(@NonNull View page, float position) {
page.setPivotY( page.getHeight());
if (position < -1f) {//[-Infinity, -1)
page.setRotation(-mMaxRotate);
page.setPivotX(page.getWidth());
} else if (position <= 1f) {//[-1, 1]
if (position < 0f) {//[-1, 0)
page.setRotation(mMaxRotate * position);
page.setPivotX(page.getWidth() * (0.5f - 0.5f * position));
} else { //[0, 1]
page.setRotation(mMaxRotate * position);
page.setPivotX(page.getWidth() * (0.5f - 0.5f * position));
}
} else {//(1, +Infinity]
page.setRotation(mMaxRotate);
page.setPivotX(0f);
}
}
}
代码如下:
/**
* 上弧形切换效果
*/
public class ArcUpTransformer implements ViewPager.PageTransformer {
private static final float DEF_MAX_ROTATE = 12.0f;
private float mMaxRotate = DEF_MAX_ROTATE;
@Override
public void transformPage(@NonNull View page, float position) {
page.setPivotY(0f);
if (position < -1f) {//[-Infinity, -1)
page.setRotation(mMaxRotate);
page.setPivotX(page.getWidth());
} else if (position <= 1f) {//[-1, 1]
if (position < 0f) {//[-1, 0)
page.setRotation(-mMaxRotate * position);
page.setPivotX(page.getWidth() * (0.5f - 0.5f * position));
} else { //[0, 1]
page.setRotation(-mMaxRotate * position);
page.setPivotX(page.getWidth() * (0.5f - 0.5f * position));
}
} else {//(1, +Infinity]
page.setRotation(-mMaxRotate);
page.setPivotX(0f);
}
}
}
其实是绕 Y 轴旋转,再加上缩放效果。绕 Y 轴旋转,用到了 View 的 setRotationY(float)
方法,此方法可以设置绕 Y 轴的旋转角度。
引入抛物线计算缩放值,是为了让页面在滑动到一半(position 为 -0.5 和 0.5)时,缩放到最小。
需要注意 的是镜头距离,即图像与屏幕距离,距离较小时,旋转时会有较大的失真,效果很差,需要设置一下镜头距离(Camera Distance,参考 View#setCameraDistance(float))。
代码如下:
/**
* 立方体翻转效果
*/
public class CubicOverturnTransformer implements ViewPager.PageTransformer {
public static final float DEFAULT_MAX_ROTATION = 60f;
public static final float DEF_MIN_SCALE = 0.86f;
/**
* 最大旋转角度
*/
private float mMaxRotation = DEFAULT_MAX_ROTATION;
/**
* 最小缩放
*/
private float mMinScale = DEF_MIN_SCALE;
public CubicOverturnTransformer() {
this(DEFAULT_MAX_ROTATION);
}
public CubicOverturnTransformer(float maxRotation) {
this(maxRotation, DEF_MIN_SCALE);
}
public CubicOverturnTransformer(float maxRotation, float minScale) {
mMaxRotation = maxRotation;
this.mMinScale = minScale;
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public void transformPage(@NonNull View page, float position) {
page.setPivotY(page.getHeight() / 2f);
float distance = getCameraDistance();
page.setCameraDistance(distance);//设置 View 的镜头距离,可以防止旋转大角度时出现图像失真或不显示。
if (position < -1) { // [-Infinity,-1)
page.setRotationY(-mMaxRotation);
page.setPivotX(page.getWidth());
} else if (position <= 1) { // [-1,1]
page.setRotationY(position * mMaxRotation);
if (position < 0) {//[0,-1]
page.setPivotX(page.getWidth());
float scale = DEF_MIN_SCALE + 4f * (1f - DEF_MIN_SCALE) * (position + 0.5f) * (position + 0.5f);
page.setScaleX(scale);
page.setScaleY(scale);
} else {//[1,0]
page.setPivotX(0);
float scale = DEF_MIN_SCALE + 4f * (1f - DEF_MIN_SCALE) * (position - 0.5f) * (position - 0.5f);
page.setScaleX(scale);
page.setScaleY(scale);
}
} else { // (1,+Infinity]
page.setRotationY(mMaxRotation);
page.setPivotX(0);
}
}
/**
* 获得镜头距离(图像与屏幕距离)。参考{@link View#setCameraDistance(float)},小距离表示小视角,
* 大距离表示大视角。这个距离较小时,在 3D 变换(如围绕X和Y轴的旋转)时,会导致更大的失真。
* 如果改变 rotationX 或 rotationY 属性,使得此 View 很大 (超过屏幕尺寸的一半),则建议始终使用
* 大于此时图高度 (X 轴旋转)或 宽度(Y 轴旋转)的镜头距离。
* @return 镜头距离 distance
*
* @see {@link View#setCameraDistance(float)}
*/
private float getCameraDistance() {
DisplayMetrics displayMetrics = VpsApplication.getAppContext().getResources().getDisplayMetrics();
float density = displayMetrics.density;
int widthPixels = displayMetrics.widthPixels;
int heightPixels = displayMetrics.heightPixels;
return 1.5f*Math.max(widthPixels, heightPixels)*density;
}
}
使用:
mPageTransformer = new CubicOverturnTransformer(90f, 0.6f);
mVpImgs.setPageTransformer(reverseDrawingOrder, mPageTransformer);
最大旋转角度 90 度,最小缩放到 0.6 。
与上一个效果是同一套代码,绕 Y 轴旋转方向相反,使用时,让 最大旋转角度小于 0 即可,如下代码所示,最大旋转角度改为 -90f 就是内部翻转:
使用:
mPageTransformer = new CubicOverturnTransformer(-90f, 0.6f);
mVpImgs.setPageTransformer(reverseDrawingOrder, mPageTransformer);
最大旋转角度 90 度,最小缩放到 0.6 。
特殊的缩放效果,有最小缩放值,页面缩到最小值不再缩小,同时有透明度的变化(可以去掉透明度变化)。
旋转中心位置的调整主要是为了调整页面间隙。
/**
* 下沉效果
*/
public class DipInTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.85f;
private float mMinScale = MIN_SCALE;
private static final float MIN_ALPHA = 0.5f;
private float mMinAlpha = MIN_ALPHA;
@Override
public void transformPage(@NonNull View page, float position) {
Log.i("DipInTransformer", "transformPage: id = " + page.getId() + ", position = " + position);
int pageWidth = page.getWidth();
int pageHeight = page.getHeight();
// page.setPivotX(pageWidth * 0.5f);
page.setPivotY(pageHeight * 0.5f);
if (position < -1f) {//(-Infinity, -1]
page.setAlpha(mMinAlpha);
page.setScaleX(mMinScale);
page.setScaleY(mMinScale);
page.setPivotX(pageWidth*1f);
} else if (position <= 1f) {//(-1, 1)
float scaleFactor = Math.max(mMinScale, 1 - Math.abs(position));
page.setScaleX(scaleFactor);
page.setScaleY(scaleFactor);
if (position < 0) {
page.setPivotX(pageWidth * (0.5f + 0.5f * scaleFactor));
} else {
page.setPivotX(pageWidth * (0.5f - 0.5f * scaleFactor));
}
page.setAlpha(mMinAlpha + (scaleFactor - mMinScale) / (1f - mMinScale) * (1f - mMinAlpha));
} else {//(1, +Infinity)
page.setAlpha(mMinAlpha);
page.setScaleX(mMinScale);
page.setScaleY(mMinScale);
page.setPivotX(pageWidth * 0f);
}
}
}
/**
* 淡入淡出
*/
public class FadeInOutTransformer implements ViewPager.PageTransformer {
private static final float DEF_MIN_ALPHA =0.5f;
private float mMinAlpha = DEF_MIN_ALPHA;
@Override
public void transformPage(@NonNull View page, float position) {
if (position < -1f) {//[-Infinity, -1)
page.setAlpha(mMinAlpha);
} else if (position <= 1f) {//[-1, 1]
if (position < 0f) {//[-1, 0)
page.setAlpha(1f + (1f - mMinAlpha) * position);
} else { //[0, 1]
page.setAlpha(1f - (1f - mMinAlpha) * position);
}
} else {//(1, +Infinity]
page.setAlpha(mMinAlpha);
}
}
}
即以水平中心线为旋转中心,绕 Y 轴旋转。代码如下所示,同样要注意镜头距离:
/**
* 水平翻转效果
*/
public class FlipHorizontalTransformer implements ViewPager.PageTransformer {
@Override
public void transformPage(@NonNull View page, float position) {
page.setCameraDistance(getCameraDistance());
page.setTranslationX(-page.getWidth() * position);
float rotation = 180f * position;
page.setAlpha(rotation > 90f || rotation < -90f ? 0f : 1f);
page.setPivotX(page.getWidth() * 0.5f);
page.setPivotY(page.getHeight() * 0.5f);
page.setRotationY(rotation);
if (position > -0.5f && position < 0.5f) {
page.setVisibility(View.VISIBLE);
} else {
page.setVisibility(View.INVISIBLE);
}
}
private float getCameraDistance() {
DisplayMetrics displayMetrics = VpsApplication.getAppContext().getResources().getDisplayMetrics();
float density = displayMetrics.density;
int widthPixels = displayMetrics.widthPixels;
int heightPixels = displayMetrics.heightPixels;
return 1.5f * Math.max(widthPixels, heightPixels) * density;
}
}
即以竖直中心线为旋转中心,绕 X 轴旋转。代码如下所示,同样要注意镜头距离:
/**
* 竖直翻转效果
*/
public class FlipVerticalTransformer implements ViewPager.PageTransformer {
@Override
public void transformPage(@NonNull View page, float position) {
page.setCameraDistance(getCameraDistance());
page.setTranslationX(-page.getWidth() * position);
float rotation = 180f * position;
page.setAlpha(rotation > 90f || rotation < -90f ? 0f : 1f);
page.setPivotX(page.getWidth() * 0.5f);
page.setPivotY(page.getHeight() * 0.5f);
page.setRotationX(rotation);
if (position > -0.5f && position < 0.5f) {
page.setVisibility(View.VISIBLE);
} else {
page.setVisibility(View.INVISIBLE);
}
}
private float getCameraDistance() {
DisplayMetrics displayMetrics = VpsApplication.getAppContext().getResources().getDisplayMetrics();
float density = displayMetrics.density;
int widthPixels = displayMetrics.widthPixels;
int heightPixels = displayMetrics.heightPixels;
return 1.5f * Math.max(widthPixels, heightPixels) * density;
}
}
让所有右边页面都移动到 正中位置,从右向左滑动切换页面时,左边从右向左滑出,右边页面放大淡入。
/**
* 浮出效果
*/
public class RiseInTransformer implements ViewPager.PageTransformer {
private static final float DEF_MIN_SCALE = 0.72f;
private float mMinScale = DEF_MIN_SCALE;
private static final float DEF_MIN_ALPHA = 0.5f;
public RiseInTransformer() {
}
public RiseInTransformer(float minScale) {
this.mMinScale = minScale;
}
public float getMinScale() {
return mMinScale;
}
public void setMinScale(float minScale) {
this.mMinScale = minScale;
}
@Override
public void transformPage(@NonNull View page, float position) {
if (position < 0f) {
page.setTranslationX(0f);
} else if (position <= 1) {
page.setTranslationX(-position * page.getWidth());
page.setScaleX(1f - (1f - mMinScale) * position);
page.setScaleY(1f - (1f - mMinScale) * position);
page.setAlpha(1f - (1f - DEF_MIN_ALPHA) * position);
} else {
page.setTranslationX(-position * page.getWidth());
page.setScaleX(mMinScale);
page.setScaleY(mMinScale);
page.setAlpha(DEF_MIN_ALPHA);
}
}
}
调用时需要反转绘制顺序,即 reverseDrawingOrder = true,使左边页面先绘制,右边页面后绘制,否则效果无法实现。
int reverseDrawingOrder = true;
mVpImgs.setPageTransformer(reverseDrawingOrder , mPageTransformer);
让所有左边页面都移动到 正中位置,切换页面时,左边页面缩小淡出,右面页面从右向左滑入正中。
/**
* 下潜效果
*/
public class DiveOutTransformer implements ViewPager.PageTransformer {
private static final float DEF_MIN_SCALE = 0.72f;
private float mMinScale = DEF_MIN_SCALE;
private static final float DEF_MIN_ALPHA = 0.5f;
public DiveOutTransformer() {
}
public DiveOutTransformer(float minScale) {
this.mMinScale = minScale;
}
public float getMinScale() {
return mMinScale;
}
public void setMinScale(float minScale) {
this.mMinScale = minScale;
}
@Override
public void transformPage(@NonNull View page, float position) {
if (position < -1f) {
page.setScaleX(mMinScale);
page.setScaleY(mMinScale);
page.setAlpha(DEF_MIN_ALPHA);
page.setTranslationX(-position * page.getWidth());
} else if (position <= 0) {
page.setTranslationX(-position * page.getWidth());
page.setScaleX(1f + (1f - mMinScale) * position);
page.setScaleY(1f + (1f - mMinScale) * position);
page.setAlpha(1f + (1f - DEF_MIN_ALPHA) * position);
} else {
page.setTranslationX(0f);
}
}
}
调用时不需要反转绘制顺序,即 reverseDrawingOrder = false,使右边页面先绘制,左边页面后绘制,否则效果无法实现。
int reverseDrawingOrder = false;
mVpImgs.setPageTransformer(reverseDrawingOrder , mPageTransformer);
所有右边页面移动到正中位置,即 0 位置,滑动时,把最上面页面滑掉,代码如下所示:
/**
* 堆叠效果
*/
public class StackTransformer implements ViewPager.PageTransformer {
@Override
public void transformPage(@NonNull View page, float position) {
page.setTranslationX(position < 0 ? 0f : -page.getWidth() * position);
}
}
调用时需要反转绘制顺序,即 reverseDrawingOrder = true,使左边页面先绘制,右边页面后绘制,否则效果无法实现。
int reverseDrawingOrder = true;
mVpImgs.setPageTransformer(reverseDrawingOrder , mPageTransformer);
比较简单,与淡入淡出效果类似,不多作解释:
/**
* 缩放效果
*/
public class ZoomInOutTransformer implements ViewPager.PageTransformer {
private static final float DEF_MIN_SCALE = 0.9f;
private float mMinScale = DEF_MIN_SCALE;
@Override
public void transformPage(@NonNull View page, float position) {
if (position < -1f) {//[-Infinity, -1)
page.setScaleX(mMinScale);
page.setScaleY(mMinScale);
} else if (position <= 1f) {//[-1, 1]
if (position < 0f) {//[-1, 0)
page.setScaleX(1f + (1f - mMinScale) * position);
page.setScaleY(1f + (1f - mMinScale) * position);
} else { //[0, 1]
page.setScaleX(1f - (1f - mMinScale) * position);
page.setScaleY(1f - (1f - mMinScale) * position);
}
} else {//(1, +Infinity]
page.setScaleX(mMinScale);
page.setScaleY(mMinScale);
}
}
}
通过调用 View 的 setScrollX() 方法,使页面内容随着 position 移动。
public class ParallaxTransformer implements ViewPager.PageTransformer {
@Override
public void transformPage(@NonNull View page, float position) {
int width = page.getWidth();
if (position <= -1f) {
page.setScrollX(0);
} else if (position < 1f) {
if (position < 0f) {
page.setScrollX((int) (width * 0.75f * position));
} else {
page.setScrollX((int) (width * 0.75f * position));
}
} else {
page.setScrollX(0);
}
}
}
调用时需要反转绘制顺序,即 reverseDrawingOrder = true,使左边页面先绘制,右边页面后绘制,否则效果无法实现。
int reverseDrawingOrder = true;
mVpImgs.setPageTransformer(reverseDrawingOrder , mPageTransformer);
作者:小空和小芝中的小空
转载说明-务必注明来源:https://zhima.blog.csdn.net/
这位道友请留步☁️,我观你气度不凡,谈吐间隐隐有王者霸气,日后定有一番大作为!!!旁边有点赞收藏今日传你,点了吧,未来你成功☀️,我分文不取,若不成功⚡️,也好回来找我。
温馨提示:点击下方卡片获取更多意想不到的资源。