flutter-searchfield

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Flutter SearchField Implementation

Flutter SearchField 组件实现

SearchField is a highly customizable autocomplete widget for Flutter.
SearchField是一款针对Flutter的高度可定制自动补全组件。

Installation

安装

bash
flutter pub add searchfield
Or add manually to
pubspec.yaml
:
yaml
dependencies:
  searchfield: ^2.0.0
dart
import 'package:searchfield/searchfield.dart';
bash
flutter pub add searchfield
或者手动添加到
pubspec.yaml
中:
yaml
dependencies:
  searchfield: ^2.0.0
dart
import 'package:searchfield/searchfield.dart';

Quick Start

快速开始

Implementation follows three core steps: initialize suggestions, map to SearchFieldListItem, and add the widget.
实现过程遵循三个核心步骤:初始化建议项、映射为SearchFieldListItem、添加组件。

Step 1: Initialize Suggestions

步骤1:初始化建议项

dart
late List<SearchFieldListItem<YourType>> items;
YourType? selectedValue;


void initState() {
  items = yourDataList.map((item) {
    return SearchFieldListItem<YourType>(
      item.searchableProperty,  // Required: search performed on this
      value: item.displayValue, // Optional: shown in input on selection
      item: item,              // Optional: custom object
      child: customWidget,     // Optional: custom suggestion widget
    );
  }).toList();
  super.initState();
}
dart
late List<SearchFieldListItem<YourType>> items;
YourType? selectedValue;


void initState() {
  items = yourDataList.map((item) {
    return SearchFieldListItem<YourType>(
      item.searchableProperty,  // 必填:基于该属性执行搜索
      value: item.displayValue, // 可选:选中后在输入框中显示的值
      item: item,              // 可选:自定义对象
      child: customWidget,     // 可选:自定义建议项组件
    );
  }).toList();
  super.initState();
}

Step 2: Add SearchField Widget

步骤2:添加SearchField组件

dart
SearchField<YourType>(
  hint: 'Search placeholder',
  suggestions: items,
  selectedValue: selectedValue,
  onSuggestionTap: (SearchFieldListItem<YourType> item) {
    setState(() {
      selectedValue = item;
    });
  },
  onSearchTextChanged: (query) {
    // Return filtered list based on query
    if (query.isEmpty) return items;
    return items.where((item) =>
      item.searchKey.toLowerCase().contains(query.toLowerCase())
    ).toList();
  },
)
dart
SearchField<YourType>(
  hint: '搜索占位符',
  suggestions: items,
  selectedValue: selectedValue,
  onSuggestionTap: (SearchFieldListItem<YourType> item) {
    setState(() {
      selectedValue = item;
    });
  },
  onSearchTextChanged: (query) {
    // 根据查询条件返回过滤后的列表
    if (query.isEmpty) return items;
    return items.where((item) =>
      item.searchKey.toLowerCase().contains(query.toLowerCase())
    ).toList();
  },
)

Common Patterns

常见实现模式

Pattern 1: Basic Text Search

模式1:基础文本搜索

For simple string lists without custom objects:
dart
SearchField(
  suggestions: ['Item 1', 'Item 2', 'Item 3']
    .map((e) => SearchFieldListItem<String>(e))
    .toList(),
  suggestionState: Suggestion.expand,
  onSuggestionTap: (item) {
    // Handle selection
  },
)
适用于无自定义对象的简单字符串列表:
dart
SearchField(
  suggestions: ['Item 1', 'Item 2', 'Item 3']
    .map((e) => SearchFieldListItem<String>(e))
    .toList(),
  suggestionState: Suggestion.expand,
  onSuggestionTap: (item) {
    // 处理选中逻辑
  },
)

Pattern 2: Complex Objects with Custom Display

模式2:带自定义展示的复杂对象

When displaying rich content in suggestions:
dart
SearchFieldListItem<City>(
  city.name,                    // Search key
  value: city.zipCode,          // Value shown in input on select
  item: city,                   // Full object for reference
  child: Row(                   // Custom widget
    children: [
      Icon(Icons.location_city),
      SizedBox(width: 8),
      Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(city.name, style: TextStyle(fontWeight: FontWeight.bold)),
          Text(city.zipCode, style: TextStyle(fontSize: 12)),
        ],
      ),
    ],
  ),
)
当需要在建议项中展示丰富内容时:
dart
SearchFieldListItem<City>(
  city.name,                    // 搜索关键字
  value: city.zipCode,          // 选中后在输入框显示的值
  item: city,                   // 用于参考的完整对象
  child: Row(                   // 自定义组件
    children: [
      Icon(Icons.location_city),
      SizedBox(width: 8),
      Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(city.name, style: TextStyle(fontWeight: FontWeight.bold)),
          Text(city.zipCode, style: TextStyle(fontSize: 12)),
        ],
      ),
    ],
  ),
)

Pattern 3: Network Loading with Pagination

模式3:带分页的网络加载

Load suggestions dynamically from API:
dart
SearchField(
  onTap: () async {
    // Trigger initial load
    final results = await fetchFromAPI();
    setState(() => suggestions = results);
  },
  onSearchTextChanged: (query) {
    // Filter or fetch based on query
    return filteredSuggestions
      .map((e) => SearchFieldListItem<String>(e))
      .toList();
  },
  emptyWidget: Container(
    height: 100,
    child: Center(
      child: CircularProgressIndicator(),
    ),
  ),
  onScroll: (position, maxScroll) {
    // Load more when near bottom
    if (position > maxScroll * 0.8) {
      loadMoreItems();
    }
  },
)
从API动态加载建议项:
dart
SearchField(
  onTap: () async {
    // 触发初始加载
    final results = await fetchFromAPI();
    setState(() => suggestions = results);
  },
  onSearchTextChanged: (query) {
    // 根据查询条件过滤或获取数据
    return filteredSuggestions
      .map((e) => SearchFieldListItem<String>(e))
      .toList();
  },
  emptyWidget: Container(
    height: 100,
    child: Center(
      child: CircularProgressIndicator(),
    ),
  ),
  onScroll: (position, maxScroll) {
    // 滚动到底部附近时加载更多
    if (position > maxScroll * 0.8) {
      loadMoreItems();
    }
  },
)

Customization Guide

自定义指南

Input Field Styling

输入框样式

Use
searchInputDecoration
for TextField-like customization:
dart
searchInputDecoration: SearchInputDecoration(
  prefixIcon: Icon(Icons.search),
  suffixIcon: Icon(Icons.arrow_drop_down),
  hintStyle: TextStyle(color: Colors.grey),
  border: OutlineInputBorder(
    borderRadius: BorderRadius.circular(8),
  ),
  focusedBorder: OutlineInputBorder(
    borderSide: BorderSide(color: Colors.blue, width: 2),
  ),
  filled: true,
  fillColor: Colors.grey[100],
)
使用
searchInputDecoration
实现类似TextField的自定义:
dart
searchInputDecoration: SearchInputDecoration(
  prefixIcon: Icon(Icons.search),
  suffixIcon: Icon(Icons.arrow_drop_down),
  hintStyle: TextStyle(color: Colors.grey),
  border: OutlineInputBorder(
    borderRadius: BorderRadius.circular(8),
  ),
  focusedBorder: OutlineInputBorder(
    borderSide: BorderSide(color: Colors.blue, width: 2),
  ),
  filled: true,
  fillColor: Colors.grey[100],
)

Suggestion List Styling

建议列表样式

Customize the dropdown container:
dart
suggestionsDecoration: SuggestionDecoration(
  border: Border.all(color: Colors.grey),
  borderRadius: BorderRadius.circular(8),
  color: Colors.white,
  hoverColor: Colors.grey.shade200,
)
自定义下拉容器样式:
dart
suggestionsDecoration: SuggestionDecoration(
  border: Border.all(color: Colors.grey),
  borderRadius: BorderRadius.circular(8),
  color: Colors.white,
  hoverColor: Colors.grey.shade200,
)

Individual Suggestion Item Styling

单个建议项样式

Style each suggestion item:
dart
suggestionItemDecoration: SuggestionDecoration(
  padding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
  color: Colors.grey.shade200,
  borderRadius: BorderRadius.all(Radius.circular(2)),
)
自定义每个建议项的样式:
dart
suggestionItemDecoration: SuggestionDecoration(
  padding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
  color: Colors.grey.shade200,
  borderRadius: BorderRadius.all(Radius.circular(2)),
)

Advanced Features

高级功能

Form Validation

表单验证

Integrate with Flutter Forms:
dart
Form(
  key: _formKey,
  child: SearchField(
    suggestions: validOptions.map((e) => SearchFieldListItem(e)).toList(),
    validator: (value) {
      if (value == null || value.isEmpty) {
        return 'Please select an option';
      }
      if (!validOptions.contains(value)) {
        return 'Please select a valid option';
      }
      return null;
    },
    autovalidateMode: AutovalidateMode.onUserInteraction,
  ),
)
与Flutter表单集成:
dart
Form(
  key: _formKey,
  child: SearchField(
    suggestions: validOptions.map((e) => SearchFieldListItem(e)).toList(),
    validator: (value) {
      if (value == null || value.isEmpty) {
        return '请选择一个选项';
      }
      if (!validOptions.contains(value)) {
        return '请选择有效的选项';
      }
      return null;
    },
    autovalidateMode: AutovalidateMode.onUserInteraction,
  ),
)

Keyboard Navigation

键盘导航

Enabled by default for desktop platforms:
  • ↑/↓
    - Navigate suggestions (circular)
  • Ctrl/Option + ↓
    - Jump to last item
  • Ctrl/Option + ↑
    - Jump to first item
  • Enter
    - Select highlighted suggestion
  • Esc
    - Close suggestions
桌面平台默认启用:
  • ↑/↓
    - 循环导航建议项
  • Ctrl/Option + ↓
    - 跳转到最后一项
  • Ctrl/Option + ↑
    - 跳转到第一项
  • Enter
    - 选中高亮的建议项
  • Esc
    - 关闭建议列表

Dynamic Height Suggestions

动态高度建议项

Allow variable height items:
dart
SearchField(
  dynamicHeight: true,
  maxSuggestionBoxHeight: 400,  // Maximum viewport height
  suggestions: items.map((item) =>
    SearchFieldListItem(
      item.name,
      child: Container(
        // Variable height content
        child: Column(
          children: [
            Text(item.title),
            if (item.hasSubtitle) Text(item.subtitle),
          ],
        ),
      ),
    ),
  ).toList(),
)
支持可变高度的建议项:
dart
SearchField(
  dynamicHeight: true,
  maxSuggestionBoxHeight: 400,  // 最大视口高度
  suggestions: items.map((item) =>
    SearchFieldListItem(
      item.name,
      child: Container(
        // 可变高度内容
        child: Column(
          children: [
            Text(item.title),
            if (item.hasSubtitle) Text(item.subtitle),
          ],
        ),
      ),
    ),
  ).toList(),
)

Positioning Control

位置控制

Control suggestion list position:
dart
SearchField(
  suggestionDirection: SuggestionDirection.up,  // Show above input
  offset: Offset(0, 10),  // Offset from input field
  // Direction auto-adjusts based on available space
)
控制建议列表的显示位置:
dart
SearchField(
  suggestionDirection: SuggestionDirection.up,  // 在输入框上方显示
  offset: Offset(0, 10),  // 与输入框的偏移量
  // 会根据可用空间自动调整方向
)

Key Properties Reference

核心属性参考

Essential Properties:
  • suggestions
    (required) - List of SearchFieldListItem
  • onSuggestionTap
    - Callback when suggestion selected
  • onSearchTextChanged
    - Filter logic, returns filtered suggestions
  • selectedValue
    - Currently selected item
  • hint
    - Placeholder text
Display Configuration:
  • itemHeight
    - Fixed height per item (default: 51.0)
  • dynamicHeight
    - Enable variable item heights
  • maxSuggestionsInViewPort
    - Max visible items
  • maxSuggestionBoxHeight
    - Max dropdown height (with dynamicHeight)
Behavior:
  • suggestionState
    - Controls initial suggestion visibility:
    • Suggestion.expand
      — Show suggestions immediately when the field is focused (common for dropdown-style pickers)
    • Suggestion.hidden
      — Show suggestions only after the user starts typing (common for search-style inputs)
  • autoCorrect
    - Enable autocorrect (default: true)
  • enabled
    - Enable/disable widget (default: true)
  • readOnly
    - Make input read-only (default: false)
  • keepSearchOnSelection
    - Keep search text in the field after selecting a suggestion (default: false)
  • textInputAction
    - Keyboard action button
  • textCapitalization
    - Configures keyboard uppercase/lowercase behavior
  • textAlign
    - Alignment of the text in the searchfield (default: TextAlign.start)
  • inputFormatters
    - Input formatters for the search field
  • SuggestionAction
    - Enum to control focus behavior on suggestion tap
Callbacks:
  • onTap
    - When field gains focus
  • onSubmit
    - When form submitted
  • onOutsideTap
    - When tapping outside
  • onScroll
    - Scroll position updates (for pagination)
  • showEmpty
    - Boolean to show/hide the emptyWidget
Styling:
  • searchInputDecoration
    - Input field decoration
  • suggestionsDecoration
    - Dropdown container decoration
  • suggestionItemDecoration
    - Individual item decoration
  • searchStyle
    - Text style for input
  • suggestionStyle
    - Text style for suggestions
  • scrollbarDecoration
    - Decoration for the scrollbar
  • marginColor
    - Color for the margin between suggestions
Controllers:
  • controller
    - TextEditingController
  • focusNode
    - FocusNode for focus management
  • scrollController
    - Control suggestion list scroll
必备属性:
  • suggestions
    (必填)- SearchFieldListItem列表
  • onSuggestionTap
    - 选中建议项时的回调
  • onSearchTextChanged
    - 过滤逻辑,返回过滤后的建议项
  • selectedValue
    - 当前选中的项
  • hint
    - 占位符文本
显示配置:
  • itemHeight
    - 每个项的固定高度(默认:51.0)
  • dynamicHeight
    - 启用可变项高度
  • maxSuggestionsInViewPort
    - 最大可见项数量
  • maxSuggestionBoxHeight
    - 下拉框最大高度(配合dynamicHeight使用)
行为配置:
  • suggestionState
    - 控制建议列表初始可见性:
    • Suggestion.expand
      — 输入框获得焦点时立即显示建议列表(常见于下拉选择器)
    • Suggestion.hidden
      — 仅在用户开始输入后显示建议列表(常见于搜索式输入框)
  • autoCorrect
    - 启用自动校正(默认:true)
  • enabled
    - 启用/禁用组件(默认:true)
  • readOnly
    - 设置输入框为只读(默认:false)
  • keepSearchOnSelection
    - 选中建议项后保留搜索文本在输入框中(默认:false)
  • textInputAction
    - 键盘操作按钮
  • textCapitalization
    - 配置键盘大小写行为
  • textAlign
    - 输入框中文本对齐方式(默认:TextAlign.start)
  • inputFormatters
    - 输入框的输入格式化器
  • SuggestionAction
    - 枚举类型,控制选中建议项时的焦点行为
回调函数:
  • onTap
    - 输入框获得焦点时触发
  • onSubmit
    - 表单提交时触发
  • onOutsideTap
    - 点击外部区域时触发
  • onScroll
    - 滚动位置更新时触发(用于分页)
  • showEmpty
    - 控制是否显示emptyWidget的布尔值
样式配置:
  • searchInputDecoration
    - 输入框装饰
  • suggestionsDecoration
    - 下拉容器装饰
  • suggestionItemDecoration
    - 单个项的装饰
  • searchStyle
    - 输入框文本样式
  • suggestionStyle
    - 建议项文本样式
  • scrollbarDecoration
    - 滚动条装饰
  • marginColor
    - 建议项之间的间距颜色
控制器:
  • controller
    - TextEditingController
  • focusNode
    - 用于焦点管理的FocusNode
  • scrollController
    - 控制建议列表的滚动

Common Issues

常见问题

Issue: Suggestions not filtering

问题:建议项无法过滤

Cause:
onSearchTextChanged
not returning filtered list
Solution: Always return a filtered List<SearchFieldListItem> from
onSearchTextChanged
:
dart
onSearchTextChanged: (query) {
  if (query.isEmpty) return allSuggestions;

  return allSuggestions.where((item) {
    return item.searchKey.toLowerCase().contains(query.toLowerCase());
  }).toList();
}
原因
onSearchTextChanged
未返回过滤后的列表
解决方案:确保
onSearchTextChanged
始终返回过滤后的List<SearchFieldListItem>
dart
onSearchTextChanged: (query) {
  if (query.isEmpty) return allSuggestions;

  return allSuggestions.where((item) {
    return item.searchKey.toLowerCase().contains(query.toLowerCase());
  }).toList();
}

Issue: Selected value not displaying

问题:选中的值不显示

Cause: Not updating
selectedValue
in setState
Solution: Update state in onSuggestionTap:
dart
onSuggestionTap: (item) {
  setState(() {
    selectedValue = item;
  });
}
原因:未在setState中更新
selectedValue
解决方案:在onSuggestionTap中更新状态:
dart
onSuggestionTap: (item) {
  setState(() {
    selectedValue = item;
  });
}

Issue: Form validation not working

问题:表单验证不生效

Cause: SearchField not wrapped in Form or missing validator
Solution: Ensure Form wrapper and provide validator:
dart
Form(
  key: _formKey,
  child: SearchField(
    validator: (value) {
      if (value == null || value.isEmpty) {
        return 'Required field';
      }
      return null;
    },
  ),
)
原因:SearchField未包裹在Form中,或缺少validator
解决方案:确保使用Form包裹,并提供验证器:
dart
Form(
  key: _formKey,
  child: SearchField(
    validator: (value) {
      if (value == null || value.isEmpty) {
        return '必填项';
      }
      return null;
    },
  ),
)

Example Code References

示例代码参考