跳到主要内容
Android 自定义 PageTransformer 实现 ViewPager 动画切换效果 | 极客日志
Java 大前端 java
Android 自定义 PageTransformer 实现 ViewPager 动画切换效果 综述由AI生成 Android 中如何使用 ViewPager 的 setPageTransformer 方法实现页面切换动画。内容涵盖了基础用法、官方提供的 Depth 和 ZoomOut 变换器示例、以及针对 SDK 11 以下版本的向下兼容方案(包括使用 NineOldAndroids 和修改 ViewPager 源码)。此外,文章还深入解析了 PageTransformer 接口中 position 参数的含义,并指导读者自定义实现了旋转动画效果。最后补充了关于 View 测量时机、性能优化及 ViewPager2 迁移的最佳实践建议,帮助开发者构建流畅且兼容的滑动体验。
未来可期 发布于 2025/2/7 更新于 2026/6/2 24 浏览Android 自定义 PageTransformer 实现 ViewPager 动画切换效果
1. 概述
在 Android 开发中,ViewPager 是进行页面滑动切换的常用组件。除了默认的滑动效果外,通过 setPageTransformer 方法可以设置丰富的页面切换动画。本文将详细介绍如何使用官方提供的 PageTransformer,如何自定义个性化的切换动画,以及如何解决低版本 SDK 的兼容性问题。
本文主要涵盖以下内容:
介绍如何使用 setPageTransformer 设置切换动画;
自定义 PageTransformer 实现个性的切换动画(如旋转效果);
针对 SDK 11 以下版本的向下兼容方案。
2. setPageTransformer 的使用
首先,我们需要搭建一个基础的 ViewPager 环境。
2.1 布局文件
<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.support.v4.view.ViewPager
android:id ="@+id/id_viewpager"
android:layout_width ="fill_parent"
android:layout_height ="fill_parent" />
</RelativeLayout >
2.2 MainActivity 代码
package com.zhy.demo_zhy_08_viewpageranim;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
android.widget.ImageView;
android.widget.ImageView.ScaleType;
{
ViewPager mViewPager;
[] mImgIds = [] { R.drawable.guide_image1,
R.drawable.guide_image2, R.drawable.guide_image3 };
List<ImageView> mImageViews = <ImageView>();
{
.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
initData();
mViewPager = (ViewPager) findViewById(R.id.id_viewpager);
mViewPager.setAdapter( () {
Object {
container.addView(mImageViews.get(position));
mImageViews.get(position);
}
{
container.removeView(mImageViews.get(position));
}
{
view == object;
}
{
mImgIds.length;
}
});
}
{
( imgId : mImgIds) {
(getApplicationContext());
imageView.setScaleType(ScaleType.CENTER_CROP);
imageView.setImageResource(imgId);
mImageViews.add(imageView);
}
}
}
import
import
public
class
MainActivity
extends
Activity
private
private
int
new
int
private
new
ArrayList
@Override
protected
void
onCreate
(Bundle savedInstanceState)
super
new
PagerAdapter
@Override
public
instantiateItem
(ViewGroup container, int position)
return
@Override
public
void
destroyItem
(ViewGroup container, int position,
Object object)
@Override
public
boolean
isViewFromObject
(View view, Object object)
return
@Override
public
int
getCount
()
return
private
void
initData
()
for
int
ImageView
imageView
=
new
ImageView
2.3 添加 PageTransformer ViewPager 提供了一个 setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) 方法用于设置切换时的动画效果。
1. DepthPageTransformer (深度变换) 这是 Google 官方示例之一,模拟卡片堆叠的深度效果。
public class DepthPageTransformer implements ViewPager .PageTransformer {
private static final float MIN_SCALE = 0.75f ;
public void transformPage (View view, float position) {
int pageWidth = view.getWidth();
if (position < -1 ) {
view.setAlpha(0 );
} else if (position <= 0 ) {
view.setAlpha(1 );
view.setTranslationX(0 );
view.setScaleX(1 );
view.setScaleY(1 );
} else if (position <= 1 ) {
view.setAlpha(1 - position);
view.setTranslationX(pageWidth * -position);
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else {
view.setAlpha(0 );
}
}
}
mViewPager.setPageTransformer(true , new DepthPageTransformer ());
2. ZoomOutPageTransformer (缩放退出) package com.zhy.view;
import android.support.v4.view.ViewPager;
import android.view.View;
public class ZoomOutPageTransformer implements ViewPager .PageTransformer {
private static final float MIN_SCALE = 0.85f ;
private static final float MIN_ALPHA = 0.5f ;
public void transformPage (View view, float position) {
int pageWidth = view.getWidth();
int pageHeight = view.getHeight();
if (position < -1 ) {
view.setAlpha(0 );
} else if (position <= 1 ) {
float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
float vertMargin = pageHeight * (1 - scaleFactor) / 2 ;
float horzMargin = pageWidth * (1 - scaleFactor) / 2 ;
if (position < 0 ) {
view.setTranslationX(horzMargin - vertMargin / 2 );
} else {
view.setTranslationX(-horzMargin + vertMargin / 2 );
}
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE)
/ (1 - MIN_SCALE) * (1 - MIN_ALPHA));
} else {
view.setAlpha(0 );
}
}
}
mViewPager.setPageTransformer(true , new ZoomOutPageTransformer ());
注意: 上述代码使用了属性动画 API,在 Android 3.0 (API 11) 之前是不生效的。注释中提到:setting a PageTransformer prior to Android 3.0 (API 11) will have no effect。
3. 版本的向下兼容
3.1 不兼容原因分析 在 Android 3.0 之前,系统不支持 View 的属性动画(Property Animation)。因此,直接使用 view.setAlpha() 等方法在旧版本上无效。此外,setPageTransformer 方法内部也有版本判断逻辑,仅当 Build.VERSION.SDK_INT >= 11 时才执行相关逻辑。
3.2 完美向下兼容方案
引入 NineOldAndroids 库,使用 ViewHelper 替代原生属性动画方法。
修改或替换 ViewPager 源码,移除 SDK 版本判断。
第一步:使用 ViewHelper 将代码中的 view.setAlpha() 等替换为 ViewHelper.setAlpha(view, ...)。
public class DepthPageTransformer implements ViewPager .PageTransformer {
private static final float MIN_SCALE = 0.75f ;
public void transformPage (View view, float position) {
int pageWidth = view.getWidth();
if (position < -1 ) {
ViewHelper.setAlpha(view, 0 );
} else if (position <= 0 ) {
ViewHelper.setAlpha(view, 1 );
ViewHelper.setTranslationX(view, 0 );
ViewHelper.setScaleX(view, 1 );
ViewHelper.setScaleY(view, 1 );
} else if (position <= 1 ) {
ViewHelper.setAlpha(view, 1 - position);
ViewHelper.setTranslationX(view, pageWidth * -position);
float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - position);
ViewHelper.setScaleX(view, scaleFactor);
ViewHelper.setScaleY(view, scaleFactor);
} else {
ViewHelper.setAlpha(view, 1 );
}
}
}
由于 setPageTransformer 内部有 if (Build.VERSION.SDK_INT >= 11) 的判断,直接修改源码是最彻底的方案。我们将 android.support.v4.view.ViewPager 拷贝一份至项目中,重命名为 ViewPagerCompat,并注释掉版本判断语句。
public class ViewPagerCompat extends ViewGroup {
public void setPageTransformer (boolean reverseDrawingOrder, ViewPager.PageTransformer transformer) {
final boolean hasTransformer = transformer != null ;
final boolean needsPopulate = hasTransformer != (mPageTransformer != null );
mPageTransformer = transformer;
setChildrenDrawingOrderEnabledCompat(hasTransformer);
if (hasTransformer) {
mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD;
} else {
mDrawingOrder = DRAW_ORDER_DEFAULT;
}
if (needsPopulate) populate();
}
}
在项目中使用 ViewPagerCompat 替换原有的 ViewPager,即可在 Android 2.3.3 等低版本设备上运行自定义动画。
4. 自定义 PageTransformer 实现个性切换动画 PageTransformer 接口非常简单,只包含一个方法:
public interface PageTransformer {
void transformPage (View page, float position) ;
}
page: 当前正在变换的 View。
position: 页面相对于中心位置的状态。0 表示正中间,1 表示右侧一整页,-1 表示左侧一整页。
4.1 Position 参数详解 当用户滑动时,transformPage 会被频繁调用。position 的值域通常分为三部分:
[-Infinity, -1): 页面完全在屏幕左侧之外。
(1, +Infinity]: 页面完全在屏幕右侧之外。
[-1, 1]: 页面处于可见区域附近,是动画计算的核心区间。
A 页的 position 从 0 变为 -1。
B 页的 position 从 1 变为 0。
4.2 实现旋转动画 我们可以利用 position 的变化来实现页面的旋转效果。例如,让滑出的页面向左旋转,滑入的页面向右旋转。
设置旋转中心点:底部中心。
根据 position 计算旋转角度。
public class RotatePageTransformer implements ViewPager .PageTransformer {
private static final float ROTATION_MAX = 20.0f ;
@Override
public void transformPage (View view, float position) {
view.setPivotX(view.getMeasuredWidth() * 0.5f );
view.setPivotY(view.getMeasuredHeight());
float rotation = ROTATION_MAX * position;
view.setRotation(rotation);
}
}
测量时机 :在 transformPage 中获取 view.getMeasuredWidth() 可能返回 0,因为此时 View 尚未完成测量。建议将旋转中心的设置放在 onLayout 之后,或者使用 view.post() 确保 View 已测量完毕后再设置 Pivot。
性能优化 :避免在每次滑动时重复创建对象,尽量复用变量。
5. 总结与最佳实践 通过 PageTransformer,我们可以轻松实现各种复杂的页面切换动画,无需依赖第三方库。但在使用时也需注意以下几点:
兼容性 :对于需要支持 Android 3.0 以下的老旧设备,必须使用 ViewPagerCompat 方案配合 NineOldAndroids。
性能 :频繁的 View 属性修改会影响 FPS。尽量使用硬件加速,避免在 transformPage 中进行复杂计算或内存分配。
维护性 :Google 已推荐使用 ViewPager2 替代旧版 ViewPager。ViewPager2 基于 RecyclerView 构建,提供了更好的性能和更灵活的动画控制(通过 PageTransformer 同样支持)。如果在新项目中开发,建议优先考虑 ViewPager2。
掌握 PageTransformer 的原理,能够帮助开发者创造出更具交互感和视觉吸引力的移动应用界面。
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online