使 CircleBorder 封装整个子部件
Make CircleBorder encapsulate the whole child widget
我正在尝试制作一个圆形的 ElevatedButton,但遇到格式问题:边框的大小似乎只考虑了子部件的高度,而不是宽度。为了说明这一点:
return ElevatedButton(
style: ElevatedButton.styleFrom(
shape: CircleBorder(),
),
onPressed: () {},
child: Text(
"I want the circle border\nto encapsulate all the text"
),
);
产生这个结果:
我想弄清楚如何让圆形边框环绕整个文本,无需对任何固定大小进行硬编码或通过使用填充来破解它,因为我想要它能够响应文本内容和大小的变化。我该怎么做?
编辑:圆形边框是一个严格的要求,因此答案已更新。
使用 FloatingActionButton
完成工作
SizedBox(
height: 200,
width: 200,
child: FloatingActionButton(
onPressed: () {},
child: const Text("I want the circle border\nto encapsulate all the text"),
),
);
SizedBox 是给按钮尺寸所必需的。
旧答案
添加 StadiumBorder()
将解决您的问题。
ElevatedButton(
style: ElevatedButton.styleFrom(
shape: StadiumBorder(),
),
onPressed: () {},
child: Text(
"I want the circle border\nto encapsulate all the text"
),
);
感谢@pskink 的评论,解决方案是调整 CircleBorder 以在绘制边界路径时使用最长边而不是最短边。这是:
class EncapsulatingCircularBorder extends OutlinedBorder {
/// Create a circle border.
///
/// The [side] argument must not be null.
const EncapsulatingCircularBorder({ BorderSide side = BorderSide.none }) : assert(side != null), super(side: side);
@override
EdgeInsetsGeometry get dimensions {
return EdgeInsets.all(side.width);
}
@override
ShapeBorder scale(double t) => EncapsulatingCircularBorder(side: side.scale(t));
@override
ShapeBorder? lerpFrom(ShapeBorder? a, double t) {
if (a is EncapsulatingCircularBorder)
return EncapsulatingCircularBorder(side: BorderSide.lerp(a.side, side, t));
return super.lerpFrom(a, t);
}
@override
ShapeBorder? lerpTo(ShapeBorder? b, double t) {
if (b is EncapsulatingCircularBorder)
return EncapsulatingCircularBorder(side: BorderSide.lerp(side, b.side, t));
return super.lerpTo(b, t);
}
@override
Path getInnerPath(Rect rect, { TextDirection? textDirection }) {
return Path()
..addOval(Rect.fromCircle(
center: rect.center,
// Changed this from rect.shortestSide to longestSide
radius: math.max(0.0, rect.longestSide / 2.0 - side.width),
));
}
@override
Path getOuterPath(Rect rect, { TextDirection? textDirection }) {
return Path()
..addOval(Rect.fromCircle(
center: rect.center,
// Changed this from rect.shortestSide to longestSide
radius: rect.longestSide / 2.0,
));
}
@override
EncapsulatingCircularBorder copyWith({ BorderSide? side }) {
return EncapsulatingCircularBorder(side: side ?? this.side);
}
@override
void paint(Canvas canvas, Rect rect, { TextDirection? textDirection }) {
switch (side.style) {
case BorderStyle.none:
break;
case BorderStyle.solid:
canvas.drawCircle(rect.center, (rect.shortestSide - side.width) / 2.0, side.toPaint());
}
}
@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType)
return false;
return other is EncapsulatingCircularBorder
&& other.side == side;
}
@override
int get hashCode => side.hashCode;
@override
String toString() {
return '${objectRuntimeType(this, 'EncapsulatingCircularBorder')}($side)';
}
}
我正在尝试制作一个圆形的 ElevatedButton,但遇到格式问题:边框的大小似乎只考虑了子部件的高度,而不是宽度。为了说明这一点:
return ElevatedButton(
style: ElevatedButton.styleFrom(
shape: CircleBorder(),
),
onPressed: () {},
child: Text(
"I want the circle border\nto encapsulate all the text"
),
);
产生这个结果:
我想弄清楚如何让圆形边框环绕整个文本,无需对任何固定大小进行硬编码或通过使用填充来破解它,因为我想要它能够响应文本内容和大小的变化。我该怎么做?
编辑:圆形边框是一个严格的要求,因此答案已更新。
使用 FloatingActionButton
完成工作
SizedBox(
height: 200,
width: 200,
child: FloatingActionButton(
onPressed: () {},
child: const Text("I want the circle border\nto encapsulate all the text"),
),
);
SizedBox 是给按钮尺寸所必需的。
旧答案
添加 StadiumBorder()
将解决您的问题。
ElevatedButton(
style: ElevatedButton.styleFrom(
shape: StadiumBorder(),
),
onPressed: () {},
child: Text(
"I want the circle border\nto encapsulate all the text"
),
);
感谢@pskink 的评论,解决方案是调整 CircleBorder 以在绘制边界路径时使用最长边而不是最短边。这是:
class EncapsulatingCircularBorder extends OutlinedBorder {
/// Create a circle border.
///
/// The [side] argument must not be null.
const EncapsulatingCircularBorder({ BorderSide side = BorderSide.none }) : assert(side != null), super(side: side);
@override
EdgeInsetsGeometry get dimensions {
return EdgeInsets.all(side.width);
}
@override
ShapeBorder scale(double t) => EncapsulatingCircularBorder(side: side.scale(t));
@override
ShapeBorder? lerpFrom(ShapeBorder? a, double t) {
if (a is EncapsulatingCircularBorder)
return EncapsulatingCircularBorder(side: BorderSide.lerp(a.side, side, t));
return super.lerpFrom(a, t);
}
@override
ShapeBorder? lerpTo(ShapeBorder? b, double t) {
if (b is EncapsulatingCircularBorder)
return EncapsulatingCircularBorder(side: BorderSide.lerp(side, b.side, t));
return super.lerpTo(b, t);
}
@override
Path getInnerPath(Rect rect, { TextDirection? textDirection }) {
return Path()
..addOval(Rect.fromCircle(
center: rect.center,
// Changed this from rect.shortestSide to longestSide
radius: math.max(0.0, rect.longestSide / 2.0 - side.width),
));
}
@override
Path getOuterPath(Rect rect, { TextDirection? textDirection }) {
return Path()
..addOval(Rect.fromCircle(
center: rect.center,
// Changed this from rect.shortestSide to longestSide
radius: rect.longestSide / 2.0,
));
}
@override
EncapsulatingCircularBorder copyWith({ BorderSide? side }) {
return EncapsulatingCircularBorder(side: side ?? this.side);
}
@override
void paint(Canvas canvas, Rect rect, { TextDirection? textDirection }) {
switch (side.style) {
case BorderStyle.none:
break;
case BorderStyle.solid:
canvas.drawCircle(rect.center, (rect.shortestSide - side.width) / 2.0, side.toPaint());
}
}
@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType)
return false;
return other is EncapsulatingCircularBorder
&& other.side == side;
}
@override
int get hashCode => side.hashCode;
@override
String toString() {
return '${objectRuntimeType(this, 'EncapsulatingCircularBorder')}($side)';
}
}