Android MotionLayout滑动时如何修改其高度?
解决方案:修复MotionLayout滑动时的灰色残留问题并实现wrap_content高度
核心问题分析
你当前的实现是通过translationY将Header平移出视野,但MotionLayout本身高度未变化,导致其LightGray背景残留。同时未正确配置约束让MotionLayout自适应高度,无法满足wrap_content的需求。
步骤1:修改Composable代码
@OptIn(ExperimentalMotionApi::class) @Composable fun AddressableMotionLayout( item: XCCAddressableReference, listener: AddressableInfoContentAdapter.AddressableClickListener?, ) { val context = LocalContext.current val motionScene = remember { context.resources .openRawResource(R.raw.motion_scene) .readBytes() .decodeToString() } val motionState = rememberMotionLayoutState() val corners = 10f - ((motionState.currentProgress * 10)).coerceAtMost(10f) MotionLayout( motionScene = MotionScene(content = motionScene), motionLayoutState = motionState, modifier = Modifier.wrapContentHeight() // 关键:让布局高度由内部约束决定 ) { Box( modifier = Modifier .layoutId("header") .background(colorResource(id = R.color.xelionMainColor)) ) Box( modifier = Modifier .fillMaxWidth() .background(Color.White, shape = RoundedCornerShape(topStart = corners, topEnd = corners)) .layoutId("contentBg") .padding(top = 16.dp) ) Button( onClick = {}, colors = ButtonDefaults.buttonColors(contentColor = Color.White), modifier = Modifier.layoutId("menu"), contentPadding = PaddingValues(4.dp), ) { Icon( Icons.Default.ArrowBack, contentDescription = "返回" ) } } }
步骤2:更新motion_scene配置
替换原有的motion_scene内容,移除translationY平移逻辑,改用高度收缩实现Header隐藏:
{ ConstraintSets: { start: { header: { width: 'parent', height: 250, top: ['parent', 'top', 0], start: ['parent', 'start', 0], end: ['parent', 'end', 0], alpha: 1 }, contentBg: { width: 'parent', top: ['header', 'bottom', 0], bottom: ['parent', 'bottom', 0], start: ['parent', 'start', 0], end: ['parent', 'end', 0] }, menu: { width: 38, height: 38, start: ['parent', 'start', 16], top: ['parent', 'top', 16], }, }, end: { header: { width: 'parent', height: 0, top: ['parent', 'top', 0], start: ['parent', 'start', 0], end: ['parent', 'end', 0], alpha: 0 }, contentBg: { width: 'parent', top: ['parent', 'top', 0], bottom: ['parent', 'bottom', 0], start: ['parent', 'start', 0], end: ['parent', 'end', 0] }, menu: { width: 38, height: 38, start: ['parent', 'start', 16], top: ['parent', 'top', 16], }, } }, Transitions: { default: { from: 'start', to: 'end', onSwipe: { anchor: 'contentBg', direction: 'up', side: 'top', }, keyFrames: { header: { height: [ {value: 250, progress: 0}, {value: 0, progress: 1} ], alpha: [ {value: 1, progress: 0}, {value: 0, progress: 0.8} ] } } } } }
步骤3:集成非Compose视图(如PreferenceCompat)
通过AndroidView将非Compose组件与MotionLayout组合,满足多Fragment复用需求:
@Composable fun AddressableScreen( item: XCCAddressableReference, listener: AddressableInfoContentAdapter.AddressableClickListener? ) { Column(modifier = Modifier.fillMaxSize()) { AddressableMotionLayout(item, listener) AndroidView( factory = { context -> // 初始化PreferenceFragmentCompat并返回视图 val fragment = object : PreferenceFragmentCompat() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.preferences, rootKey) } } fragment.view ?: FrameLayout(context) }, modifier = Modifier.fillMaxSize() ) } }
关键改动说明
- 移除固定背景:去掉MotionLayout的LightGray背景配置,避免残留空白区域
- wrap_content高度:通过
Modifier.wrapContentHeight()让MotionLayout高度随内部约束动态变化 - 替换平移为高度收缩:直接修改Header的height属性实现隐藏,而非平移视图,从根源解决背景残留
- 约束联动:让内容区域的顶部与Header底部绑定,滑动时自动填充Header收缩后的空间
内容的提问来源于stack exchange,提问作者rosu alin
相关产品推荐
相关产品推荐

