跳至主要內容

處理使用者輸入

既然您知道如何在 Flutter 應用程式中管理狀態,您如何讓使用者與您的應用程式互動並變更其狀態?

使用者輸入處理簡介

#

作為一個多平台 UI 框架,使用者與 Flutter 應用程式互動的方式有很多種。本節中的資源將向您介紹一些常用的 Widget,用於在您的應用程式中啟用使用者互動。

一些使用者輸入機制,例如捲動,已在版面配置中介紹過。

參考資料Widget 目錄列出了 MaterialCupertino 程式庫中常用的 Widget。

接下來,我們將介紹一些 Material Widget,這些 Widget 支援在您的 Flutter 應用程式中處理使用者輸入的常見使用案例。

按鈕

#

A collection of Material 3 Buttons.

按鈕允許使用者透過點擊或輕觸來啟動 UI 中的動作。Material 程式庫提供了多種功能相似但樣式不同的按鈕類型,適用於各種使用案例,包括

  • ElevatedButton:具有一些深度的按鈕。使用凸起的按鈕為其他大部分為平面的版面配置增加維度。
  • FilledButton:填滿的按鈕,應用於重要、完成流程的最終動作,例如儲存立即加入確認
  • Tonal Button:介於 FilledButtonOutlinedButton 之間的按鈕。它們適用於較低優先級的按鈕需要比輪廓更多的強調的情況,例如下一步
  • OutlinedButton:具有文字和可見邊框的按鈕。這些按鈕包含重要但不是應用程式中主要動作的動作。
  • TextButton:可點擊的文字,沒有邊框。由於文字按鈕沒有可見邊框,因此它們必須依賴其相對於其他內容的位置來取得上下文。
  • IconButton:具有圖示的按鈕。
  • FloatingActionButton:懸浮在內容上的圖示按鈕,用於宣傳主要動作。

影片FloatingActionButton (Widget of the Week)

建構按鈕通常有 3 個主要方面:樣式、回呼及其子項,如下列 ElevatedButton 範例程式碼所示

  • 按鈕的回呼函式 onPressed 決定了點擊按鈕時會發生什麼事,因此,此函式是您更新應用程式狀態的地方。如果回呼是 null,則按鈕會停用,而且當使用者按下按鈕時不會發生任何事情。

  • 按鈕的 child(顯示在按鈕的內容區域中)通常是文字或圖示,用於指示按鈕的用途。

  • 最後,按鈕的 style 會控制其外觀:顏色、邊框等等。

dart
int count = 0;

@override
Widget build(BuildContext context) {
  return ElevatedButton(
    style: ElevatedButton.styleFrom(
      textStyle: const TextStyle(fontSize: 20),
    ),
    onPressed: () {
      setState(() {
        count += 1;
      });
    },
    child: const Text('Enabled'),
  );
}

A GIF of an elevated button with the text "Enabled"
此圖顯示正在點擊文字為「已啟用」的 ElevatedButton。


檢查點:完成此教學課程,它會教您如何建構「最愛」按鈕:將互動性新增至您的 Flutter 應用程式


API 文件ElevatedButtonFilledButtonOutlinedButtonTextButtonIconButtonFloatingActionButton

文字

#

有幾個 Widget 支援文字輸入。

SelectableText

#

Flutter 的 Text Widget 會在畫面上顯示文字,但不允許使用者反白或複製文字。SelectableText 會顯示使用者可選取的文字字串。

dart
@override
Widget build(BuildContext context) {
  return const SelectableText('''
Two households, both alike in dignity,
In fair Verona, where we lay our scene,
From ancient grudge break to new mutiny,
Where civil blood makes civil hands unclean.
From forth the fatal loins of these two foes''');
}

A GIF of a cursor highlighting two lines of text from a paragraph.
此圖顯示一個游標反白文字字串的一部分。

影片SelectableText (Widget of the Week)

RichText

#

RichText 可讓您在應用程式中顯示豐富文字字串。與 RichText 類似的 TextSpan 可讓您顯示具有不同文字樣式的文字部分。它不是用於處理使用者輸入,而是如果您允許使用者編輯和設定文字格式時很有用。

