· 6 years ago · Oct 20, 2019, 10:44 AM
1import 'package:flutter/material.dart';
2import 'package:flutter/gestures.dart';
3import 'package:flutter/widgets.dart';
4import 'package:flutter/rendering.dart';
5void main() => runApp(MyApp());
6
7class MyApp extends StatelessWidget {
8 // This widget is the root of your application.
9 @override
10 Widget build(BuildContext context) {
11 return MaterialApp(
12 title: 'Scroll Performance',
13 theme: ThemeData(
14 // This is the theme of your application.
15 //
16 // Try running your application with "flutter run". You'll see the
17 // application has a blue toolbar. Then, without quitting the app, try
18 // changing the primarySwatch below to Colors.green and then invoke
19 // "hot reload" (press "r" in the console where you ran "flutter run",
20 // or simply save your changes to "hot reload" in a Flutter IDE).
21 // Notice that the counter didn't reset back to zero; the application
22 // is not restarted.
23 primarySwatch: Colors.blue,
24 ),
25 home: MyHomePage(title: 'Flutter Demo Home Page'),
26 );
27 }
28}
29
30class MyHomePage extends StatefulWidget {
31 MyHomePage({Key key, this.title}) : super(key: key);
32
33 final String title;
34
35 @override
36 _MyHomePageState createState() => _MyHomePageState();
37}
38
39class _MyHomePageState extends State<MyHomePage> {
40
41 @override
42 Widget build(BuildContext context) {
43 return Scaffold(
44 appBar: AppBar(
45 title: Text(widget.title),
46 ),
47 body: Scrollable(
48 viewportBuilder: (BuildContext context, ViewportOffset offset) {
49 return ArticleRichText(
50 offset: offset,
51 );
52 },
53 )
54 // This trailing comma makes auto-formatting nicer for build methods.
55 );
56 }
57}
58
59class ArticleRichText extends StatefulWidget {
60 ArticleRichText({Key key, this.offset}) : super(key: key);
61 final ViewportOffset offset;
62
63 @override
64 ArticleRichTextState createState() => ArticleRichTextState();
65}
66
67class ArticleRichTextState extends State<ArticleRichText> {
68
69 Offset _lastTapDownPosition;
70 GlobalKey key = GlobalKey();
71
72 TextPainter get textPainter {
73 return renderObject.textPainter;
74 }
75
76 CustomRenderParagraph get renderObject {
77 return key.currentContext.findRenderObject();
78 }
79
80 Offset get _paintOffset {
81 return Offset(0.0, -widget.offset.pixels);
82 }
83
84 @override
85 Widget build(BuildContext context) {
86 // The custom widget will be pretty much copy paste from RichText
87 // but with the CustomRenderParagraph.
88 // The CustomRenderParagraph will also be pretty much the same as RenderParagraph
89 // but with exposing the api to textpainter.
90 return CustomRichText(
91 key: key,
92 text: TextSpan(
93 text: 'this this this this this this this this this this this this this this this this this this this this this this this this \nthis this this this this this this this this this this this this this this this this this this this this this this this \n',
94 recognizer: TapGestureRecognizer()
95 ..onTapDown = (TapDownDetails details) {
96 _lastTapDownPosition = details.globalPosition;
97 }
98 ..onTap = () {
99 final TextPosition tapPosition = textPainter.getPositionForOffset(renderObject.globalToLocal(_lastTapDownPosition - _paintOffset));
100 // you should have the text index to find out which word it is clicked
101 }
102 ),
103 );
104 }
105}