我如何滚动到textfield

问题描述 投票:0回答:1

void scrollToWord(String word) { final text = _controller.text; // Find the position of the word in the text int index = text.indexOf(word); if (index == -1) { // Word not found, return early return; } // Move the cursor to the start of the word _controller.selection = TextSelection.fromPosition(TextPosition(offset: index)); // Calculate the scroll position (find position of word's start) final textPainter = TextPainter( text: TextSpan(text: text), textDirection: TextDirection.ltr, ); textPainter.layout(maxWidth: MediaQuery.of(context).size.width); // Calculate the word's start position on screen final wordStartOffset = textPainter.getOffsetForCaret(TextPosition(offset: index)); final wordHeight = textPainter.size.height; // Scroll to the word's position _scrollController.animateTo( wordStartOffset.dy, // Scroll position duration: Duration(milliseconds: 300), curve: Curves.easeInOut, ); }

但这不起作用,因为这个词以某种方式离开了。

    

经过一些研究,我找到了解决这个问题的解决方案。 imgLET将其分成部分以清楚:

flutter dart textfield
1个回答
0
投票

您想:

将单词作为用户(或任何其他资源)的输入。

在存储在

startOffset

的文本中的文字中找到了这个词。 TextField

。 croll到该位置(

controller.text

),因此单词变成可见范围。
  1. 要实现这一目标,您需要两个主要控制器:
  2. offset
    :控制
    TextField
    的滚动行为。
  3. offset
    :管理文本和光标位置
    ScrollController
  4. 1。编程部分
  5. 定义和初始化控制器:
TextField

然后创建将控制滚动的方法:

TextEditingController
2。 UI部分

-创建textfielwidget组件


TextField
您必须将高度定义到一个字段或给它一个约束以防止其扩展

-创建按钮小部件组件

// Controller that will catch the target Word from the User // Also will be used to control the cursor position late final TextEditingController _searchController; // The Target contrller that we will scroll from it late final TextEditingController _targetController; // The ScrollController of the TextField Widget late final ScrollController _scrollController; // Initialize the Controllers in the initState @override void initState() { _searchController = TextEditingController(); _targetController = TextEditingController(); _scrollController = ScrollController(); super.initState(); } @override void dispose() { _searchController.dispose(); _targetController.dispose(); _scrollController.dispose(); super.dispose(); }

最终这是完整的代码

 void get _scrollToSearchedText {
   log("Start to Scroll .....");

   final String contentText = _targetController.text;

   final String searchText = _searchController.text;

   final int indexOfTextinContent = contentText.indexOf(searchText);

   if (indexOfTextinContent != -1 || contentText.isNotEmpty) {
     log("trying ....");
     // ensure that all frames has been build and there are no Widgets need to bind
     WidgetsBinding.instance.addPostFrameCallback(
       (_) {
         final textPainter = TextPainter(
           text: TextSpan(
             text: contentText.substring(0, indexOfTextinContent),
             style: const TextStyle(fontSize: 16),
           ),
           textDirection: TextDirection.ltr,
         );

         // Layout the text to calculate the size
         // Computes the visual position of the glyphs for painting the text.
         textPainter.layout();

         // Calculate the scroll offset based on the text width and height

         final double scrollOffset = textPainter.size.height *
             (textPainter.size.width /
                 _scrollController.position.viewportDimension);

         // Scroll to the calculated offset

         _scrollController.jumpTo(scrollOffset.clamp(
             0.0, _scrollController.position.maxScrollExtent));

      
         // Move the cursor to the start of the searched word
         _targetController.selection = TextSelection.collapsed(
           offset: indexOfTextinContent,
         );
       },
     );
   }
 }

您可以忽略代码的某些部分,例如class CustomTextFielWidget extends StatelessWidget { const CustomTextFielWidget({ super.key, required this.controller, required this.hintText, this.isTargetField = false, this.scrollController, }); final TextEditingController controller; final String hintText; final bool isTargetField; final ScrollController? scrollController; @override Widget build(BuildContext context) { return Container( height: isTargetField ? context.screenHeight * .5 : null, <---- Height is must padding: const EdgeInsets.all(10), child: TextField( controller: controller, scrollController: scrollController, scrollPhysics: const AlwaysScrollableScrollPhysics(), maxLines: isTargetField ? null : 1, style: TextStyle( fontSize: isTargetField ? 20 : 18, fontWeight: FontWeight.bold, fontFamily: isTargetField ? FontFamily.verlaFont : null, ), decoration: InputDecoration( enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide( color: Colors.grey.withOpacity(0.6), width: 1.3, ), ), hintText: hintText, fillColor: Colors.grey.withOpacity(0.3), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide( color: Colors.grey.withOpacity(0.6), width: 2.0, ), ), ), ), ); } }