dart
@override
Widget build(BuildContext context) {
  return RichText(
    text: TextSpan(
      text: 'Hello ',
      style: DefaultTextStyle.of(context).style,
      children: const <TextSpan>[
        TextSpan(text: 'bold', style: TextStyle(fontWeight: FontWeight.bold)),
        TextSpan(text: ' world!'),
      ],
    ),
  );
}

A screenshot of the text "Hello bold world!" with the word "bold" in bold font.
此圖顯示一個以不同文字樣式格式化的文字字串。

影片Rich Text (Widget of the Week)

範例Rich Text Editor

程式碼Rich Text Editor 程式碼

TextField

#

TextField 可讓使用者使用硬體或螢幕鍵盤在文字方塊中輸入文字。

TextField 有許多不同的屬性和配置。以下是一些重點

  • InputDecoration 決定文字欄位的外觀,例如顏色和邊框。
  • controllerTextEditingController 控制正在編輯的文字。您為什麼可能需要控制器?預設情況下,您的應用程式使用者可以在文字欄位中輸入文字,但如果您想要以程式方式控制 TextField 並清除其值,例如,您將需要 TextEditingController
  • onChanged:當使用者變更文字欄位的值時(例如插入或移除文字時),會觸發此回呼函式。
  • onSubmitted:當使用者表示他們已完成編輯欄位中的文字時,會觸發此回呼;例如,當文字欄位處於焦點時,點擊「輸入」鍵。

此類別支援其他可配置的屬性,例如將每個字母變成輸入時的 readOnly 圓形的 obscureText,以及阻止使用者變更文字的 readOnly

dart
final TextEditingController _controller = TextEditingController();

@override
Widget build(BuildContext context) {
  return TextField(
    controller: _controller,
    decoration: const InputDecoration(
      border: OutlineInputBorder(),
      labelText: 'Mascot Name',
    ),
  );
}

A GIF of a text field with the label "Mascot Name", purple focus border and the phrase "Dash the hummingbird" being typed in.
此圖顯示正在輸入文字到具有選取邊框和標籤的 TextField 中。

檢查點:完成這個 4 部分的食譜系列,逐步引導您如何建立文字欄位、擷取其值並更新您的應用程式狀態

  1. 建立文字欄位並設定樣式
  2. 擷取文字欄位的值
  3. 處理文字欄位的變更
  4. 焦點和文字欄位.

表單

#

Form 是一個可選的容器,用於將多個表單欄位 Widget 分組在一起,例如 TextField

每個個別的表單欄位都應該包裝在以 Form Widget 作為共同祖先的 FormField Widget 中。現有的便利 Widget 會為您將表單欄位 Widget 預先包裝在 FormField 中。例如,TextFieldForm Widget 版本是 TextFormField

使用 Form 可讓您存取 FormState,這可讓您儲存、重設和驗證繼承自此 Form 的每個 FormField。您也可以提供 GlobalKey 以識別特定的表單,如下列程式碼所示

dart
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();

@override
Widget build(BuildContext context) {
  return Form(
    key: _formKey,
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        TextFormField(
          decoration: const InputDecoration(
            hintText: 'Enter your email',
          ),
          validator: (String? value) {
            if (value == null || value.isEmpty) {
              return 'Please enter some text';
            }
            return null;
          },
        ),
        Padding(
          padding: const EdgeInsets.symmetric(vertical: 16.0),
          child: ElevatedButton(
            onPressed: () {
              // Validate returns true if the form is valid, or false otherwise.
              if (_formKey.currentState!.validate()) {
                // Process data.
              }
            },
            child: const Text('Submit'),
          ),
        ),
      ],
    ),
  );
}

檢查點:完成此教學課程以學習如何使用驗證建構表單

範例表單應用程式

程式碼表單應用程式程式碼


API 文件TextFieldRichTextSelectableTextForm

從選項群組中選擇值

#

提供使用者從多個選項中進行選擇的方式。

SegmentedButton

#

SegmentedButton 可讓使用者從最少 2-5 個項目群組中進行選擇。

