Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TextField with Scrollbar?

i wan't to made a textfield with a scrollbar, but with a specific design, but i cannot moove this bar, if someone have the solution, i search a package or some solution but i don't have one, so i ask here maybe someone can help me.

There is a picture of what i try to reach.

reach

and this is what i have.

ihave

My code,


MediaQuery.removePadding(
  context: context,
  removeTop: true,
  child: Scrollbar(
    radius: const Radius.circular(5),
    interactive: true,
    isAlwaysShown: true,
    trackVisibility: true,
    controller: scrollController,
    child: TextField(
      scrollController: scrollController,
      scrollPhysics: const BouncingScrollPhysics(),
      scrollPadding: EdgeInsets.zero,

Thanks by advence.

like image 824
Martin Saison Avatar asked Apr 10 '26 10:04

Martin Saison


1 Answers

You could create own ScrollableTexField using SingleChildScrollView like this:

class ScrollableTextField extends StatefulWidget {
  const ScrollableTextField({
    super.key,
    required this.placeholder,
    required this.controller,
  });

  final String placeholder;
  final TextEditingController controller;

  @override
  State<ScrollableTextField> createState() => _ScrollableTextFieldState();
}

class _ScrollableTextFieldState extends State<ScrollableTextField> {
  final ScrollController _scrollController = ScrollController();

  double _thumbHeight = 0;
  double _thumbTop = 0;

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(_updateThumbPosition);
  }

  void _updateThumbPosition() {
    double maxScroll = _scrollController.position.maxScrollExtent;
    double currentScroll = _scrollController.position.pixels;
    double viewportHeight = _scrollController.position.viewportDimension;
    setState(() {
      if (maxScroll != 0) {
        _thumbTop = (currentScroll / maxScroll) * (viewportHeight - _thumbHeight);
        _thumbHeight = viewportHeight * viewportHeight / (maxScroll + viewportHeight);
      } else {
        _thumbTop = 0;
        _thumbHeight = 0;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (BuildContext context, BoxConstraints constraints) {
        return Stack(
          children: <Widget>[
            SingleChildScrollView(
              controller: _scrollController,
              child: TextField(
                controller: widget.controller,
                keyboardType: TextInputType.multiline,
                maxLines: null,
                decoration: InputDecoration(
                  hintText: widget.placeholder,
                  border: InputBorder.none,
                  counterText: '',
                ),
                onChanged: (value) {
                  WidgetsBinding.instance.addPostFrameCallback((_) {
                    _updateThumbPosition(); // Update the scroll thumb position and height
                  });
                },
              ),
            ),

            // Track
            Positioned(
              top: 0,
              right: 0,
              child: _thumbHeight == 0
                  ? Container()
                  : Container(
                      width: 10,
                      height: constraints.maxHeight,
                      decoration: BoxDecoration(
                        color: Colors.grey[300],
                        borderRadius: BorderRadius.circular(5),
                      )),
            ),

            // Thumb
            Positioned(
              top: _thumbTop,
              right: 0,
              child: Container(
                width: 10,
                height: _thumbHeight,
                decoration: BoxDecoration(
                  color: Colors.blue,
                  borderRadius: BorderRadius.circular(5),
                ),
              ),
            ),
          ],
        );
      },
    );
  }
}

The widget has two parameters to provide Placeholder and TextEditingController.

In the code I use TextField with multiple lines of input and on change of the text I update the thumb position. PostFrameCallback is used to ensure that thumb would be updates after for example select all and delete operation. Positioned widgets are used to visual the Thumb and Track.

It can be used like this. I added some Decoration outside of the widget itself, but it can be embedded inside.

Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Container(
              height: 300,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(8),
                border: Border.all(
                  color: Colors.black,
                  width: 1,
                ),
              ),
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: ScrollableTextField(
                  placeholder: 'Placeholder',
                  controller: TextEditingController(),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

Demo

like image 193
MIHOW Avatar answered Apr 13 '26 02:04

MIHOW



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!