如何为ViewPager中各Fragment设置不同的进出动画?
给ViewPager中每个Fragment配置独立进出动画的解决方案
我之前也碰到过一模一样的需求——全局的PageTransformer确实能搞定统一动画,但要给每个Fragment单独配滑动进出效果就不够用了。这里给你几个经过验证的可行方案,你可以根据自己的场景选:
方案一:基于Fragment标识的自定义PageTransformer
这是最直接的思路:在自定义的PageTransformer里,根据当前页面对应的Fragment类型/标识,应用不同的动画逻辑。
步骤:
- 给每个Fragment加个区分标识,比如在Fragment的根View上设置Tag:
// 示例:在FirstFragment的onCreateView中 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_first, container, false); rootView.setTag("slide_left"); // 标记该Fragment使用左滑动画 return rootView; }
- 编写自定义
PageTransformer,在transformPage方法里判断标识并执行对应动画:
public class PerFragmentPageTransformer implements ViewPager.PageTransformer { private ViewPager mViewPager; public PerFragmentPageTransformer(ViewPager viewPager) { mViewPager = viewPager; } @Override public void transformPage(@NonNull View page, float position) { String animTag = (String) page.getTag(); if (animTag == null) return; switch (animTag) { case "slide_left": // 左滑进出动画逻辑 if (position < -1) { page.setAlpha(0); } else if (position <= 1) { page.setAlpha(1 - Math.abs(position)); page.setTranslationX(page.getWidth() * -position); } else { page.setAlpha(0); } break; case "fade_scale": // 淡入+缩放动画逻辑 float scale = Math.max(0.85f, 1 - Math.abs(position)); page.setScaleX(scale); page.setScaleY(scale); page.setAlpha(1 - Math.abs(position)); break; case "slide_up": // 上滑进出动画逻辑 page.setTranslationY(page.getHeight() * position); page.setAlpha(1 - Math.abs(position)); break; // 其他Fragment的动画类型依次添加 } } }
- 给ViewPager设置这个Transformer:
mViewPager.setPageTransformer(false, new PerFragmentPageTransformer(mViewPager));
方案二:结合Fragment自带的进入/退出过渡动画
如果你的需求是页面切换完成时的过渡效果(而非滑动过程中的实时动画),可以直接用Fragment自身的过渡动画,和ViewPager配合使用:
步骤:
在每个Fragment的onCreate方法里设置独立的进入/退出动画:
// 示例:第一个Fragment——从右侧滑入,淡出退出 @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setEnterTransition(new Slide(Gravity.RIGHT)); setExitTransition(new Fade()); }
// 示例:第二个Fragment——缩放淡入,下滑退出 @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setEnterTransition(new Scale()); setExitTransition(new Slide(Gravity.BOTTOM)); }
注意:这个方案适合页面切换完成后的过渡效果,和ViewPager的滑动动画可能存在冲突,建议禁用ViewPager的默认动画,或者使用ViewPager2配合
FragmentStateAdapter,兼容性更好。
方案三:自定义ViewPager监听滑动过程,精细控制动画
如果需要更极致的自定义(比如滑动过程中每个Fragment的动画实时变化),可以自定义ViewPager,监听页面滑动事件,手动给每个可见Fragment的View应用动画:
public class CustomViewPager extends ViewPager { public CustomViewPager(@NonNull Context context) { super(context); initPageChangeListener(); } public CustomViewPager(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); initPageChangeListener(); } private void initPageChangeListener() { addOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { FragmentPagerAdapter adapter = (FragmentPagerAdapter) getAdapter(); if (adapter == null) return; // 左侧Fragment的退出动画 Fragment leftFragment = adapter.getItem(position); if (leftFragment != null && leftFragment.getView() != null) { View leftView = leftFragment.getView(); leftView.setTranslationX(positionOffsetPixels); leftView.setAlpha(1 - positionOffset); } // 右侧Fragment的进入动画(如果存在) if (position + 1 < adapter.getCount()) { Fragment rightFragment = adapter.getItem(position + 1); if (rightFragment != null && rightFragment.getView() != null) { View rightView = rightFragment.getView(); rightView.setTranslationX(getWidth() - positionOffsetPixels); rightView.setAlpha(positionOffset); } } } @Override public void onPageSelected(int position) {} @Override public void onPageScrollStateChanged(int state) {} }); } }
注意事项:
- 确保Fragment的View已经初始化完成,否则
getView()会返回null,建议在Fragment的onViewCreated里做初始化标记,或者在动画逻辑里加非空判断。 - 优先使用硬件加速的属性(如
translationX、alpha、scaleX),避免使用layout()之类的耗时操作,防止卡顿。 - 如果使用ViewPager2,获取Fragment的方法是
((FragmentStateAdapter) getAdapter()).getFragment(position),需要注意AndroidX版本的兼容性。
内容的提问来源于stack exchange,提问作者PBS
相关产品推荐
相关产品推荐

