backup. before shop update
This commit is contained in:
198
lib/widgets/general/read_more_text.dart
Normal file
198
lib/widgets/general/read_more_text.dart
Normal file
@@ -0,0 +1,198 @@
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
enum TrimMode {
|
||||
Length,
|
||||
Line,
|
||||
}
|
||||
|
||||
class ReadMoreText extends StatefulWidget {
|
||||
const ReadMoreText(
|
||||
this.data, {
|
||||
Key key,
|
||||
this.trimExpandedText = ' read less',
|
||||
this.trimCollapsedText = ' ...read more',
|
||||
this.colorClickableText,
|
||||
this.trimLength = 240,
|
||||
this.trimLines = 2,
|
||||
this.trimMode = TrimMode.Length,
|
||||
this.style,
|
||||
this.textAlign,
|
||||
this.textDirection,
|
||||
this.locale,
|
||||
this.textScaleFactor,
|
||||
this.semanticsLabel,
|
||||
}) : assert(data != null),
|
||||
super(key: key);
|
||||
|
||||
final String data;
|
||||
final String trimExpandedText;
|
||||
final String trimCollapsedText;
|
||||
final Color colorClickableText;
|
||||
final int trimLength;
|
||||
final int trimLines;
|
||||
final TrimMode trimMode;
|
||||
final TextStyle style;
|
||||
final TextAlign textAlign;
|
||||
final TextDirection textDirection;
|
||||
final Locale locale;
|
||||
final double textScaleFactor;
|
||||
final String semanticsLabel;
|
||||
|
||||
@override
|
||||
ReadMoreTextState createState() => ReadMoreTextState();
|
||||
}
|
||||
|
||||
const String _kEllipsis = '\u2026';
|
||||
|
||||
const String _kLineSeparator = '\u2028';
|
||||
|
||||
class ReadMoreTextState extends State<ReadMoreText> {
|
||||
bool _readMore = true;
|
||||
|
||||
void _onTapLink() {
|
||||
setState(() => _readMore = !_readMore);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context);
|
||||
TextStyle effectiveTextStyle = widget.style;
|
||||
if (widget.style == null || widget.style.inherit) {
|
||||
effectiveTextStyle = defaultTextStyle.style.merge(widget.style);
|
||||
}
|
||||
|
||||
final textAlign =
|
||||
widget.textAlign ?? defaultTextStyle.textAlign ?? TextAlign.start;
|
||||
final textDirection = widget.textDirection ?? Directionality.of(context);
|
||||
final textScaleFactor =
|
||||
widget.textScaleFactor ?? MediaQuery.textScaleFactorOf(context);
|
||||
final overflow = defaultTextStyle.overflow;
|
||||
final locale =
|
||||
widget.locale ?? Localizations.localeOf(context);
|
||||
|
||||
final colorClickableText =
|
||||
widget.colorClickableText ?? Theme.of(context).accentColor;
|
||||
|
||||
TextSpan link = TextSpan(
|
||||
text: _readMore ? widget.trimCollapsedText : widget.trimExpandedText,
|
||||
style: effectiveTextStyle.copyWith(
|
||||
color: colorClickableText,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()..onTap = _onTapLink,
|
||||
);
|
||||
|
||||
Widget result = LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints constraints) {
|
||||
assert(constraints.hasBoundedWidth);
|
||||
final double maxWidth = constraints.maxWidth;
|
||||
|
||||
// Create a TextSpan with data
|
||||
final text = TextSpan(
|
||||
style: effectiveTextStyle,
|
||||
text: widget.data,
|
||||
);
|
||||
|
||||
// Layout and measure link
|
||||
TextPainter textPainter = TextPainter(
|
||||
text: link,
|
||||
textAlign: textAlign,
|
||||
textDirection: textDirection,
|
||||
textScaleFactor: textScaleFactor,
|
||||
maxLines: widget.trimLines,
|
||||
ellipsis: overflow == TextOverflow.ellipsis ? _kEllipsis : null,
|
||||
locale: locale,
|
||||
);
|
||||
textPainter.layout(minWidth: constraints.minWidth, maxWidth: maxWidth);
|
||||
final linkSize = textPainter.size;
|
||||
|
||||
// Layout and measure text
|
||||
textPainter.text = text;
|
||||
textPainter.layout(minWidth: constraints.minWidth, maxWidth: maxWidth);
|
||||
final textSize = textPainter.size;
|
||||
|
||||
print('linkSize $linkSize textSize $textSize');
|
||||
|
||||
// Get the endIndex of data
|
||||
bool linkLongerThanLine = false;
|
||||
int endIndex;
|
||||
|
||||
if (linkSize.width < maxWidth) {
|
||||
final pos = textPainter.getPositionForOffset(Offset(
|
||||
textSize.width - linkSize.width,
|
||||
textSize.height,
|
||||
));
|
||||
endIndex = textPainter.getOffsetBefore(pos.offset);
|
||||
}
|
||||
else {
|
||||
var pos = textPainter.getPositionForOffset(
|
||||
textSize.bottomLeft(Offset.zero),
|
||||
);
|
||||
endIndex = pos.offset;
|
||||
linkLongerThanLine = true;
|
||||
}
|
||||
|
||||
var textSpan;
|
||||
switch (widget.trimMode) {
|
||||
case TrimMode.Length:
|
||||
if (widget.trimLength < widget.data.length) {
|
||||
textSpan = TextSpan(
|
||||
style: effectiveTextStyle,
|
||||
text: _readMore
|
||||
? widget.data.substring(0, widget.trimLength)
|
||||
: widget.data,
|
||||
children: <TextSpan>[link],
|
||||
);
|
||||
} else {
|
||||
textSpan = TextSpan(
|
||||
style: effectiveTextStyle,
|
||||
text: widget.data,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case TrimMode.Line:
|
||||
if (textPainter.didExceedMaxLines) {
|
||||
textSpan = TextSpan(
|
||||
style: effectiveTextStyle,
|
||||
text: _readMore
|
||||
? widget.data.substring(0, endIndex) +
|
||||
(linkLongerThanLine ? _kLineSeparator : '')
|
||||
: widget.data,
|
||||
children: <TextSpan>[link],
|
||||
);
|
||||
} else {
|
||||
textSpan = TextSpan(
|
||||
style: effectiveTextStyle,
|
||||
text: widget.data,
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw Exception(
|
||||
'TrimMode type: ${widget.trimMode} is not supported');
|
||||
}
|
||||
|
||||
return RichText(
|
||||
textAlign: textAlign,
|
||||
textDirection: textDirection,
|
||||
softWrap: true,
|
||||
//softWrap,
|
||||
overflow: TextOverflow.clip,
|
||||
//overflow,
|
||||
textScaleFactor: textScaleFactor,
|
||||
text: textSpan,
|
||||
);
|
||||
},
|
||||
);
|
||||
if (widget.semanticsLabel != null) {
|
||||
result = Semantics(
|
||||
textDirection: widget.textDirection,
|
||||
label: widget.semanticsLabel,
|
||||
child: ExcludeSemantics(
|
||||
child: result,
|
||||
),
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user