資料類型 <T> 可以是內建類型,例如 intStringbool 或列舉。SegmentedButton 有幾個相關的屬性

  • segmentsButtonSegment 的清單,其中每個都代表使用者可以選取的「區段」或選項。在視覺上,每個 ButtonSegment 都可以有圖示、文字標籤或兩者都有。

  • multiSelectionEnabled 指示是否允許使用者選取多個選項。此屬性預設為 false。

  • selected 識別目前選取的值。注意:selected 的類型是 Set<T>,因此如果您只允許使用者選取一個值,則該值必須以具有單一元素的 Set 提供。

  • 當使用者選取任何區段時,會觸發 onSelectionChanged 回呼。它會提供選取區段的清單,以便您可以更新您的應用程式狀態。

  • 其他樣式參數可讓您修改按鈕的外觀。例如,style 採用 ButtonStyle,提供設定 selectedIcon 的方法。

dart
enum Calendar { day, week, month, year }

// StatefulWidget...
Calendar calendarView = Calendar.day;

@override
Widget build(BuildContext context) {
  return SegmentedButton<Calendar>(
    segments: const <ButtonSegment<Calendar>>[
      ButtonSegment<Calendar>(
          value: Calendar.day,
          label: Text('Day'),
          icon: Icon(Icons.calendar_view_day)),
      ButtonSegment<Calendar>(
          value: Calendar.week,
          label: Text('Week'),
          icon: Icon(Icons.calendar_view_week)),
      ButtonSegment<Calendar>(
          value: Calendar.month,
          label: Text('Month'),
          icon: Icon(Icons.calendar_view_month)),
      ButtonSegment<Calendar>(
          value: Calendar.year,
          label: Text('Year'),
          icon: Icon(Icons.calendar_today)),
    ],
    selected: <Calendar>{calendarView},
    onSelectionChanged: (Set<Calendar> newSelection) {
      setState(() {
        Suggested change
        // By default there is only a single segment that can be
        // selected at one time, so its value is always the first
        // By default, only a single segment can be
        // selected at one time, so its value is always the first
        calendarView = newSelection.first;
      });
    },
  );
}

A GIF of a SegmentedButton with 4 segments: Day, Week, Month, and Year.
Each has a calendar icon to represent its value and a text label.
Day is first selected, then week and month, then year.
此圖顯示一個 SegmentedButton,每個區段都有一個圖示和文字,代表其值。

Chip

#

Chip 是一種以精簡方式表示特定內容的屬性、文字、實體或動作的方法。存在用於特定使用案例的專門 Chip Widget

  • InputChip 以精簡的形式表示複雜的資訊,例如實體(人員、地點或事物)或對話文字。
  • ChoiceChip 允許從一組選項中進行單一選擇。Choice Chip 包含相關的描述性文字或類別。
  • FilterChip 使用標籤或描述性文字來篩選內容。
  • ActionChip 表示與主要內容相關的動作。

每個 Chip 小工具都必須要有 label。它可以選擇性地擁有一個 avatar(例如圖示或使用者的大頭貼)和一個 onDeleted 回呼函式,該函式會顯示一個刪除圖示,當觸發時,會刪除這個 Chip。Chip 小工具的外觀也可以透過設定一些可選的參數來自訂,例如 shapecoloriconTheme

您通常會使用 Wrap 這個小工具,它會在多個水平或垂直的運行中顯示其子元件,以確保您的 Chip 可以換行,而不會在應用程式的邊緣被截斷。

dart
@override
Widget build(BuildContext context) {
  return const SizedBox(
    width: 500,
    child: Wrap(
      alignment: WrapAlignment.center,
      spacing: 8,
      runSpacing: 4,
      children: [
        Chip(
          avatar: CircleAvatar(
              backgroundImage: AssetImage('assets/images/dash_chef.png')),
          label: Text('Chef Dash'),
        ),
        Chip(
          avatar: CircleAvatar(
              backgroundImage:
                  AssetImage('assets/images/dash_firefighter.png')),
          label: Text('Firefighter Dash'),
        ),
        Chip(
          avatar: CircleAvatar(
              backgroundImage: AssetImage('assets/images/dash_musician.png')),
          label: Text('Musician Dash'),
        ),
        Chip(
          avatar: CircleAvatar(
              backgroundImage: AssetImage('assets/images/dash_artist.png')),
          label: Text('Artist Dash'),
        ),
      ],
    ),
  );
}

A screenshot of 4 Chips split over two rows with a leading circular
profile image with content text.
此圖顯示兩行 Chip 小工具,每個小工具都包含一個圓形的前導個人資料圖片和內容文字。

#

DropdownMenu 允許使用者從選項選單中選擇一個選項,並將選定的文字放入 TextField 中。它還允許使用者根據文字輸入來篩選選單項目。

組態參數包括以下內容:

  • dropdownMenuEntries 提供一個 DropdownMenuEntry 列表,描述每個選單項目。選單可能包含文字標籤,以及前導或後置圖示。(這也是唯一必需的參數。)
  • TextEditingController 允許以程式方式控制 TextField
  • 當使用者選擇一個選項時,會觸發 onSelected 回呼函式。
  • initialSelection 允許您設定預設值。
  • 還有其他參數可用於自訂小工具的外觀和行為。
dart
enum ColorLabel {
  blue('Blue', Colors.blue),
  pink('Pink', Colors.pink),
  green('Green', Colors.green),
  yellow('Orange', Colors.orange),
  grey('Grey', Colors.grey);

  const ColorLabel(this.label, this.color);
  final String label;
  final Color color;
}

// StatefulWidget...
@override
Widget build(BuildContext context) {
  return DropdownMenu<ColorLabel>(
    initialSelection: ColorLabel.green,
    controller: colorController,
    // requestFocusOnTap is enabled/disabled by platforms when it is null.
    // On mobile platforms, this is false by default. Setting this to true will
    // trigger focus request on the text field and virtual keyboard will appear
    // afterward. On desktop platforms however, this defaults to true.
    requestFocusOnTap: true,
    label: const Text('Color'),
    onSelected: (ColorLabel? color) {
      setState(() {
        selectedColor = color;
      });
    },
    dropdownMenuEntries: ColorLabel.values
      .map<DropdownMenuEntry<ColorLabel>>(
          (ColorLabel color) {
            return DropdownMenuEntry<ColorLabel>(
              value: color,
              label: color.label,
              enabled: color.label != 'Grey',
              style: MenuItemButton.styleFrom(
                foregroundColor: color.color,
              ),
            );
      }).toList(),
  );
}

A GIF the DropdownMenu widget that is selected, it displays 5 options:
Blue, Pink, Green, Orange, and Grey. The option text is displayed in the color
of its value.
此圖顯示一個具有 5 個數值選項的 DropdownMenu 小工具。每個選項的文字顏色都經過樣式設定,以表示顏色值。

影片DropdownMenu (Widget of the Week)

Slider

#

Slider 小工具讓使用者可以透過移動指示器來調整數值,例如音量條。

Slider 小工具的組態參數:

  • value 代表滑桿的目前值
  • onChanged 是當控制柄移動時觸發的回呼函式
  • minmax 建立滑桿允許的最小值和最大值
  • divisions 建立一個離散間隔,使用者可以透過該間隔沿著軌道移動控制柄。
dart
double _currentVolume = 1;

@override
Widget build(BuildContext context) {
  return Slider(
    value: _currentVolume,
    max: 5,
    divisions: 5,
    label: _currentVolume.toString(),
    onChanged: (double value) {
      setState(() {
        _currentVolume = value;
      });
    },
  );
}

A GIF of a slider that has the dial dragged left to right in increments 
of 1, from 0.0 to 5.0
此圖顯示一個滑桿小工具,其數值範圍從 0.0 到 5.0,分為 5 個區間。它會在撥號被拖曳時以標籤顯示目前的值。

影片Slider, RangeSlider, CupertinoSlider (Widget of the Week)


API 文件: SegmentedButtonDropdownMenuSliderChip

