You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android开发:点击MotionLayout实现的Carousel轮播卡片全屏效果求助

实现方案

1. 调整MotionScene配置

首先修改你当前引用的@xml/demo_020_carousel_scene文件,新增两组状态和对应的过渡动画:

  • 新增carousel_normal状态:保留你原有的轮播卡片约束、尺寸、边距配置,所有额外详情View的visibility设为gone
  • 新增carousel_fullscreen状态:将当前选中卡片的约束修改为匹配父布局宽高,取消边距,额外详情View的visibility设为visible,调整内部元素的位置适配全屏布局
  • 新增normal_to_fullscreen过渡:设置动画时长300-500ms,插值器用DecelerateInterpolator保证平滑效果

对应MotionScene示例代码片段:

<Transition
    android:id="@+id/normal_to_fullscreen"
    app:constraintSetStart="@id/carousel_normal"
    app:constraintSetEnd="@id/carousel_fullscreen"
    app:duration="400"
    app:interpolator="android.view.animation.DecelerateInterpolator" />

2. 绑定卡片点击事件

在你的Activity/Fragment中,给所有轮播卡片的根布局(即imageView0到imageView4这几个LinearLayout)设置统一的点击事件,触发逻辑如下:

// 先获取Carousel实例
val carousel = findViewById<Carousel>(R.id.carousel)
val motionLayout = findViewById<MotionLayout>(R.id.motion_layout_carousel)
// 给每个卡片设置点击事件
listOf(R.id.imageView0, R.id.imageView1, R.id.imageView2, R.id.imageView3, R.id.imageView4).forEach { id ->
    findViewById<LinearLayout>(id).setOnClickListener {
        // 判断点击的卡片是否是当前选中的项
        val currentPosition = carousel.currentIndex
        // 适配5个复用卡片的索引映射
        val clickedViewIndex = when(id) {
            R.id.imageView0 -> currentPosition -2
            R.id.imageView1 -> currentPosition -1
            R.id.imageView2 -> currentPosition
            R.id.imageView3 -> currentPosition +1
            R.id.imageView4 -> currentPosition +2
            else -> -1
        }
        if (clickedViewIndex == currentPosition) {
            // 点击的是当前选中卡片,触发全屏过渡
            motionLayout.transitionToState(R.id.carousel_fullscreen)
            // 过渡期间禁用Carousel滑动,避免冲突
            carousel.isEnabled = false
            // 给当前选中的卡片填充额外的全屏数据
            fillFullScreenData(currentPosition)
        }
    }
}

3. 添加返回逻辑

全屏状态下新增返回普通轮播状态的逻辑即可:

// 监听返回键或者全屏状态下的关闭按钮点击
override fun onBackPressed() {
    if (motionLayout.currentState == R.id.carousel_fullscreen) {
        motionLayout.transitionToState(R.id.carousel_normal)
        // 过渡完成后重新启用Carousel滑动
        motionLayout.addTransitionListener(object : MotionLayout.TransitionListener {
            override fun onTransitionCompleted(motionLayout: MotionLayout?, currentId: Int) {
                if (currentId == R.id.carousel_normal) {
                    carousel.isEnabled = true
                    motionLayout?.removeTransitionListener(this)
                }
            }
            // 其余回调空实现即可
            override fun onTransitionStarted(p0: MotionLayout?, p1: Int, p2: Int) {}
            override fun onTransitionChange(p0: MotionLayout?, p1: Int, p2: Int, p3: Float) {}
            override fun onTransitionTrigger(p0: MotionLayout?, p1: Int, p2: Boolean, p3: Float) {}
        })
        return
    }
    super.onBackPressed()
}

你提供的Carousel布局参考代码

<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/motion_layout_carousel"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:visibility="invisible"
    app:layout_constraintTop_toBottomOf="@+id/player_image_with_elements"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layoutDescription="@xml/demo_020_carousel_scene">

    <LinearLayout
        android:id="@+id/imageView0"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="5dp"
        android:orientation="vertical"
        android:scaleType="centerCrop"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/imageView1"
        app:layout_constraintTop_toTopOf="parent">

        <include
            layout="@layout/match_statistic"
            android:background="@drawable/layout_rounded"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="5dp"
        android:orientation="vertical"
        android:scaleType="centerCrop"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/imageView2"
        app:layout_constraintTop_toTopOf="parent">

        <include
            layout="@layout/match_statistic"
            android:background="@drawable/layout_rounded"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/imageView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:scaleType="centerCrop"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <include
            layout="@layout/match_statistic"
            android:background="@drawable/layout_rounded"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/imageView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="5dp"
        android:orientation="vertical"
        android:scaleType="centerCrop"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@+id/imageView2"
        app:layout_constraintTop_toTopOf="parent">

        <include
            layout="@layout/match_statistic"
            android:background="@drawable/layout_rounded"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/imageView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="5dp"
        android:orientation="vertical"
        android:scaleType="centerCrop"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@+id/imageView3"
        app:layout_constraintTop_toTopOf="parent">

        <include
            layout="@layout/match_statistic"
            android:background="@drawable/layout_rounded"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_begin="50dp" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_end="50dp" />

    <androidx.constraintlayout.helper.widget.Carousel
        android:id="@+id/carousel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:carousel_backwardTransition="@+id/backward"
        app:carousel_firstView="@+id/imageView2"
        app:carousel_forwardTransition="@+id/forward"
        app:carousel_nextState="@+id/next"
        app:carousel_previousState="@+id/previous"
        app:carousel_touchUpMode="carryVelocity"
        app:carousel_touchUp_dampeningFactor="0.8"
        app:constraint_referenced_ids="imageView0,imageView1,imageView2,imageView3,imageView4" />
</androidx.constraintlayout.motion.widget.MotionLayout>

内容的提问来源于stack exchange,提问作者Valentin Cerneanu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 23:45:03