如何在Android App中实现类似JioCinema首页的ViewPager缩放切换效果?
实现JioCinema式ViewPager缩放切换效果
要实现你描述的「切换时当前页缩小、目标页放大」的轮播效果,用ViewPager2(推荐替代旧版ViewPager)配合自定义PageTransformer是最优方案,下面直接给你可落地的步骤和代码:
1. 核心原理
PageTransformer是Android官方提供的自定义ViewPager页面切换动画的接口,我们可以通过监听页面的滑动偏移量,动态调整当前页和目标页的缩放比例,从而实现缩小/放大的过渡效果。
2. 实现自定义PageTransformer
创建一个类实现ViewPager2.PageTransformer,在transformPage方法里处理缩放逻辑:
class ScalePageTransformer : ViewPager2.PageTransformer { // 定义最小缩放比例,当前页滑动时会缩小到这个值 private val minScale = 0.85f override fun transformPage(page: View, position: Float) { page.apply { val pageWidth = width when { // 页面完全在左侧屏幕外 position < -1 -> scaleX = minScale // 当前页正在向左滑出,或目标页从左向右滑入 position <= 0 -> { scaleX = minScale + (1 - minScale) * (1 + position) scaleY = minScale + (1 - minScale) * (1 + position) } // 当前页正在向右滑出,或目标页从右向左滑入 position <= 1 -> { scaleX = minScale + (1 - minScale) * (1 - position) scaleY = minScale + (1 - minScale) * (1 - position) } // 页面完全在右侧屏幕外 else -> scaleX = minScale } } } }
注:
position参数含义:
- 小于-1:页面完全在左侧屏幕外
- 0到-1之间:当前页正在向左滑出
- 0:当前页完全显示
- 0到1之间:下一页正在向右滑入
- 大于1:页面完全在右侧屏幕外
3. 布局与ViewPager2配置
在布局文件中添加ViewPager2:
<androidx.viewpager2.widget.ViewPager2 android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="250dp" android:clipToPadding="false" android:paddingHorizontal="24dp"/>
clipToPadding="false"和paddingHorizontal是为了让前后页露出一部分,更贴近JioCinema的视觉效果,可根据需求调整padding值。
4. 设置适配器与PageTransformer
在Activity/Fragment中给ViewPager2配置适配器和自定义动画:
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val viewPager = findViewById<ViewPager2>(R.id.viewPager) // 设置适配器,这里用本地图片列表示例 viewPager.adapter = BannerAdapter(listOf( R.drawable.banner1, R.drawable.banner2, R.drawable.banner3 )) // 预加载前后各1页,确保动画正常触发 viewPager.offscreenPageLimit = 1 // 绑定自定义切换动画 viewPager.setPageTransformer(ScalePageTransformer()) } } // 简单的Banner适配器示例 class BannerAdapter(private val imageList: List<Int>) : RecyclerView.Adapter<BannerAdapter.BannerViewHolder>() { inner class BannerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val imageView: ImageView = itemView.findViewById(R.id.bannerImage) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BannerViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_banner, parent, false) return BannerViewHolder(view) } override fun onBindViewHolder(holder: BannerViewHolder, position: Int) { holder.imageView.setImageResource(imageList[position]) } override fun getItemCount() = imageList.size }
对应的item_banner布局:
<ImageView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/bannerImage" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop"/>
5. 优化调整
- 若想更贴近JioCinema的动画手感,可以修改
minScale的值(比如改成0.9f),或者给缩放逻辑加上动画曲线 - 需要自动轮播的话,用
Handler配合postDelayed即可实现定时切换 - 若坚持用旧版ViewPager(
androidx.viewpager.widget.ViewPager),逻辑完全一致,只需要实现ViewPager.PageTransformer接口
内容的提问来源于stack exchange,提问作者Mr.Code
相关产品推荐
相关产品推荐

