Hello friends, Our today’s tutorial is a bit different from others. In today’s tutorial we would make animated collapsible expandable text widget with Read More and Read Less button. The text widget is completely animated and control by 2 buttons. We have seen in many applications or websites when there are a large amount of Text which cannot be shown at once. Then there are Read More Button present at the bottom of text. When user clicks on the Button then the text will start expanding it self using animation until all text has been shown. So we are making this now. The best thing of this tutorial is that we are not using any custom Pub package in our tutorial. So in this tutorial we would learn about Flutter Expandable Collapsible Animated Text Read More.
Contents in this project Flutter Expandable Collapsible Animated Text Read More :-
1. Open your project’s main.dart file and import material.dart package.
1 |
import 'package:flutter/material.dart'; |
2. Creating void main runApp() method and here we would call our main MyApp class.
1 2 3 |
void main() { runApp(MyApp()); } |
3. Creating our first Parent class MyApp extends StatelessWidget. In this class we would call Home class.
1 2 3 4 5 6 7 8 |
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Home(), ); } } |
4. Creating class Home extends StatefulWidget. In this class we would make ReadMoreText class with createState() method to enable mutable state management.
1 2 3 |
class Home extends StatefulWidget { ReadMoreText createState() => ReadMoreText(); } |
5. creating our class ReadMoreText extends State<Home>. This is our main child class and our sample Text is present in this class. Now as you can see there is a custom widget named as ExpandableText which is doing our all animation work. In flutter there are no widget associated with this name, So we have to make it manually. We are writing code for this widget.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class ReadMoreText extends State<Home> { @override Widget build(BuildContext context) { return const SafeArea( child: Scaffold( body: Padding( padding: EdgeInsets.fromLTRB(10, 10, 10, 10), child: ExpandableText( text: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.")), )); } } |
6. Creating our ExpandableText extends StatefulWidget class. In this class first we have to make a Text receiver named as text. Now we have to make ExpandableTextState class with createState() method. All the magic happens in this class.
1 2 3 4 5 6 7 8 |
class ExpandableText extends StatefulWidget { const ExpandableText({Key? key, required this.text}) : super(key: key); final String text; @override ExpandableTextState createState() => ExpandableTextState(); } |
7. Creating our final and most important class ExpandableTextState extends State<ExpandableText> with TickerProviderStateMixin. THIS IS OUR MAIN CLASS AND ALL THE ANIMATION HAPPENS IN THIS CLASS.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
class ExpandableTextState extends State<ExpandableText> with TickerProviderStateMixin { bool expanded = false; @override Widget build(BuildContext context) { return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ AnimatedSize( duration: const Duration(milliseconds: 250), child: ConstrainedBox( constraints: expanded ? const BoxConstraints() : const BoxConstraints(maxHeight: 85), child: Text( widget.text, style: const TextStyle(fontSize: 18), overflow: TextOverflow.fade, ))), expanded ? OutlinedButton.icon( icon: const Icon(Icons.arrow_upward, color: Color(0xFFD50000)), label: const Text( 'Close Text / Read Less', style: TextStyle(color: Color(0xFF2E7D32)), ), onPressed: () => setState(() => expanded = false)) : OutlinedButton.icon( icon: const Icon(Icons.arrow_downward, color: Color(0xFFD50000)), label: const Text('Read More Here', style: TextStyle(color: Color(0xFF2E7D32))), onPressed: () => setState(() => expanded = true)) ]); } } |
8. Complete source code for main.dart file :-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Home(), ); } } class Home extends StatefulWidget { ReadMoreText createState() => ReadMoreText(); } class ReadMoreText extends State<Home> { @override Widget build(BuildContext context) { return const SafeArea( child: Scaffold( body: Padding( padding: EdgeInsets.fromLTRB(10, 10, 10, 10), child: ExpandableText( text: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.")), )); } } class ExpandableText extends StatefulWidget { const ExpandableText({Key? key, required this.text}) : super(key: key); final String text; @override ExpandableTextState createState() => ExpandableTextState(); } class ExpandableTextState extends State<ExpandableText> with TickerProviderStateMixin { bool expanded = false; @override Widget build(BuildContext context) { return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ AnimatedSize( duration: const Duration(milliseconds: 250), child: ConstrainedBox( constraints: expanded ? const BoxConstraints() : const BoxConstraints(maxHeight: 85), child: Text( widget.text, style: const TextStyle(fontSize: 18), overflow: TextOverflow.fade, ))), expanded ? OutlinedButton.icon( icon: const Icon(Icons.arrow_upward, color: Color(0xFFD50000)), label: const Text( 'Close Text / Read Less', style: TextStyle(color: Color(0xFF2E7D32)), ), onPressed: () => setState(() => expanded = false)) : OutlinedButton.icon( icon: const Icon(Icons.arrow_downward, color: Color(0xFFD50000)), label: const Text('Read More Here', style: TextStyle(color: Color(0xFF2E7D32))), onPressed: () => setState(() => expanded = true)) ]); } } |
Live Screenshot :-