Skip to content

Instantly share code, notes, and snippets.

@MelbourneDeveloper
Created May 9, 2023 05:28
Show Gist options
  • Save MelbourneDeveloper/cd233afb0bf718d4b8bc71cc3999b776 to your computer and use it in GitHub Desktop.
Save MelbourneDeveloper/cd233afb0bf718d4b8bc71cc3999b776 to your computer and use it in GitHub Desktop.
ChipSet Sample
import 'package:flutter/material.dart';
final colors = [
const Color.fromARGB(255, 255, 0, 0),
const Color.fromARGB(255, 0, 255, 0),
const Color.fromARGB(255, 0, 0, 255),
];
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(useMaterial3: true),
home: const Scaffold(
body: ChipSets(),
),
),
);
}
class ChipSets extends StatefulWidget {
const ChipSets({
super.key,
});
@override
State<ChipSets> createState() => _ChipSetsState();
}
class _ChipSetsState extends State<ChipSets> {
var selectedItems = <Color>{};
@override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.topLeft,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'RawChip',
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: 12),
chipSet(),
const SizedBox(height: 12),
Text(
'FilterChip',
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: 12),
chipSet(builder: (
context,
color,
selected,
onSelected,
) {
return FilterChip(
selectedColor: color,
backgroundColor: color.withOpacity(.5),
selected: selected,
label: Text(colorToText(color)),
onSelected: onSelected,
);
}),
const SizedBox(height: 12),
Text(
'InputChip',
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: 12),
chipSet(builder: (
context,
color,
selected,
onSelected,
) {
return InputChip(
selectedColor: color,
backgroundColor: color.withOpacity(.5),
selected: selected,
label: Text(colorToText(color)),
onSelected: onSelected,
);
}),
const SizedBox(height: 12),
Text(
'ActionChip',
style: Theme.of(context).textTheme.bodyMedium,
),
chipSet(builder: (
context,
color,
selected,
onSelected,
) {
return ActionChip(
backgroundColor: color.withOpacity(.5),
label: Text(colorToText(color)),
//onPressed: () => onSelected(selected),
);
}),
],
),
);
}
String colorToText(Color color) {
if (color.blue == 255) return 'Blue';
if (color.red == 255) {
return 'Red';
} else {
return 'Green';
}
}
Widget chipSet<T extends Widget>(
{T Function(
BuildContext context,
Color color,
bool selected,
void Function(bool value) onSelected,
)?
builder}) =>
ChipSet(
constraints: const BoxConstraints(
maxWidth: 200,
minWidth: 200,
),
//direction: Axis.vertical,
spacing: 8,
runSpacing: 8,
chipBuilder: builder,
items: colors,
isSelected: (item) => selectedItems.contains(item),
onSelected: (item, value) {
setState(
() {
if (value) {
if (!selectedItems.contains(item)) selectedItems.add(item);
} else {
if (selectedItems.contains(item)) selectedItems.remove(item);
}
},
);
});
}
///Builds a custom chip widget for a given item of type T
///- BuildContext context: The build context in which the widget is being built.
///- T item: An item of type T from the list of items provided to the ChipSet.
///- bool selected: A boolean flag indicating whether the current item is selected or not.
///- void Function(bool value) onSelected: A callback function that is triggered when a chip is selected or deselected. It accepts a boolean value to indicate the selection state.
typedef ChipBuilder<T> = Widget Function(
BuildContext context,
T item,
bool selected,
void Function(bool value) onSelected,
);
///A Material Design widget that displays a set of chips
///based on a list of items of type [T].
///
///The type T is the type of the value that each chip item represents.
///All the entries in a given set must represent values
///with consistent types. Each item in items must be specialized
///with that same type argument. The chips can be created
///using a custom [ChipBuilder] function or the default
///implementation using [RawChip].
///
///[ChipSet] supports customizing the appearance and layout of each chip.
///The chips render in a [Wrap] and render horiontally by default.
///
///The onSelected callback should update a state list
///that defines the selected value. It should also call [State.setState]
///to rebuild the set with the new values.
class ChipSet<T> extends StatefulWidget {
/// Creates a [ChipSet].
///
/// The [items] must have distinct values.
///
/// The [onSelected] callback must update a state selected list
///
/// The [isSelected] callback must return a boolean value
/// based on the state selected list
const ChipSet({
required this.items,
required this.onSelected,
required this.isSelected,
this.chipBuilder,
this.spacing,
this.runSpacing,
this.constraints,
this.direction,
super.key,
});
/// An optional custom ChipBuilder function to build the chips.
/// If not provided, the default implementation using RawChip will be used.
/// and the chips will display a [toString] of the item.
final ChipBuilder<T>? chipBuilder;
///A function that returns true if the item is selected, otherwise false.
final bool Function(T item) isSelected;
///A list of items of type [T] that the chips will be built from.
final List<T> items;
//An optional set of constraints to apply to the size of the chips
//in the ChipSet.
final BoxConstraints? constraints;
///How much space to place between chips in a run in the main axis.
final double? spacing;
///How much space to place between the runs themselves in the cross axis.
final double? runSpacing;
///The direction to use as the main axis.
final Axis? direction;
///A callback function that is triggered when a chip is selected or deselected.
final void Function(T item, bool value) onSelected;
@override
State<ChipSet<T>> createState() => _ChipSetState<T>();
}
class _ChipSetState<T> extends State<ChipSet<T>> {
@override
Widget build(BuildContext context) => Wrap(
direction: widget.direction ?? Axis.horizontal,
spacing: widget.spacing ?? 0,
runSpacing: widget.runSpacing ?? 0,
children:
widget.items.map((item) => _buildItem(context, item)).toList(),
);
Widget _rawChip(
BuildContext context,
T item,
bool selected,
void Function(bool value) onSelected,
) =>
RawChip(
selected: selected,
label: Text(item.toString()),
onSelected: (value) => setState(() {
onSelected(value);
}),
);
Widget _buildItem(
BuildContext context,
item,
) {
final builder = widget.chipBuilder ?? _rawChip;
var child = builder(
context,
item,
widget.isSelected(item),
(value) => widget.onSelected(item, value),
);
if (widget.constraints != null) {
return ConstrainedBox(
constraints: widget.constraints!,
child: child,
);
}
return child;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment