scrollbar的Textfield?

发布于 2025-02-11 03:28:20 字数 936 浏览 1 评论 0原文

我不是要用滚动条制作一个文字场,但是有一个特定的设计,但是我不能摩得这个标准,如果有人有解决方案,我搜索包裹或解决方案,但我没有一个解决方案,所以我在这里问也许有人可以帮助我。

有一张我试图达到的照片。

这就是我所拥有的。

我的代码,


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,

感谢Advance。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

最美的太阳 2025-02-18 03:28:21

您可以使用SINGLECHILDSCROLLVIEW创建自己的scrollableTexfield,例如:

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

小部件有两个参数可以提供占位符textedingedingcontroller

在代码中,我使用textfield具有多个输入行,并且在文本更改时,我更新了拇指位置。
FrameCallback用于确保在选择ALL和DELETE操作之后进行更新。
定位的小部件用于可视化拇指和跟踪。

可以这样使用。我在小部件本身之外添加了一些装饰,但是可以嵌入其中。

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文