在值之間切換

#

您的 UI 可以透過幾種方式讓使用者在數值之間切換。

Checkbox、Switch 和 Radio

#

提供一個選項來開啟和關閉單個數值。這些小工具背後的運作邏輯是相同的,因為這 3 個小工具都是建立在 ToggleableStateMixin 之上,儘管每個小工具都提供稍微不同的呈現方式。

  • Checkbox 是一個容器,當值為 false 時為空,當值為 true 時則會填入一個核取記號。
  • Switch 有一個控制柄,當值為 false 時位於左側,當值為 true 時滑到右側。
  • Radio 類似於 Checkbox,因為它是一個容器,當值為 false 時為空,但當值為 true 時則會填入。

CheckboxSwitch 的組態包含:

  • 一個 value,其值為 truefalse
  • 以及一個 onChanged 回呼函式,當使用者切換小工具時會觸發該函式

Checkbox

#
dart
bool isChecked = false;

@override
Widget build(BuildContext context) {
  return Checkbox(
    checkColor: Colors.white,
    value: isChecked,
    onChanged: (bool? value) {
      setState(() {
        isChecked = value!;
      });
    },
  );
}

A GIF that shows a pointer clicking a checkbox 
and then clicking again to uncheck it.
此圖顯示一個核取方塊被勾選和取消勾選。

Switch

#
dart
bool light = true;

@override
Widget build(BuildContext context) {
  return Switch(
    // This bool value toggles the switch.
    value: light,
    activeColor: Colors.red,
    onChanged: (bool value) {
      // This is called when the user toggles the switch.
      setState(() {
        light = value;
      });
    },
  );
}

A GIF of a Switch widget that is toggled on and off. In its off state,
it is gray with dark gray borders. In its on state, 
it is red with a light red border.
此圖顯示一個開啟和關閉的 Switch 小工具。

Radio

#

一組 Radio 按鈕,允許使用者在互斥的數值之間進行選擇。當使用者選擇群組中的一個單選按鈕時,其他單選按鈕會被取消選擇。

  • 特定 Radio 按鈕的 value 代表該按鈕的值,
  • 一組單選按鈕的選定值由 groupValue 參數識別。
  • Radio 也有一個 onChanged 回呼函式,當使用者點擊它時會觸發該函式,就像 SwitchCheckbox 一樣
dart
enum Character { musician, chef, firefighter, artist }

class RadioExample extends StatefulWidget {
  const RadioExample({super.key});

  @override
  State<RadioExample> createState() => _RadioExampleState();
}

class _RadioExampleState extends State<RadioExample> {
  Character? _character = Character.musician;

  void setCharacter(Character? value) {
    setState(() {
      _character = value;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        ListTile(
          title: const Text('Musician'),
          leading: Radio<Character>(
            value: Character.musician,
            groupValue: _character,
            onChanged: setCharacter,
          ),
        ),
        ListTile(
          title: const Text('Chef'),
          leading: Radio<Character>(
            value: Character.chef,
            groupValue: _character,
            onChanged: setCharacter,
          ),
        ),
        ListTile(
          title: const Text('Firefighter'),
          leading: Radio<Character>(
            value: Character.firefighter,
            groupValue: _character,
            onChanged: setCharacter,
          ),
        ),
        ListTile(
          title: const Text('Artist'),
          leading: Radio<Character>(
            value: Character.artist,
            groupValue: _character,
            onChanged: setCharacter,
          ),
        ),
      ],
    );
  }
}

A GIF of 4 ListTiles in a column, each containing a leading Radio button
and title text. The Radio buttons are selected in order from top to bottom.
此圖顯示一欄包含單選按鈕和標籤的 ListTile,其中一次只能選擇一個單選按鈕。

額外功能:CheckboxListTile & SwitchListTile

#

這些便利小工具與核取方塊和小工具相同,但支援標籤(作為 ListTile)。

dart
double timeDilation = 1.0;
bool _lights = false;

