Flutter中如何让Row/Column的先序子组件覆盖后序子组件?
问题:控制Dismissible在Row/Column中的渲染层级,让两侧组件表现一致
演示效果

问题说明
假设我们有一个Widget树,要么是Row中包含水平方向(通过direction参数设置)的Dismissible,要么是Column中包含垂直方向的Dismissible。两种场景下,Dismissible都被另外两个Widget包裹,代码示例如下:
Row( children: <Widget>[ WillAppearBelowDismissibleThatIsBeingSwipedToTheLeft(), Dismissible( direction: DismissDirection.horizontal, child: ...), WillAppearAboveDismissibleThatIsBeingSwipedToTheRight(), ], ) // 另一种场景 Column( children: <Widget>[ WillAppearBelowDismissibleThatIsBeingSwipedUpwards(), Dismissible( direction: DismissDirection.vertical, child: ...), WillAppearAboveDismissibleThatIsBeingSwipedDownwards(), ], )
可以看到,当向某个方向滑动Dismissible时,它会遮挡一侧的Widget,但另一侧不会。我想要实现的是:让Dismissible的子组件在Row或Column的所有Widget下方渲染,或者反过来,让两侧的红色圆圈(测试代码中的组件)表现完全一致。
这里的“先序”和“后序”指的是它们在List中的顺序——列表中越靠后的组件渲染层级越高,从演示动画中能看到一个红色圆圈被Dismissible遮挡,另一个则不会。
可测试代码
import 'package:flutter/material.dart'; void main() => runApp( MaterialApp( home: Scaffold( body: SafeArea( child: Row( children: <Widget>[ Expanded( child: Container( decoration: BoxDecoration( color: Colors.redAccent, shape: BoxShape.circle, ), ), ), Dismissible( key: ObjectKey(0), direction: DismissDirection.horizontal, child: Container( height: 150.0, width: 150.0, decoration: BoxDecoration( color: Colors.amber, shape: BoxShape.circle, ), ), ), Expanded( child: Container( decoration: BoxDecoration( color: Colors.redAccent, shape: BoxShape.circle, ), ), ), ], ), ), ), ), );
解决方案
方案1:让Dismissible在所有组件下方渲染
要实现这个效果,我们可以用Stack替代Row/Column,把Dismissible放在Stack的最底层,然后将左右(或上下)的组件放在上层:
import 'package:flutter/material.dart'; void main() => runApp( MaterialApp( home: Scaffold( body: SafeArea( child: Stack( alignment: Alignment.center, children: [ // 把Dismissible放在最底层 Dismissible( key: ObjectKey(0), direction: DismissDirection.horizontal, child: Container( height: 150.0, width: 150.0, decoration: BoxDecoration( color: Colors.amber, shape: BoxShape.circle, ), ), ), // 用Row来放置左右的红色圆圈,它们会在Dismissible上方 Row( children: [ Expanded( child: Container( decoration: BoxDecoration( color: Colors.redAccent, shape: BoxShape.circle, ), ), ), const SizedBox(width: 150), // 给中间的Dismissible留位置 Expanded( child: Container( decoration: BoxDecoration( color: Colors.redAccent, shape: BoxShape.circle, ), ), ), ], ), ], ), ), ), ), );
这样滑动Dismissible时,它会始终在两个红色圆圈下方,不会遮挡任何一个。
方案2:让Dismissible在所有组件上方渲染
如果想要Dismissible遮挡所有组件,只需要调整Stack中组件的顺序,把Dismissible放在Row/Column的后面:
import 'package:flutter/material.dart'; void main() => runApp( MaterialApp( home: Scaffold( body: SafeArea( child: Stack( alignment: Alignment.center, children: [ // 先放Row,红色圆圈在底层 Row( children: [ Expanded( child: Container( decoration: BoxDecoration( color: Colors.redAccent, shape: BoxShape.circle, ), ), ), const SizedBox(width: 150), Expanded( child: Container( decoration: BoxDecoration( color: Colors.redAccent, shape: BoxShape.circle, ), ), ), ], ), // Dismissible放在上层,滑动时会遮挡所有红色圆圈 Dismissible( key: ObjectKey(0), direction: DismissDirection.horizontal, child: Container( height: 150.0, width: 150.0, decoration: BoxDecoration( color: Colors.amber, shape: BoxShape.circle, ), ), ), ], ), ), ), ), );
方案3:用IndexedStack动态控制层级(可选)
如果需要动态切换Dismissible的层级,可以使用IndexedStack,通过改变index来控制哪个组件在上层:
import 'package:flutter/material.dart'; void main() => runApp( MaterialApp( home: Scaffold( body: SafeArea( child: IndexedStack( index: 0, // 0表示Dismissible在底层,1表示在上层 alignment: Alignment.center, children: [ Dismissible( key: ObjectKey(0), direction: DismissDirection.horizontal, child: Container( height: 150.0, width: 150.0, decoration: BoxDecoration( color: Colors.amber, shape: BoxShape.circle, ), ), ), Row( children: [ Expanded( child: Container( decoration: BoxDecoration( color: Colors.redAccent, shape: BoxShape.circle, ), ), ), const SizedBox(width: 150), Expanded( child: Container( decoration: BoxDecoration( color: Colors.redAccent, shape: BoxShape.circle, ), ), ), ], ), ], ), ), ), ), );
这样你可以根据业务需求随时调整index值,灵活控制渲染层级。
内容的提问来源于stack exchange,提问作者creativecreatorormaybenot
相关产品推荐
相关产品推荐

