Flutter中TextEditingController.fromValue方法的研究


最近在研究,自己試着用Flutter編寫一個文本編輯的軟件,只要和系統自帶的記事本功能差不多就行。

心想,這不是很簡單嗎?直接使用TextField組件不就行了!

記事本的界面是占全屏,沒有下划線,用代碼設置一下樣式就行。然后編寫了如下代碼:

return const Scaffold(
  body: SafeArea(
    child: Padding(
      padding: EdgeInsets.all(12.0),
        child: TextField(
          decoration: InputDecoration(
            border: InputBorder.none,
          ),
          maxLines: null,
         ),
       ),
     ),
  );

image

哈哈,果然簡單!😄

然后我試着輸入內容:

image

誒?😦第一行輸入的字上移了。

碰到問題當然先百度一下,沒有結果。然后又必應一下,還是沒有。

🙁要不就找個現成的項目看看它是怎么寫的。然后從Flutter上克隆了一個項目到本地,直沖寫作的界面代碼,然后發現了新大陸。

代碼如下:

TextField(
  controller: TextEditingController.fromValue(
    TextEditingValue(
      // 設置內容
      text: notes,
      selection: TextSelection.fromPosition(
        TextPosition(
          affinity: TextAffinity.downstream,
          offset: notes.length,
        ),
      ),
    ),
  ),
  onChanged: (text) {
    setState(() {
      notes = text;
    });
  },
  maxLines: null,
  style: const TextStyle(),
  keyboardType: TextInputType.multiline,
  decoration: const InputDecoration.collapsed(hintText: '請輸入您的內容'),
)

第一次發現TextEditingController還能這樣寫,以前都是先定義再初始化。

既然知道了,那就來好好研究研究這個fromValue方法。

TextEditingController.fromValue

TextEditingController.fromValue需要傳入一個可為空的TextEditingValue對象。既然能為空,那就傳入一個null先看看:

TextField(
  controller: TextEditingController.fromValue(null),
),

image

效果和不寫這個參數是一樣的。如果我們傳入null值的話,這個值會被Flutter替換成TextEditingValue.empty

TextEditingController.fromValue方法可以直接傳入一個TextEditingValue對象,也可以使用TextEditingValue.fromJson方法。

TextEditingValue

TextEditingValue有3個屬性:

  • String text:TextField顯示的默認值
  • TextSelection selection:文本選中范圍
  • TextRange composing

text

TextEditingValue.text相當於``TextEditingController里的text參數。其實看源碼可以發現,TextEditingController里的text最終將會賦值給TextEditingValue.text

TextEditingController({ String? text })
    : super(text == null ? TextEditingValue.empty : TextEditingValue(text: text));

selection

selection屬性的默認值是TextSelection.collapsed(offset: -1),我們來看看是啥效果:

image

我們可以看到,光標瞬間移到最前面。我們修改一下數值看看:

TextSelection.collapsed(offset: 10)

image

通過上面的實驗我們可以發現,offset可以用來設置光標的位置(當offset=0時和-1一樣效果)。這還不算玩,我們試試刪除這些文字會發生什么。

image

😦竟然從第10個字符開始,把后面的全都刪除了。

TextSelection.collapsed中還有一個可選參數affinity,該參數可以傳入兩個不同的值:TextAffinity.upstream和TextAffinity.downstream(🤨下流???),其中 TextAffinity.downstream是默認值,我們改成TextAffinity.upstream一下看看是什么效果。。。試了一下,沒有效果😦。。。如果有效果的話,會是如下樣子:

image

該值用來設置,當字符串從offset處換行,光標應該顯示在上一行還是下一行。

selection還可以傳入TextSelection.fromPosition方法,該方法需要傳入一個TextPosition對象的參數,該對象也有兩個參數,和TextSelection.collapsed一模一樣,效果也一樣。

現在來說說TextSelection對象本身。

TextSelection

  • int baseOffset:開始的位置
  • int extentOffset:結束的位置
  • TextAffinity affinity:光標的位置
  • bool isDirectional:是否消除了其基礎和范圍的歧義(不懂可以直接忽略)

該對象可以用來設置文本的選擇范圍:

selection: const TextSelection(
  extentOffset: 5,
  baseOffset: 12,
),

image

其實,TextSelection.fromPosition是把TextSelection對象的 extentOffset 和 baseOffset賦值給了同一個數,而TextSelection.collapsed又是TextSelection.fromPosition的簡化版。

composing

該值傳入一個TextRange對象,該對象有兩個屬性:

  • int start:開始的位置
  • int end:結束的位置

我們來試試有什么效果:

composing: const TextRange(start: 8, end: 16),

image

我們設定的范圍會有一條下划線。

composing的默認值為TextRange.empty,相當於把start和end的值設置成-1,而TextRange.collapsed方法是把start和end設置成相同的數值,所以顯示效果回合TextRange.empty一樣。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM