// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Template: dev/snippets/config/templates/freeform.tmpl // // Comment lines marked with "▼▼▼" and "▲▲▲" are used for authoring // of samples, and may be ignored if you are just exploring the sample. // Flutter code sample for RawAutocomplete // //*************************************************************************** //* ▼▼▼▼▼▼▼▼ description ▼▼▼▼▼▼▼▼ (do not modify or remove section marker) // This example is similar to the previous example, but it uses a custom T data // type instead of directly using String. //* ▲▲▲▲▲▲▲▲ description ▲▲▲▲▲▲▲▲ (do not modify or remove section marker) //*************************************************************************** //************************************************************************* //* ▼▼▼▼▼▼▼▼ code-main ▼▼▼▼▼▼▼▼ (do not modify or remove section marker) import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; void main() => runApp(const AutocompleteExampleApp()); class AutocompleteExampleApp extends StatelessWidget { const AutocompleteExampleApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text('RawAutocomplete Custom Type'), ), body: const Center( child: AutocompleteCustomTypeExample(), ), ), ); } } // An example of a type that someone might want to autocomplete a list of. @immutable class User { const User({ required this.email, required this.name, }); final String email; final String name; @override String toString() { return '$name, $email'; } @override bool operator ==(Object other) { if (other.runtimeType != runtimeType) { return false; } return other is User && other.name == name && other.email == email; } @override int get hashCode => hashValues(email, name); } class AutocompleteCustomTypeExample extends StatelessWidget { const AutocompleteCustomTypeExample({Key? key}) : super(key: key); static const List _userOptions = [ User(name: 'Alice', email: 'alice@example.com'), User(name: 'Bob', email: 'bob@example.com'), User(name: 'Charlie', email: 'charlie123@gmail.com'), ]; static String _displayStringForOption(User option) => option.name; @override Widget build(BuildContext context) { return RawAutocomplete( optionsBuilder: (TextEditingValue textEditingValue) { return _userOptions.where((User option) { // Search based on User.toString, which includes both name and // email, even though the display string is just the name. return option .toString() .contains(textEditingValue.text.toLowerCase()); }); }, displayStringForOption: _displayStringForOption, fieldViewBuilder: (BuildContext context, TextEditingController textEditingController, FocusNode focusNode, VoidCallback onFieldSubmitted) { return TextFormField( controller: textEditingController, focusNode: focusNode, onFieldSubmitted: (String value) { onFieldSubmitted(); }, ); }, optionsViewBuilder: (BuildContext context, AutocompleteOnSelected onSelected, Iterable options) { return Align( alignment: Alignment.topLeft, child: Material( elevation: 4.0, child: SizedBox( height: 200.0, child: ListView.builder( padding: const EdgeInsets.all(8.0), itemCount: options.length, itemBuilder: (BuildContext context, int index) { final User option = options.elementAt(index); return GestureDetector( onTap: () { onSelected(option); }, child: ListTile( title: Text(_displayStringForOption(option)), ), ); }, ), ), ), ); }, ); } } //* ▲▲▲▲▲▲▲▲ code-main ▲▲▲▲▲▲▲▲ (do not modify or remove section marker) //*************************************************************************