Skip to content

Instantly share code, notes, and snippets.

@csells
Last active September 14, 2021 18:22
Show Gist options
  • Select an option

  • Save csells/fa385b970ef9eeb281ba915beb7a1118 to your computer and use it in GitHub Desktop.

Select an option

Save csells/fa385b970ef9eeb281ba915beb7a1118 to your computer and use it in GitHub Desktop.
import 'package:flutter/material.dart';
import 'package:linked_scroll_controller/linked_scroll_controller.dart';
void main() => runApp(const App());
class App extends StatelessWidget {
static const title = 'Flutter App';
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => const MaterialApp(
title: title,
home: HomePage(),
);
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(title: const Text(App.title)),
body: const Padding(
padding: EdgeInsets.all(8),
child: TextEditorWithLineNumbers(),
),
);
}
class TextEditorWithLineNumbers extends StatefulWidget {
const TextEditorWithLineNumbers({Key? key}) : super(key: key);
@override
State<TextEditorWithLineNumbers> createState() =>
_TextEditorWithLineNumbersState();
}
class _TextEditorWithLineNumbersState extends State<TextEditorWithLineNumbers> {
var _lineNos = 1;
final _textController = TextEditingController();
final _controllers = LinkedScrollControllerGroup();
late final ScrollController _textScroll;
late final ScrollController _numbersScroll;
late final TextStyle _textStyle;
@override
void initState() {
super.initState();
_textScroll = _controllers.addAndGet();
_numbersScroll = _controllers.addAndGet();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
_textStyle =
Theme.of(context).textTheme.subtitle1!.copyWith(color: Colors.black26);
}
@override
void dispose() {
_textController.dispose();
_textScroll.dispose();
_numbersScroll.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 50, // HACK: width of four characters
child: ScrollConfiguration(
behavior: ScrollConfiguration.of(context).copyWith(
scrollbars: false,
),
child: ListView.builder(
controller: _numbersScroll,
itemCount: _lineNos,
itemExtent: 19, // HACK: match TextField style
shrinkWrap: true,
physics: null,
itemBuilder: (context, index) => Text(
'${index + 1}',
style: _textStyle,
),
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(top: 4), // HACK: match ListView
child: TextField(
scrollController: _textScroll,
controller: _textController,
maxLines: null,
expands: true,
onChanged: _textChanged,
decoration:
const InputDecoration.collapsed(hintText: 'enter text'),
),
),
),
],
);
void _textChanged(String value) =>
setState(() => _lineNos = value.split('\n').length);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment