質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

Q&A

解決済

1回答

3632閲覧

riverpod+TextFieldで入力エリアを実装すると編集時にカーソルが左端に移動してしまう

Aqt

総合スコア27

Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

0グッド

0クリップ

投稿2022/11/27 03:38

編集2022/11/27 04:32

前提

Flutter初心者です。
riverpodのstateを編集する入力エリアを作成しようとしています。

発生している問題

TextFieldを使った入力エリアだと、編集時にカーソルが左端に移動してしまいます。
TextFormFieldのinitialValueを使えば期待通りの動作をしますが、Formの入力エリアにするつもりはなく、Enter時の動作(onSubmited)が必要なのでTextFieldを利用したいです。

質問

riverpodを使う場合、どのように入力エリアを実装するものなのでしょうか?
なぜこのような挙動をするのでしょうか?

該当のソースコード

dart

1final _textProvider = StateProvider((ref) => "Hello"); 2 3class MyApp extends ConsumerWidget { 4 5 Widget build(context, ref) { 6 final text = ref.watch(_textProvider); 7 8 return MaterialApp( 9 home: Scaffold( 10 body: Column(children: [ 11 TextField( 12 onChanged: (newText) { 13 ref.read(_textProvider.notifier).update((state) => newText); 14 }, 15 controller: TextEditingController(text: text), 16 ), 17 Text(text), 18 ]), 19 ), 20 ); 21 } 22} 23

試したこと

  • riverpod, texteditingcontroller, cursor などのワードでいくつか検索しました。
  • rebuild時にTextEditingControllerの持っているカーソル位置などの情報がリセットされているのかと思い、TextEditingControllerをグローバルに宣言して、buildメソッドで_controller.text = textで代入してみましたが、やはり期待通りにはなりませんでした。

補足情報(FW/ツールのバージョンなど)

Windowsデバイスで実行しています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

テキストフィールドのカーソル位置情報などをTextEditingController内に含まれますが、提示されたコードの場合、テキストの変更があると、そのインスタンスが毎回再作成されるのでカーソルが先頭に行く結果になります。
これはcontroller: TextEditingController(text: text)としているからです。

TextEditingControllerを使う場合、初期化処理やdipose処理などちょっとした作法があるのでStatefulWidget内で使うのが面倒がなくていいです。
flutter_riverpodであればConsumerStatefulWidgetか。

ざっと実装してみたのが以下の様なもの。

dart

1import 'package:flutter/material.dart'; 2import 'package:flutter_riverpod/flutter_riverpod.dart'; 3 4void main() => runApp(const ProviderScope(child: MyApp())); 5 6final _textProvider = StateProvider((ref) => "Hello"); 7 8class MyApp extends ConsumerWidget { 9 const MyApp({super.key}); 10 11 12 Widget build(context, ref) { 13 final text = ref.watch(_textProvider); 14 15 return MaterialApp( 16 home: Scaffold( 17 body: Column(children: [ 18 const TextLine(), 19 Text(text), 20 ]), 21 ), 22 ); 23 } 24} 25 26class TextLine extends ConsumerStatefulWidget { 27 const TextLine({super.key}); 28 29 30 ConsumerState<TextLine> createState() => _MyApp1State(); 31} 32 33class _MyApp1State extends ConsumerState<TextLine> { 34 late TextEditingController _text; 35 36 void initState() { 37 _text = TextEditingController(text: ref.read(_textProvider)); 38 super.initState(); 39 } 40 41 42 void dispose() { 43 _text.dispose(); 44 super.dispose(); 45 } 46 47 48 Widget build(BuildContext context) { 49 return TextField( 50 onChanged: (newText) { 51 ref.read(_textProvider.notifier).update((state) => newText); 52 }, 53 controller: _text, 54 ); 55 } 56}

なおglobalにして_controller.text = textすると、選択範囲などの初期化が走るのでカーソルが先頭に行ってしまうのだと思います。
_control.value = _control.value.copyWith(text: text);とするとうまくいくとは思います。
けどglobalで管理するのはお勧めはしません。

投稿2022/11/27 09:19

ta.fu

総合スコア1667

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Aqt

2022/11/27 10:32

ありがとうございます!助かりました! TextEditingControllerはTextFieldに渡すだけで中の.textは“自動で更新される”というのが分かってませんでした。根本的に理解不足でしたね。 また、.textに代入するだけでも初期化されてしまうんですね。勉強になりました。 もちろんglobalでは使いません!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問