可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
My Container having a description about movies.
Initially i want to show only few lines of description. And below to that there should be a link (more...), After Tapping more... all content of description should be get displayed.
For example check this JQuery plugin.
回答1:
you can do that this way
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
home: new HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
final String description =
"Flutter is Google’s mobile UI framework for crafting high-quality native interfaces on iOS and Android in record time. Flutter works with existing code, is used by developers and organizations around the world, and is free and open source.";
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: const Text("Demo App"),
),
body: new Container(
child: new DescriptionTextWidget(text: description),
),
);
}
}
class DescriptionTextWidget extends StatefulWidget {
final String text;
DescriptionTextWidget({@required this.text});
@override
_DescriptionTextWidgetState createState() => new _DescriptionTextWidgetState();
}
class _DescriptionTextWidgetState extends State<DescriptionTextWidget> {
String firstHalf;
String secondHalf;
bool flag = true;
@override
void initState() {
super.initState();
if (widget.text.length > 50) {
firstHalf = widget.text.substring(0, 50);
secondHalf = widget.text.substring(50, widget.text.length);
} else {
firstHalf = widget.text;
secondHalf = "";
}
}
@override
Widget build(BuildContext context) {
return new Container(
padding: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
child: secondHalf.isEmpty
? new Text(firstHalf)
: new Column(
children: <Widget>[
new Text(flag ? (firstHalf + "...") : (firstHalf + secondHalf)),
new InkWell(
child: new Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
new Text(
flag ? "show more" : "show less",
style: new TextStyle(color: Colors.blue),
),
],
),
onTap: () {
setState(() {
flag = !flag;
});
},
),
],
),
);
}
}
回答2:
A simple example
class ExpandableText extends StatefulWidget {
ExpandableText(this.text);
final String text;
bool isExpanded = false;
@override
_ExpandableTextState createState() => new _ExpandableTextState();
}
class _ExpandableTextState extends State<ExpandableText> {
@override
Widget build(BuildContext context) {
return new Column(children: <Widget>[
new ConstrainedBox(
constraints: widget.isExpanded
? new BoxConstraints()
: new BoxConstraints(maxHeight: 50.0),
child: new Text(
widget.text,
softWrap: true,
overflow: TextOverflow.fade,
)),
widget.isExpanded
? new Container()
: new FlatButton(
child: const Text('...'),
onPressed: () => setState(() => widget.isExpanded = true))
]);
}
}
with animation
class ExpandableText extends StatefulWidget {
ExpandableText(this.text);
final String text;
bool isExpanded = false;
@override
_ExpandableTextState createState() => new _ExpandableTextState();
}
class _ExpandableTextState extends State<ExpandableText>
with TickerProviderStateMixin<ExpandableText> {
@override
Widget build(BuildContext context) {
return new Column(children: <Widget>[
new AnimatedSize(
vsync: this,
duration: const Duration(milliseconds: 500),
child: new ConstrainedBox(
constraints: widget.isExpanded
? new BoxConstraints()
: new BoxConstraints(maxHeight: 50.0),
child: new Text(
widget.text,
softWrap: true,
overflow: TextOverflow.fade,
))),
widget.isExpanded
? new ConstrainedBox(constraints: new BoxConstraints())
: new FlatButton(
child: const Text('...'),
onPressed: () => setState(() => widget.isExpanded = true))
]);
}
}
回答3:
Try this.
Watch the output from here ( Video )
or refer below images
import 'package:flutter/material.dart';
class DemoPage extends StatefulWidget {
final Widget child;
DemoPage({Key key, this.child}) : super(key: key);
_DemoPageState createState() => _DemoPageState();
}
class _DemoPageState extends State<DemoPage> {
String descText = "Description Line 1\nDescription Line 2\nDescription Line 3\nDescription Line 4\nDescription Line 5\nDescription Line 6\nDescription Line 7\nDescription Line 8";
bool descTextShowFlag = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("DemoPage"),
),
body: new Container(
margin: EdgeInsets.all(16.0),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(descText,
maxLines: descTextShowFlag ? 8 : 2,textAlign: TextAlign.start),
InkWell(
onTap: (){ setState(() {
descTextShowFlag = !descTextShowFlag;
}); },
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
descTextShowFlag ? Text("Show Less",style: TextStyle(color: Colors.blue),) : Text("Show More",style: TextStyle(color: Colors.blue))
],
),
),
],
),
),
);
}
}
回答4:
Please use package flutter-expandable.
This package can produce an effect of expanding an image or text.
https://github.com/aryzhov/flutter-expandable
import 'package:expandable/expandable.dart';
...
ExpandablePanel(
header: Text( content,
maxLines: 2,
style: Theme.of(context).textTheme.body2,
),
expanded: Align(
alignment: Alignment.centerLeft,
child: Text(
content,
softWrap: true,
)),
tapHeaderToExpand: true,
hasIcon: true,
),
回答5:
ExpandableText with regrex validation as well.
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
class ExpandableText extends StatefulWidget {
ExpandableText(this.text);
final String text;
// bool isExpanded = false;
@override
_ExpandableTextState createState() => new _ExpandableTextState();
}
class _ExpandableTextState extends State<ExpandableText> {
String text;
bool canExpand = false;
bool isExpand = false;
@override
Widget build(BuildContext context) {
//
canExpand = widget.text != null && widget.text.length >= 150;
text = canExpand
? (isExpand ? widget.text : widget.text.substring(0, 150))
: (widget.text);
return canExpand
? Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
buildTextWithLinks(text.trim()),
GestureDetector(
onTap: () {
setState(() {
isExpand = !isExpand;
});
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Text(isExpand ? ' ... show less' : ' ... show more'
),
),
),
],
)
: Text(text != null ? text : "");
}
}
Text buildTextWithLinks(String textToLink, {String text}) =>
Text.rich(TextSpan(children: linkify(textToLink)));
Future<void> openUrl(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
const String urlPattern =
r"(https?|http)://([-A-Z0-9.]+)(/[-A-Z0-9+&@#/%=~_|!:,.;]*)?(\?[A-Z0-9+&@#/%=~_|!:,.;]*)?";
const String emailPattern = r'\S+@\S+';
const String phonePattern = r'[\d-]{9,}';
final RegExp linkRegExp = RegExp(
'($urlPattern)|($emailPattern)|($phonePattern)',
caseSensitive: false);
WidgetSpan buildLinkComponent(String text, String linkToOpen) => WidgetSpan(
child: InkWell(
child: Text(
text,
style: TextStyle(
color: Colors.red,
decoration: TextDecoration.underline,
),
),
onTap: () => openUrl(linkToOpen),
));
List<InlineSpan> linkify(String text) {
final List<InlineSpan> list = <InlineSpan>[];
final RegExpMatch match = linkRegExp.firstMatch(text);
if (match == null) {
list.add(TextSpan(text: text));
return list;
}
if (match.start > 0) {
list.add(TextSpan(text: text.substring(0, match.start)));
}
final String linkText = match.group(0);
if (linkText.contains(RegExp(urlPattern, caseSensitive: false))) {
list.add(buildLinkComponent(linkText, linkText));
} else if (linkText.contains(RegExp(emailPattern, caseSensitive: false))) {
list.add(buildLinkComponent(linkText, 'mailto:$linkText'));
} else if (linkText.contains(RegExp(phonePattern, caseSensitive: false))) {
list.add(buildLinkComponent(linkText, 'tel:$linkText'));
} else {
throw 'Unexpected match: $linkText';
}
list.addAll(linkify(text.substring(match.start + linkText.length)));
return list;
}
回答6:
Widget _text() {
var exceeded;
return LayoutBuilder(builder: (context, size) {
// Build the textspan
var span = TextSpan(
text:
"The red-tailed tropicbird is a seabird native to the tropical Indian and Pacific Oceans. One of three closely related species of tropicbird, it has four subspecies. Text wrapping is quite a pain for me too. I find that putting Text in a Container and then wrapping that container in a Expanded/Flexible works well.",
style: Theme.of(context).textTheme.body1.copyWith(color: Colors.white),
);
// Use a textpainter to determine if it will exceed max lines
var tp = TextPainter(
maxLines: _maxLine.toInt(),
textAlign: TextAlign.left,
textDirection: TextDirection.ltr,
text: span,
);
// trigger it to layout
tp.layout(maxWidth: size.maxWidth);
// whether the text overflowed or not
exceeded = tp.didExceedMaxLines;
// return Column(children: <Widget>[
return Container(
child: exceeded && seeMoreClicked
? _seeMoreLess(span, "See Less ")
: exceeded && !seeMoreClicked
? _seeMoreLess(span, "See More", 3)
: Text.rich(
span,
overflow: TextOverflow.visible,
),
);
});
}
Widget _seeMoreLess(TextSpan span, String _text, [int maxLine = 0]) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
maxLine > 0
? Text.rich(
span,
overflow: TextOverflow.ellipsis,
maxLines: 3,
)
: Text.rich(
span,
overflow: TextOverflow.visible,
),
InkWell(
child: Text(
_text,
style: Theme.of(context)
.textTheme
.body1
.copyWith(color: Colors.blue),
),
onTap: () {
setState(() {
seeMoreClicked = !seeMoreClicked;
});
}),
],
);