class ScrollButtonWidget extends StatelessWidget { const ScrollButtonWidget({ super.key, required this.onScrollTap, }); final void Function() onScrollTap; @override Widget build(BuildContext context) { return SizedBox( width: context.screenWidth * .7, height: context.screenHeight * .07, child: MaterialButton( onPressed: onScrollTap, color: Colors.blue, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), child: const Text("Scroll To Target Word"), ), ); } }

import 'dart:developer'; import 'package:flutter/material.dart'; class ScrollToTextWidget extends StatefulWidget { const ScrollToTextWidget({super.key}); @override State<ScrollToTextWidget> createState() => _ScrollToTextWidgetState(); } class _ScrollToTextWidgetState extends State<ScrollToTextWidget> { // Controller that will catch the target Word from the User late final TextEditingController _searchController; // The Target contrller that we will scroll from it late final TextEditingController _targetController; // The ScrollController of the TextField Widget late final ScrollController _scrollController; @override void initState() { _searchController = TextEditingController(); _targetController = TextEditingController(); _scrollController = ScrollController(); super.initState(); } @override void dispose() { _searchController.dispose(); _targetController.dispose(); _scrollController.dispose(); super.dispose(); } void get _scrollToSearchedText { log("Start to Scroll ....."); final String contentText = _targetController.text; final String searchText = _searchController.text; final int indexOfTextinContent = contentText.indexOf(searchText); if (indexOfTextinContent != -1 || contentText.isNotEmpty) { log("trying ...."); WidgetsBinding.instance.addPostFrameCallback( (_) { final TextPainter textPainter = TextPainter( text: TextSpan( text: contentText.substring(0, indexOfTextinContent), style: const TextStyle(fontSize: 16), ), textDirection: TextDirection.ltr, ); // Layout the text to calculate the size // Computes the visual position of the glyphs for painting the text. textPainter.layout(); // Calculate the scroll offset based on the text width and height final double scrollOffset = textPainter.size.height * (textPainter.size.width / _scrollController.position.viewportDimension); // Scroll to the calculated offset _scrollController.jumpTo(scrollOffset.clamp( 0.0, _scrollController.position.maxScrollExtent)); // Move the cursor to the start of the searched word _targetController.selection = TextSelection.collapsed( offset: indexOfTextinContent, ); }, ); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Scroll To Text"), automaticallyImplyLeading: false, backgroundColor: Colors.green, ), body: Column( children: <Widget>[ Expanded( child: SingleChildScrollView( child: Column( children: <Widget>[ gapH1, CustomTextFielWidget( controller: _searchController, hintText: "Enter Target Text", ), gapH1, CustomTextFielWidget( controller: _targetController, hintText: "Content Text", scrollController: _scrollController, isTargetField: true, ), gapH2, ], ), ), ), ScrollButtonWidget( onScrollTap: () { _scrollToSearchedText; }, ) ], ), ); } } class CustomTextFielWidget extends StatelessWidget { const CustomTextFielWidget({ super.key, required this.controller, required this.hintText, this.isTargetField = false, this.scrollController, }); final TextEditingController controller; final String hintText; final bool isTargetField; final ScrollController? scrollController; @override Widget build(BuildContext context) { return Container( height: isTargetField ? context.screenHeight * .5 : null, padding: const EdgeInsets.all(10), child: TextField( controller: controller, scrollController: scrollController, scrollPhysics: const AlwaysScrollableScrollPhysics(), maxLines: isTargetField ? null : 1, style: TextStyle( fontSize: isTargetField ? 20 : 18, fontWeight: FontWeight.bold, fontFamily: isTargetField ? FontFamily.verlaFont : null, ), decoration: InputDecoration( enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide( color: Colors.grey.withOpacity(0.6), width: 1.3, ), ), hintText: hintText, fillColor: Colors.grey.withOpacity(0.3), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide( color: Colors.grey.withOpacity(0.6), width: 2.0, ), ), ), ), ); } } class ScrollButtonWidget extends StatelessWidget { const ScrollButtonWidget({ super.key, required this.onScrollTap, }); final void Function() onScrollTap; @override Widget build(BuildContext context) { return SizedBox( width: context.screenWidth * .7, height: context.screenHeight * .07, child: MaterialButton( onPressed: onScrollTap, color: Colors.blue, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), child: const Text("Scroll To Target Word"), ), ); } } 这是我创建的属性

也...。

有一些关于光标的注释,如果您希望光标处于单词的开头,您的目标文本字段必须是焦点,则可以通过用

gapH1小部件包裹screenWidth

并控制
screenHeight来处理
TextField

当用户单击按钮时将其形成


最新问题
© www.soinside.com 2019 - 2025. All rights reserved.