Flutter Button Stack - 图标需要与父级重叠
Flutter Button Stack - Icon needs to overlap parent
我有一个按钮,要求将图标稍微放在矩形之外。
我可以使用 Stack 完成此操作,但是按钮边框与图标重叠,如您在此处所见:
它应该是这样的:
这是我的代码:
OutlinedButton(
style: scansButtonStyle,
onPressed: () {}, // TODO: add later
child: Stack(clipBehavior: Clip.none, children: [
Padding(
padding: const EdgeInsets.only(left: 50.0),
child: Text('CONNECT'),
),
Positioned(
bottom: 0,
left: -20,
child: CircleAvatar(
radius: 30,
backgroundColor: Colors.black,
child: CircleAvatar(
radius: 27,
backgroundColor: Colors.white,
child: Icon(
Icons.bluetooth_connected,
color: Colors.black,
size: 48,
),
),
),
),
]),
),
和样式:
final ButtonStyle scansButtonStyle = OutlinedButton.styleFrom(
alignment: Alignment.centerLeft,
primary: Colors.black,
backgroundColor: Color(0xfffcd722),
minimumSize: Size(242, 48),
padding: EdgeInsets.fromLTRB(20, 3, 20, 3),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.zero,
bottomRight: Radius.circular(16),
bottomLeft: Radius.zero),
),
textStyle: const TextStyle(
color: Colors.black,
fontWeight: FontWeight.w600,
fontSize: 34,
fontFamily: 'HP',
),
side: BorderSide(
color: Colors.black,
width: 3.0,
style: BorderStyle.solid,
));
我通过将按钮和图标放在堆栈中(而不是按钮内部的堆栈)实现了所需的视觉效果。
这里的缺点是,如果我现在单击图标,它不再触发按钮。
所以这个答案不太正确....
Stack(
clipBehavior: Clip.none,
children: [
OutlinedButton(
style: scansButtonStyle,
onPressed: () {}, // TODO: add later
child: Padding(
padding: const EdgeInsets.only(left: 50.0),
child: Text('CONNECT'),
),
),
Positioned(
bottom: 6,
left: 0,
child: CircleAvatar(
radius: 30,
backgroundColor: Colors.black,
child: CircleAvatar(
radius: 27,
backgroundColor: Colors.white,
child: Icon(
Icons.bluetooth_connected,
color: Colors.black,
size: 48,
),
),
),
),
]),
我已经更正了代码。
主要变化是:
- 将 Outlined 按钮放入 Stack 中
- 将 CircleAvatar 更改为带有装饰的简单容器(为此您真的需要 CircleAvatar 吗?您会以任何方式为图标设置动画吗?如果没有,那么简单的容器可能会更好)
- 将 IgnorePointer 添加到图标,使其忽略点击事件并将其向下传递给按钮本身(这是为了即使在按下图标时也能产生涟漪效果)
- 用 FittedBox 小部件包裹 Icon 并向外部容器添加填充。这将允许我们的图标根据外圈的大小动态改变它的大小。
- 向文本小部件添加了一些参数,以便在文本长于宽度时不会破坏设计。您可以使用 Text('CONNECT' * 10)
检查它
Stack(
clipBehavior: Clip.none,
children: [
OutlinedButton(
onPressed: () {},
style: scansButtonStyle,
child: Padding(
padding: const EdgeInsets.only(left: 50.0),
child: Text(
'CONNECT',
maxLines: 1,
overflow: TextOverflow.ellipsis,
textScaleFactor: 1.0, // We do not want OS preferences (text scale option) to break our button's design
),
),
),
Positioned(
bottom: 0,
child: IgnorePointer(
//ignore touch events, so that the Outlined button triggers touch animation when pressed on the icon
child: SizedBox(
width: 60.0,
child: AspectRatio(
aspectRatio: 1.0,
child: Container(
padding: EdgeInsets.all(6.0),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.black,
width: 3.0,
),
shape: BoxShape.circle,
),
child: FittedBox(
child: Icon(
Icons.bluetooth_connected,
color: Colors.black,
),
),
),
),
),
),
),
],
)
代码可能需要进一步调整,但您会明白的。
另请注意,图标的顶部缺口不占用任何 space(因为 Clip.none 并且它在堆栈中的位置)。您可以通过将按钮包裹在彩色容器中来对其进行测试。
如果您不喜欢 SizedBox 中的 AspectRatio 这个想法 - 在 Container 中将其改回 width/height。
我有一个按钮,要求将图标稍微放在矩形之外。
我可以使用 Stack 完成此操作,但是按钮边框与图标重叠,如您在此处所见:
它应该是这样的:
这是我的代码:
OutlinedButton(
style: scansButtonStyle,
onPressed: () {}, // TODO: add later
child: Stack(clipBehavior: Clip.none, children: [
Padding(
padding: const EdgeInsets.only(left: 50.0),
child: Text('CONNECT'),
),
Positioned(
bottom: 0,
left: -20,
child: CircleAvatar(
radius: 30,
backgroundColor: Colors.black,
child: CircleAvatar(
radius: 27,
backgroundColor: Colors.white,
child: Icon(
Icons.bluetooth_connected,
color: Colors.black,
size: 48,
),
),
),
),
]),
),
和样式:
final ButtonStyle scansButtonStyle = OutlinedButton.styleFrom(
alignment: Alignment.centerLeft,
primary: Colors.black,
backgroundColor: Color(0xfffcd722),
minimumSize: Size(242, 48),
padding: EdgeInsets.fromLTRB(20, 3, 20, 3),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.zero,
bottomRight: Radius.circular(16),
bottomLeft: Radius.zero),
),
textStyle: const TextStyle(
color: Colors.black,
fontWeight: FontWeight.w600,
fontSize: 34,
fontFamily: 'HP',
),
side: BorderSide(
color: Colors.black,
width: 3.0,
style: BorderStyle.solid,
));
我通过将按钮和图标放在堆栈中(而不是按钮内部的堆栈)实现了所需的视觉效果。
这里的缺点是,如果我现在单击图标,它不再触发按钮。
所以这个答案不太正确....
Stack(
clipBehavior: Clip.none,
children: [
OutlinedButton(
style: scansButtonStyle,
onPressed: () {}, // TODO: add later
child: Padding(
padding: const EdgeInsets.only(left: 50.0),
child: Text('CONNECT'),
),
),
Positioned(
bottom: 6,
left: 0,
child: CircleAvatar(
radius: 30,
backgroundColor: Colors.black,
child: CircleAvatar(
radius: 27,
backgroundColor: Colors.white,
child: Icon(
Icons.bluetooth_connected,
color: Colors.black,
size: 48,
),
),
),
),
]),
我已经更正了代码。
主要变化是:
- 将 Outlined 按钮放入 Stack 中
- 将 CircleAvatar 更改为带有装饰的简单容器(为此您真的需要 CircleAvatar 吗?您会以任何方式为图标设置动画吗?如果没有,那么简单的容器可能会更好)
- 将 IgnorePointer 添加到图标,使其忽略点击事件并将其向下传递给按钮本身(这是为了即使在按下图标时也能产生涟漪效果)
- 用 FittedBox 小部件包裹 Icon 并向外部容器添加填充。这将允许我们的图标根据外圈的大小动态改变它的大小。
- 向文本小部件添加了一些参数,以便在文本长于宽度时不会破坏设计。您可以使用 Text('CONNECT' * 10) 检查它
Stack(
clipBehavior: Clip.none,
children: [
OutlinedButton(
onPressed: () {},
style: scansButtonStyle,
child: Padding(
padding: const EdgeInsets.only(left: 50.0),
child: Text(
'CONNECT',
maxLines: 1,
overflow: TextOverflow.ellipsis,
textScaleFactor: 1.0, // We do not want OS preferences (text scale option) to break our button's design
),
),
),
Positioned(
bottom: 0,
child: IgnorePointer(
//ignore touch events, so that the Outlined button triggers touch animation when pressed on the icon
child: SizedBox(
width: 60.0,
child: AspectRatio(
aspectRatio: 1.0,
child: Container(
padding: EdgeInsets.all(6.0),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.black,
width: 3.0,
),
shape: BoxShape.circle,
),
child: FittedBox(
child: Icon(
Icons.bluetooth_connected,
color: Colors.black,
),
),
),
),
),
),
),
],
)
代码可能需要进一步调整,但您会明白的。
另请注意,图标的顶部缺口不占用任何 space(因为 Clip.none 并且它在堆栈中的位置)。您可以通过将按钮包裹在彩色容器中来对其进行测试。
如果您不喜欢 SizedBox 中的 AspectRatio 这个想法 - 在 Container 中将其改回 width/height。