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.

and this is what i have.

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.
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(),
),
),
),
),
),
),
);
}
}

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