What is the Flutter InputChip Widget
Flutter InputChip Widget is a user interface element that represents a choice or an action in your app. It looks like a button but is smaller and more compact. InputChips can display a label, icon, or both, and are usually used to display options that the user can select from, such as tags or categories.
InputChips can be used in various scenarios, such as for filtering or searching data, selecting an item from a list, or adding tags to content. They are highly customizable, so you can adjust their appearance and behaviour to match your app’s design and requirements.
One of the advantages of using InputChips is that they are interactive and allow the user to select or deselect options. When the user taps an InputChip, it will display a selected or unselected state, depending on its current state. You can also add callbacks to handle user interaction with InputChips, such as when the user selects or deselects an option.
What is the difference between Chip and InputChip widget
The Flutter Chip widget and the Flutter InputChip widget are both user interface elements used to display a choice or an action in your app. However, there are some key differences between the two widgets.
The main difference is that the Flutter Chip widget is read-only and displays information, while the Flutter InputChip widget is interactive and allows the user to select or deselect options. This means that the user can interact with InputChips, but cannot interact with Chips.
Chips are often used to display information, such as tags or categories, while InputChips are used to enable user selection, such as selecting filters or adding tags to content. InputChips can display a label, an icon, or both, while Chips usually only display a label.
Another difference between the two widgets is that InputChips have a selected or unselected state, which allows the user to choose whether to activate the option or not. Chips do not have a selected or unselected state, as they only display information.
Where the Flutter InputChip widget can be used
The Flutter InputChip widget is a user interface element used to represent a choice or an action in your app, and it allows the user to select or deselect options. Here are some common use cases for the Flutter InputChip widget:
- Tags: InputChips are often used to represent tags that can be attached to content. For example, in a note-taking app, the user might use InputChips to tag their notes with different categories such as “personal,” “work,” or “ideas.”
- Filters: InputChips can be used to represent filters that the user can apply to a list of items. For example, in an e-commerce app, the user might use InputChips to filter products based on various criteria such as price range, category, or brand.
- Selections: InputChips can be used to represent selections that the user can make. For example, in a music player app, the user might use InputChips to select songs for a custom playlist.
- Contacts: InputChips can be used to represent contacts or people. For example, in a messaging app, the user might use InputChips to add recipients to a message.
- Search: InputChips can be used to represent search queries or search suggestions. For example, in a search engine app, the user might use InputChips to enter their search terms or to select from suggested search terms.
InputChip widget as a Button in Flutter
The InputChip widget can be used as a button in Flutter by styling it to look like a button and adding an onTap or onPressed event to handle the button press. Here’s an example code snippet that shows how to use the InputChip widget as a button:
InputChip(
label: Text('Press me!'),
onPressed: () {
// Handle button press here
print('Button pressed!');
},
backgroundColor: Colors.blue,
padding: EdgeInsets.symmetric(horizontal: 16.0),
labelStyle: TextStyle(color: Colors.white),
),
In this example, the InputChip widget is created with a label of “Press me!” and an onTap event handler that prints a message to the console when the button is pressed. The backgroundColor, padding, and labelStyle properties are used to style the InputChip to look like a button.
When the user taps on the InputChip, the onPressed event handler will be called, and any code inside the handler will be executed. In this case, we’re simply printing a message to the console, but you can replace this with any code you want to execute when the button is pressed.
Using the InputChip widget as a button is a great way to create interactive elements in your app without having to use a separate button widget. By styling the InputChip to look like a button, you can create a consistent visual style across your app and make it easier for users to understand how to interact with your app.
How to disable the InputChip widget after pressed
To disable an InputChip after it has been pressed, you can use the onPressed property. The onPressed property is a callback function that is executed when the InputChip is pressed. By default, it is set to null, which means that the InputChip is disabled. To enable the InputChip, you can set the onPressed property to a function that defines the action that should be performed when the InputChip is pressed.
To disable the InputChip after it has been pressed, you can create a boolean variable, such as _isDisabled, that is initially set to false. Then, in the onPressed function, you can check if the _isDisabled variable is true. If it is true, then the function returns null, which disables the InputChip. If it is false, then the function sets the _isDisabled variable to true, which disables the InputChip.
Here’s an example code snippet that demonstrates how to disable an InputChip after it has been pressed:
bool _isDisabled = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('flutterassets.com'),
),
body: Container(
alignment: Alignment.topCenter,
padding: const EdgeInsets.all(8.0),
child: InputChip(
label: _isDisabled ? Text('Disabled') : Text('Press me!'),
onPressed: _isDisabled ? null : () {
setState(() {
_isDisabled = true;
});
// Handle button press here
print('Button pressed!');
},
backgroundColor: Colors.blue,
padding: EdgeInsets.symmetric(horizontal: 16.0),
labelStyle: TextStyle(color: Colors.white),
),
),
);
}
In this example, the InputChip is initially enabled. When the user presses the InputChip, the onPressed function is called. It checks if the _isDisabled variable is true. If it is false, then the function sets the _isDisabled variable to true, which disables the InputChip. If the _isDisabled variable is true, then the function returns null, which disables the InputChip.
Use the Flutter InputChip widget as tags
here’s an example of how to use the Flutter InputChip widget as tags:
List<String> tags = ['Personal', 'Work', 'Ideas'];
List<String> selectedTags = [];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('flutterassets.com'),
),
body: Container(
alignment: Alignment.topCenter,
padding: const EdgeInsets.all(8.0),
child: Wrap(
children: tags.map((tag) {
return InputChip(
label: Text(tag),
selected: selectedTags.contains(tag),
selectedColor: Colors.blue,
onSelected: (isSelected) {
setState(() {
if (isSelected) {
selectedTags.add(tag);
} else {
selectedTags.remove(tag);
}
});
},
padding: EdgeInsets.symmetric(horizontal: 8.0),
labelStyle: TextStyle(
color: selectedTags.contains(tag) ? Colors.white : Colors.black,
),
backgroundColor: selectedTags.contains(tag) ? Colors.blue : Colors.grey[200],
);
}).toList(),
),
),
);
}
In this example, we have a list of tags (in this case, “Personal,” “Work,” and “Ideas”), and a list of selected tags (initially empty). We’re using a Wrap widget to display the tags in a horizontal row, and we’re mapping over the tags list to create an InputChip widget for each tag.
The label of each InputChip is set to the tag text, and we’re using the selected and onSelected properties to handle the chip selection state. The selectedColor property is used to change the background colour of a selected chip, and the backgroundColor property is used to set the default background colour for unselected chips.
When a chip is selected, we’re updating the selectedTags list and calling setState to trigger a rebuild of the widget. We’re also using the labelStyle property to change the text colour of a selected chip to white and the backgroundColor property to change the background colour to blue.
Use the Flutter InputChip widget as Filter
Here is an example of how to use the Flutter InputChip widget as filters in an e-commerce app with a list of products:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>{
List<Product> products = [
Product(name: 'Product 1', category: 'Category 1', price: 10.0),
Product(name: 'Product 2', category: 'Category 2', price: 20.0),
Product(name: 'Product 3', category: 'Category 1', price: 30.0),
Product(name: 'Product 4', category: 'Category 3', price: 40.0),
Product(name: 'Product 5', category: 'Category 2', price: 50.0),
];
List<String> categories = ['Category 1', 'Category 2', 'Category 3'];
List<String> selectedCategories = [];
List<String> priceRanges = ['Under \$25', '\$25 - \$50', '\$50 - \$100', 'Over \$100'];
List<String> selectedPriceRanges = [];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('flutterassets.com'),
),
body: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
final product = products[index];
if (selectedCategories.isNotEmpty && !selectedCategories.contains(product.category)) {
return SizedBox();
}
if (selectedPriceRanges.isNotEmpty) {
if (selectedPriceRanges.contains('Under \$25') && product.price >= 25) {
return SizedBox();
}
if (selectedPriceRanges.contains('\$25 - \$50') &&
(product.price < 25 || product.price >= 50)) {
return SizedBox();
}
if (selectedPriceRanges.contains('\$50 - \$100') &&
(product.price < 50 || product.price >= 100)) {
return SizedBox();
}
if (selectedPriceRanges.contains('Over \$100') && product.price < 100) {
return SizedBox();
}
}
return ListTile(
title: Text(product.name),
subtitle: Text('${product.category} - \$${product.price}'),
);
},
),
),
Wrap(
spacing: 8.0,
children: [
...categories.map((category) => InputChip(
label: Text(category),
selected: selectedCategories.contains(category),
onSelected: (isSelected) {
setState(() {
if (isSelected) {
selectedCategories.add(category);
} else {
selectedCategories.remove(category);
}
});
},
)),
...priceRanges.map((priceRange) => InputChip(
label: Text(priceRange),
selected: selectedPriceRanges.contains(priceRange),
onSelected: (isSelected) {
setState(() {
if (isSelected) {
selectedPriceRanges.add(priceRange);
} else {
selectedPriceRanges.remove(priceRange);
}
});
},
)),
],
),
],
),
);
}
}
class Product {
final String name;
final String category;
final double price;
Product({required this.name, required this.category, required this.price});
}
In this example, we have a list of products, each with a name, category, and price. We’re using a ListView.builder widget to display the products, and we’re filtering the list based on the selected categories and price ranges.
The categories and price ranges are displayed using an InputChip widget wrapped in a Wrap widget. When a chip is selected, we’re updating the selectedCategories or selectedPriceRanges list and calling setState to trigger a rebuild of the widget.
Inside the itemBuilder method of the ListView.builder widget, we’re checking whether a product should be displayed based on the selected categories and price ranges. If a product’s category isn’t in the selectedCategories list, we’re returning a SizedBox widget to hide it.
Similarly, if any of the selected price ranges don’t match the product’s price, we’re hiding it as well. If the product passes both checks, we’re displaying its details using a ListTile
widget.
By using InputChip
widgets to represent the categories and price ranges, we’re allowing the user to filter the products displayed on the screen. When a chip is selected, we’re updating the corresponding list (selectedCategories
or selectedPriceRanges
) and calling setState
to trigger a rebuild of the widget. This causes the ListView.builder
widget to re-run its itemBuilder
method and update the list of products displayed on the screen.
Use the Flutter InputChip widget with contacts
Here’s an example of how to use the Flutter InputChip widget with contacts:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>{
List<Contact> _contacts = [
Contact(
name: 'John Doe',
email: 'johndoe@example.com',
photoUrl:
'https://cdn.pixabay.com/photo/2017/01/31/21/23/avatar-2027366_960_720.png'),
Contact(
name: 'Jane Doe',
email: 'janedoe@example.com',
photoUrl:
'https://cdn.pixabay.com/photo/2014/04/03/10/32/user-310807_960_720.png'),
Contact(
name: 'Bob Smith',
email: 'bobsmith@example.com',
photoUrl:
'https://cdn.pixabay.com/photo/2016/08/08/09/17/avatar-1577909_960_720.png'),
Contact(
name: 'Alice Johnson',
email: 'alicejohnson@example.com',
photoUrl:
'https://cdn.pixabay.com/photo/2016/08/20/05/36/avatar-1606914_960_720.png'),
];
List<Contact> _selectedContacts = [];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('flutterassets.com'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'To:',
style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold),
),
),
Wrap(
spacing: 8.0,
children: _selectedContacts
.map(
(contact) => InputChip(
label: Text(contact.name),
avatar: CircleAvatar(
backgroundImage: NetworkImage(contact.photoUrl),
),
onDeleted: () {
setState(() {
_selectedContacts.remove(contact);
});
},
),
)
.toList(),
),
Expanded(
child: ListView.builder(
itemCount: _contacts.length,
itemBuilder: (context, index) {
final contact = _contacts[index];
return ListTile(
leading: CircleAvatar(
backgroundImage: NetworkImage(contact.photoUrl),
),
title: Text(contact.name),
subtitle: Text(contact.email),
trailing: _selectedContacts.contains(contact)
? Icon(Icons.check_circle_outline)
: null,
onTap: () {
setState(() {
if (_selectedContacts.contains(contact)) {
_selectedContacts.remove(contact);
} else {
_selectedContacts.add(contact);
}
});
},
);
},
),
),
],
),
);
}
}
class Contact {
final String name;
final String email;
final String photoUrl;
Contact({required this.name, required this.email, required this.photoUrl});
}
First, we define a class Contact
with a name and a photo. We will use this class to represent the contacts. In our example, the Contact
class is at the end of the code.
class Contact {
final String name;
final String email;
final String photoUrl;
Contact({required this.name, required this.email, required this.photoUrl});
}
Next, we create a list of Contact
objects to represent the contacts that the user can select.
List<Contact> _contacts = [
Contact(
name: 'John Doe',
email: 'johndoe@example.com',
photoUrl:
'https://cdn.pixabay.com/photo/2017/01/31/21/23/avatar-2027366_960_720.png'),
Contact(
name: 'Jane Doe',
email: 'janedoe@example.com',
photoUrl:
'https://cdn.pixabay.com/photo/2014/04/03/10/32/user-310807_960_720.png'),
Contact(
name: 'Bob Smith',
email: 'bobsmith@example.com',
photoUrl:
'https://cdn.pixabay.com/photo/2016/08/08/09/17/avatar-1577909_960_720.png'),
Contact(
name: 'Alice Johnson',
email: 'alicejohnson@example.com',
photoUrl:
'https://cdn.pixabay.com/photo/2016/08/20/05/36/avatar-1606914_960_720.png'),
];
We then create an empty list selectedContacts
to keep track of the contacts that the user has selected.
List<Contact> _selectedContacts = [];
Next, we use a Wrap
widget to display the contacts as InputChip
s. We iterate over the contacts
list using the map
method to create an InputChip
for each contact. We set the label
property of the InputChip
to the contact’s name and the avatar
property to the contact’s photo. We also set the selected
property of the InputChip
to true
if the contact is in the selectedContacts
list.
Wrap(
spacing: 8.0,
children: _selectedContacts
.map(
(contact) => InputChip(
label: Text(contact.name),
avatar: CircleAvatar(
backgroundImage: NetworkImage(contact.photoUrl),
),
onDeleted: () {
setState(() {
_selectedContacts.remove(contact);
});
},
),
)
.toList(),
),
When the user taps on an InputChip
, we update the selectedContacts
list by adding or removing the selected contact, depending on whether the InputChip
is selected or deselected. We use the setState
method to trigger a rebuild of the widget and update the UI.
Use the Flutter InputChip widget with the selection
Here’s an example of how to use the Flutter InputChip widget to allow the user to make selections in a music player app:
final List<String> songs = [
'Song 1',
'Song 2',
'Song 3',
'Song 4',
'Song 5',
'Song 6',
'Song 7',
'Song 8',
'Song 9',
'Song 10',
];
final List<String> selectedSongs = [];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('flutterassets.com'),
),
body: Column(
children: [
Wrap(
spacing: 8.0,
children: songs.map((song) => InputChip(
label: Text(song),
selected: selectedSongs.contains(song),
onSelected: (isSelected) {
setState(() {
if (isSelected) {
selectedSongs.add(song);
} else {
selectedSongs.remove(song);
}
});
},
)).toList(),
),
ElevatedButton(
onPressed: () {
print('Selected songs: $selectedSongs');
},
child: Text('Play Selected Songs'),
),
],
),
);
}
In this example, we have a list of songs that the user can select using InputChip widgets. The selected songs are stored in the selectedSongs
list.
The songs are displayed using an InputChip widget wrapped in a Wrap widget. When a chip is selected, we’re updating the selectedSongs
list and calling setState
to trigger a rebuild of the widget.
We also have a button that the user can press to play the selected songs. When the button is pressed, we’re simply printing the selectedSongs
list to the console.
Use the Flutter InputChip widget with the search
Here’s an example of how to use the Flutter InputChip widget as search queries or suggestions in a search app:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>{
TextEditingController _searchQueryController = TextEditingController();
bool _isSearching = false;
List<String> searchHistory = [
'Flutter tutorial',
'Dart programming',
'Mobile app development',
];
List<String> searchSuggestions = [
'Flutter widgets',
'Firebase integration',
'Flutter animations',
'Flutter packages',
];
@override
void initState() {
super.initState();
_searchQueryController.addListener(() {
setState(() {});
});
}
@override
void dispose() {
_searchQueryController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: _isSearching ? BackButton() : null,
title: _isSearching
? TextField(
controller: _searchQueryController,
decoration: InputDecoration(
hintText: 'Search...',
border: InputBorder.none,
),
)
: Text('flutterassets.com'),
actions: <Widget>[
_isSearching
? IconButton(
icon: Icon(Icons.clear),
onPressed: () {
_searchQueryController.clear();
},
)
: IconButton(
icon: Icon(Icons.search),
onPressed: () {
setState(() {
_isSearching = true;
});
},
)
],
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
if (_searchQueryController.text.isNotEmpty)
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Search Results for "${_searchQueryController.text}"',
style: Theme.of(context).textTheme.titleLarge,
),
),
if (_searchQueryController.text.isEmpty && searchHistory.isNotEmpty)
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Search History',
style: Theme.of(context).textTheme.titleLarge,
),
),
Wrap(
spacing: 8.0,
children: _searchQueryController.text.isEmpty
? searchHistory
.map(
(query) => InputChip(
label: Text(query),
onPressed: () {
_searchQueryController.text = query;
setState(() {
_isSearching = true;
});
},
),
)
.toList()
: searchSuggestions
.where((suggestion) =>
suggestion.contains(_searchQueryController.text))
.map(
(suggestion) => InputChip(
label: Text(suggestion),
onPressed: () {
_searchQueryController.text = suggestion;
setState(() {
_isSearching = true;
});
},
),
)
.toList(),
),
],
),
),
);
}
}
In this example, we have a search app with an AppBar that contains a search icon. When the user taps the icon, the AppBar transforms to contain a TextField where the user can enter their search query. The search history and search suggestions are displayed as InputChips in a Wrap widget below the AppBar.
As the user types in the search query, the search suggestions are filtered based on the input text using the where
method. When the user taps on a search suggestion, the onSelected
callback of the InputChip
is called, and the selected suggestion is added to the search history.
The search history is stored in a List<String>
, and is displayed as InputChips in the same Wrap widget as the search suggestions. When the user taps on a search history InputChip, the onDeleted
callback is called, and the corresponding history item is removed from the list.
Finally, when the user submits the search query by pressing the enter key or tapping the search icon in the keyboard, the onSubmitted
callback of the TextField is called, and the search query is added to the search history and displayed as an InputChip. In this example, we have also added a button to clear the search history, which removes all items from the list and updates the UI.