@override
Widget build(BuildContext context) {
  return Column(
    children: [
      CheckboxListTile(
        title: const Text('Animate Slowly'),
        value: timeDilation != 1.0,
        onChanged: (bool? value) {
          setState(() {
            timeDilation = value! ? 10.0 : 1.0;
          });
        },
        secondary: const Icon(Icons.hourglass_empty),
      ),
      SwitchListTile(
        title: const Text('Lights'),
        value: _lights,
        onChanged: (bool value) {
          setState(() {
            _lights = value;
          });
        },
        secondary: const Icon(Icons.lightbulb_outline),
      ),
    ],
  );
}

A ListTile with a leading icon, title text, and a trailing checkbox being
checked and unchecked. It also shows a ListTile with a leading icon, title text
and a switch being toggled on and off.
此圖顯示一欄包含一個正在切換的 CheckboxListTile 和一個 SwitchListTile。

影片CheckboxListTile (Widget of the Week)

影片SwitchListTile (Widget of the Week)


API 文件CheckboxCheckboxListTileSwitchSwitchListTileRadio

選擇日期或時間

#

提供小工具,讓使用者可以選擇日期和時間。

有一組對話框可讓使用者選擇日期或時間,如您在以下章節中所見。除了日期類型不同(日期的 DateTime 與時間的 TimeOfDay)之外,這些對話框的功能類似,您可以透過提供以下內容來設定它們:

  • 預設的 initialDateinitialTime
  • 或者,一個決定顯示選擇器 UI 的 initialEntryMode

DatePickerDialog

#

此對話框允許使用者選擇日期或日期範圍。透過呼叫 showDatePicker 函式來啟用,該函式會傳回 Future<DateTime>,因此別忘了等待非同步函式呼叫!

dart
DateTime? selectedDate;

@override
Widget build(BuildContext context) {
  var date = selectedDate;

  return Column(children: [
    Text(
      date == null
          ? "You haven't picked a date yet."
          : DateFormat('MM-dd-yyyy').format(date),
    ),
    ElevatedButton.icon(
      icon: const Icon(Icons.calendar_today),
      onPressed: () async {
        var pickedDate = await showDatePicker(
          context: context,
          initialEntryMode: DatePickerEntryMode.calendarOnly,
          initialDate: DateTime.now(),
          firstDate: DateTime(2019),
          lastDate: DateTime(2050),
        );

        setState(() {
          selectedDate = pickedDate;
        });
      },
      label: const Text('Pick a date'),
    )
  ]);
}

A GIF of a pointer clicking a button that says "Pick a date",
then shows a date picker. The date Friday, August 30 is selected and the "OK"
button is clicked.
此圖顯示在點擊「選擇日期」按鈕時顯示的 DatePicker。

TimePickerDialog

#

TimePickerDialog 是一個顯示時間選擇器的對話框。可以透過呼叫 showTimePicker() 函式來啟用。showTimePicker 不是傳回 Future<DateTime>,而是傳回 Future<TimeOfDay>。再一次,別忘了等待函式呼叫!

dart
TimeOfDay? selectedTime;

@override
Widget build(BuildContext context) {
  var time = selectedTime;

  return Column(children: [
    Text(
      time == null ? "You haven't picked a time yet." : time.format(context),
    ),
    ElevatedButton.icon(
      icon: const Icon(Icons.calendar_today),
      onPressed: () async {
        var pickedTime = await showTimePicker(
          context: context,
          initialEntryMode: TimePickerEntryMode.dial,
          initialTime: TimeOfDay.now(),
        );

        setState(() {
          selectedTime = pickedTime;
        });
      },
      label: const Text('Pick a date'),
    )
  ]);
}

A GIF of a pointer clicking a button that says "Pick a time", then shows
 a time picker. The time picker shows a circular clock as the cursor moves the 
 hour hand, then minute hand, selects PM, then the "OK" button is clicked.
此圖顯示在點擊「選擇時間」按鈕時顯示的 TimePicker。


API 文件: showDatePickershowTimePicker

滑動 & 拖曳

#

Dismissible 是一個小工具,可讓使用者透過滑動來關閉它。它具有許多組態參數,包括

  • 一個 child 小工具
  • 一個 onDismissed 回呼函式,在使用者滑動時觸發
  • 樣式設定參數,例如 background
  • 包含一個 key 物件也很重要,這樣才能在小工具樹狀結構中從同級的 Dismissible 小工具中唯一識別它們。
dart
List<int> items = List<int>.generate(100, (int index) => index);

@override
Widget build(BuildContext context) {
  return ListView.builder(
    itemCount: items.length,
    padding: const EdgeInsets.symmetric(vertical: 16),
    itemBuilder: (BuildContext context, int index) {
      return Dismissible(
        background: Container(
          color: Colors.green,
        ),
        key: ValueKey<int>(items[index]),
        onDismissed: (DismissDirection direction) {
          setState(() {
            items.removeAt(index);
          });
        },
        child: ListTile(
          title: Text(
            'Item ${items[index]}',
          ),
        ),
      );
    },
  );
}

A screenshot of three widgets, spaced evenly from each other.
此圖顯示一個 Dismissible 小工具列表,每個小工具都包含一個 ListTile。在 ListTile 上滑動會顯示綠色背景,並使圖塊消失。

影片Dismissible (Widget of the Week)

檢查點:完成此教學課程,瞭解如何使用可關閉的小工具實作滑動以關閉


API 文件: Dismissible

正在尋找更多小工具嗎?

#

此頁面僅介紹您可以在 Flutter 應用程式中用於處理使用者輸入的一些常見 Material 小工具。請查看Material 小工具程式庫Material 程式庫 API 文件以取得完整的小工具列表。

示範:請參閱 Flutter 的Material 3 示範,其中包含 Material 程式庫中提供的使用者輸入小工具的精選範例。

如果 Material 和 Cupertino 程式庫沒有符合您需求的小工具,請查看 pub.dev 以尋找 Flutter 和 Dart 社群擁有和維護的套件。例如,flutter_slidable 套件提供了一個 Slidable 小工具,它比上一節中描述的 Dismissible 小工具更具可自訂性。

影片flutter_slidable (Package of the Week)

使用 GestureDetector 建構互動式小工具

#

您是否已仔細研究過小工具程式庫、pub.dev、詢問過您的程式設計朋友,但仍然找不到符合您尋找的使用者互動的小工具?您可以使用 GestureDetector 建立自己的自訂小工具並使其具有互動性。

檢查點:使用此食譜作為起點,建立您自己的自訂按鈕小工具,它可以處理點擊

影片GestureDetector (Widget of the Week)

參考資料:請查看點擊、拖曳和其他手勢,其中說明如何在 Flutter 中接聽並回應手勢。

額外影片:是否好奇 Flutter 的 GestureArena 如何將原始使用者互動資料轉換為人類可識別的概念,例如點擊、拖曳和捏合?請觀看此影片:GestureArena (Decoding Flutter)

別忘了無障礙功能!

#

如果您正在建立自訂小工具,請使用 Semantics 小工具註解其含義。它會為螢幕閱讀器和其他基於語意分析的工具提供描述和中繼資料。

影片Semantics (Flutter Widget of the Week)


API 文件GestureDetectorSemantics

測試

#

當您完成在應用程式中建立使用者互動後,別忘了編寫測試以確保一切正常運作!

這些教學課程會引導您編寫測試,以模擬應用程式中的使用者互動

檢查點:依照此點擊、拖曳和輸入文字食譜文章,學習如何使用 WidgetTester 來模擬和測試應用程式中的使用者互動。

額外教學處理捲動的 cookbook 食譜示範了如何透過使用 widget 測試捲動列表來驗證 widget 列表是否包含預期的內容。

下一步:網路

#

這個頁面是關於處理使用者輸入的介紹。現在您已經了解如何處理來自應用程式使用者的輸入,您可以透過新增外部資料來讓您的應用程式更加有趣。在下一節中,您將學習如何透過網路為您的應用程式獲取資料、如何將資料轉換為 JSON 以及從 JSON 轉換資料、驗證和其他網路功能。

意見回饋

#

由於網站的這部分正在不斷發展,我們歡迎您的回饋