我为的内容画了一个形状Text。
我想要背景自动缩放文本,甚至softWrap是真实的。
因此,我需要先获取Text Widget的宽度和高度Widget build(BuildContext context)。
实际上,我正在使用flutter模拟像iOS消息这样的聊天气泡效果。这是iOS版本的教程。创建聊天气泡。
下面的核心代码:
let label = UILabel()
label.numberOfLines = 0
label.font = UIFont.systemFont(ofSize: 18)
label.textColor = .white
label.text = text
let constraintRect = CGSize(width: 0.66 * view.frame.width,
height: .greatestFiniteMagnitude)
let boundingBox = text.boundingRect(with: constraintRect,
options: .usesLineFragmentOrigin,
attributes: [.font: label.font],
context: nil)
label.frame.size = CGSize(width: ceil(boundingBox.width),
height: ceil(boundingBox.height))
let bubbleSize = CGSize(width: label.frame.width + 28,
height: label.frame.height + 20)
let width = bubbleSize.width
let height = bubbleSize.height
Run Code Online (Sandbox Code Playgroud)
=======================================
解决方案
这是我的解决方案。
bubble.dart:
// Define a CustomPainter to paint the bubble background.
class BubblePainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final Paint paint = Paint()
..color = Color(0xff188aff)
..style = PaintingStyle.fill;
final Path bubble = Path()
..moveTo(size.width - 22.0, size.height)
..lineTo(17.0, size.height)
..cubicTo(
7.61, size.height, 0.0, size.height - 7.61, 0.0, size.height - 17.0)
..lineTo(0.0, 17.0)
..cubicTo(0.0, 7.61, 7.61, 0.0, 17.0, 0.0)
..lineTo(size.width - 21, 0.0)
..cubicTo(size.width - 11.61, 0.0, size.width - 4.0, 7.61,
size.width - 4.0, 17.0)
..lineTo(size.width - 4.0, size.height - 11.0)
..cubicTo(size.width - 4.0, size.height - 1.0, size.width, size.height,
size.width, size.height)
..lineTo(size.width + 0.05, size.height - 0.01)
..cubicTo(size.width - 4.07, size.height + 0.43, size.width - 8.16,
size.height - 1.06, size.width - 11.04, size.height - 4.04)
..cubicTo(size.width - 16.0, size.height, size.width - 19.0, size.height,
size.width - 22.0, size.height)
..close();
canvas.drawPath(bubble, paint);
}
@override
bool shouldRepaint(BubblePainter oldPainter) => true;
}
// This is my custom RenderObject.
class BubbleMessage extends SingleChildRenderObjectWidget {
BubbleMessage({
Key key,
this.painter,
Widget child,
}) : super(key: key, child: child);
final CustomPainter painter;
@override
RenderCustomPaint createRenderObject(BuildContext context) {
return RenderCustomPaint(
painter: painter,
);
}
@override
void updateRenderObject(
BuildContext context, RenderCustomPaint renderObject) {
renderObject..painter = painter;
}
}
Run Code Online (Sandbox Code Playgroud)
BubbleMessage像这样使用小部件:
import 'bubble.dart'
...code ...
BubbleMessage(
painter: BubblePainter(),
child: Container(
constraints: BoxConstraints(
maxWidth: 250.0,
minWidth: 50.0,
),
padding: EdgeInsets.symmetric(horizontal: 15.0, vertical: 6.0),
child: Text(
'your text variable',
softWrap: true,
style: TextStyle(
fontSize: 16.0,
),
),
),
),
...code ...
Run Code Online (Sandbox Code Playgroud)
气泡效果:
小智 51
我很抱歉。 这不是对该主题问题的直接回答! 但是如果有人需要获取 Text 小部件的大小 - 这种方法可以提供帮助。它帮助我创建了自定义菜单小部件。
class TextSized extends StatelessWidget {
const TextSized({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
final String text = "Text in one line";
final TextStyle textStyle = TextStyle(
fontSize: 30,
color: Colors.white,
);
final Size txtSize = _textSize(text, textStyle);
// This kind of use - meaningless. It's just an example.
return Container(
color: Colors.blueGrey,
width: txtSize.width,
height: txtSize.height,
child: Text(
text,
style: textStyle,
softWrap: false,
overflow: TextOverflow.clip,
maxLines: 1,
),
);
}
// Here it is!
Size _textSize(String text, TextStyle style) {
final TextPainter textPainter = TextPainter(
text: TextSpan(text: text, style: style), maxLines: 1, textDirection: TextDirection.ltr)
..layout(minWidth: 0, maxWidth: double.infinity);
return textPainter.size;
}
}
Run Code Online (Sandbox Code Playgroud)
Ami*_*r_P 30
其他答案的问题是,如果您使用Text小部件显示文本并使用测量结果对其进行约束而不考虑默认字体系列和比例因子,那么您将得到错误的结果,因为Text小部件textScaleFactor默认使用设备并将其传递给其中的RichText小部件. 这是测量文本大小的正确代码:
final Size size = (TextPainter(
text: TextSpan(text: text, style: textStyle),
maxLines: 1,
textScaleFactor: MediaQuery.of(context).textScaleFactor,
textDirection: TextDirection.ltr)
..layout())
.size;
Run Code Online (Sandbox Code Playgroud)
Iva*_*iuk 12
多行文本高度(Dmitry_Kovalov 的修改变体)
import 'package:flutter/cupertino.dart';
extension StringExtension on String {
double textHeight(TextStyle style, double textWidth) {
final TextPainter textPainter = TextPainter(
text: TextSpan(text: this, style: style),
textDirection: TextDirection.ltr,
maxLines: 1,
)..layout(minWidth: 0, maxWidth: double.infinity);
final countLines = (textPainter.size.width / textWidth).ceil();
final height = countLines * textPainter.size.height;
return height;
}
}
Run Code Online (Sandbox Code Playgroud)
import 'dart:ui' as ui;如果ltr不可见,您可能需要这样做。然后textDirection: ui.TextDirection.ltr
一个简单的例子:
有关其工作方式的信息,请参见内联注释。
来自https://github.com/flutter/flutter/issues/23247的启示
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Calc Text Size',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Calc Text Size'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
static const String loremIpsum =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod '
'tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim '
'veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea '
'commodo consequat. Duis aute irure dolor in reprehenderit in voluptate '
'velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint '
'occaecat cupidatat non proident, sunt in culpa qui officia deserunt '
'mollit anim id est laborum.';
@override
Widget build(BuildContext context) {
final mq = MediaQuery.of(context);
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(
height: mq.size.height,
width: 240.0,
child: ListView(
padding: EdgeInsets.all(4.0),
children: <Widget>[
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.orange),
),
child: Bubble(
text: TextSpan(
text: loremIpsum,
style: Theme.of(context).textTheme.body1,
),
),
),
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.orange, width: 2.0),
),
padding: EdgeInsets.symmetric(horizontal: 2.0),
child: Bubble(
text: TextSpan(
text: loremIpsum,
style: Theme.of(context).textTheme.body1,
),
),
),
],
),
),
],
),
),
);
}
}
class Bubble extends StatefulWidget {
Bubble({@required this.text});
final TextSpan text;
@override
_BubbleState createState() => new _BubbleState();
}
class _BubbleState extends State<Bubble> {
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
// The text to render
final textWidget = Text.rich(widget.text);
// Calculate the left, top, bottom position of the end of the last text
// line.
final lastBox = _calcLastLineEnd(context, constraints);
// Calculate whether the timestamp fits into the last line or if it has
// to be positioned after the last line.
final fitsLastLine =
constraints.maxWidth - lastBox.right > Timestamp.size.width + 10.0;
return Stack(
children: [
// Ensure the stack is big enough to render the text and the
// timestamp.
SizedBox.fromSize(
size: Size(
constraints.maxWidth,
(fitsLastLine ? lastBox.top : lastBox.bottom) +
10.0 +
Timestamp.size.height,
),
child: Container()),
// Render the text.
textWidget,
// Render the timestamp.
Positioned(
left: constraints.maxWidth - (Timestamp.size.width + 10.0),
top: (fitsLastLine ? lastBox.top : lastBox.bottom) + 5.0,
child: Timestamp(DateTime.now()),
),
],
);
});
}
// Calculate the left, top, bottom position of the end of the last text
// line.
TextBox _calcLastLineEnd(BuildContext context, BoxConstraints constraints) {
final richTextWidget = Text.rich(widget.text).build(context) as RichText;
final renderObject = richTextWidget.createRenderObject(context);
renderObject.layout(constraints);
final lastBox = renderObject
.getBoxesForSelection(TextSelection(
baseOffset: 0, extentOffset: widget.text.toPlainText().length))
.last;
return lastBox;
}
}
class Timestamp extends StatelessWidget {
Timestamp(this.timestamp);
final DateTime timestamp;
/// This size could be calculated similarly to the way the text size in
/// [Bubble] is calculated instead of using magic values.
static final Size size = Size(60.0, 25.0);
@override
Widget build(BuildContext context) => Container(
padding: EdgeInsets.all(3.0),
decoration: BoxDecoration(
color: Colors.greenAccent,
border: Border.all(color: Colors.yellow),
),
child:
Text('${timestamp.hour}:${timestamp.minute}:${timestamp.second}'),
);
}
Run Code Online (Sandbox Code Playgroud)
我没有使用context:
final constraints = BoxConstraints(
maxWidth: 800.0, // maxwidth calculated
minHeight: 0.0,
minWidth: 0.0,
);
RenderParagraph renderParagraph = RenderParagraph(
TextSpan(
text: text,
style: TextStyle(
fontSize: fontSize,
),
),
textDirection: ui.TextDirection.ltr,
maxLines: 1,
);
renderParagraph.layout(constraints);
double textlen = renderParagraph.getMinIntrinsicWidth(fontSize).ceilToDouble();
Run Code Online (Sandbox Code Playgroud)
小智 6
来自 G\xc3\xbcnter Z\xc3\xb6chbauer 的启发
\n\nList<bool> _calcLastLineEnd(String msg) {\n // self-defined constraint\n final constraints = BoxConstraints(\n maxWidth: 800.0, // maxwidth calculated\n minHeight: 30.0,\n minWidth: 80.0,\n );\n final richTextWidget =\n Text.rich(TextSpan(text: msg)).build(context) as RichText;\n final renderObject = richTextWidget.createRenderObject(context);\n renderObject.layout(constraints);\n final boxes = renderObject.getBoxesForSelection(TextSelection(\n baseOffset: 0, extentOffset: TextSpan(text: msg).toPlainText().length));\n bool needPadding = false, needNextline = false;\n if (boxes.length < 2 && boxes.last.right < 630) needPadding = true;\n if (boxes.length < 2 && boxes.last.right > 630) needNextline = true;\n if (boxes.length > 1 && boxes.last.right > 630) needNextline = true;\n return [needPadding, needNextline];\n}\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
6388 次 |
| 最近记录: |