// 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. /// Flutter code sample for [ListTile] selection in a ListView or GridView. // Long press any ListTile to enable selection mode. import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); static const String _title = 'Flutter Code Sample'; @override Widget build(BuildContext context) { return const MaterialApp( title: _title, home: ListTileSelectExample(), ); } } class ListTileSelectExample extends StatefulWidget { const ListTileSelectExample({super.key}); @override ListTileSelectExampleState createState() => ListTileSelectExampleState(); } class ListTileSelectExampleState extends State<ListTileSelectExample> { bool isSelectionMode = false; final int listLength = 30; late List<bool> _selected; bool _selectAll = false; bool _isGridMode = false; @override void initState() { super.initState(); initializeSelection(); } void initializeSelection() { _selected = List<bool>.generate(listLength, (_) => false); } @override void dispose() { _selected.clear(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text( 'ListTile selection', ), leading: isSelectionMode ? IconButton( icon: const Icon(Icons.close), onPressed: () { setState(() { isSelectionMode = false; }); initializeSelection(); }, ) : const SizedBox(), actions: <Widget>[ if (_isGridMode) IconButton( icon: const Icon(Icons.grid_on), onPressed: () { setState(() { _isGridMode = false; }); }, ) else IconButton( icon: const Icon(Icons.list), onPressed: () { setState(() { _isGridMode = true; }); }, ), if (isSelectionMode) TextButton( child: !_selectAll ? const Text( 'select all', style: TextStyle(color: Colors.white), ) : const Text( 'unselect all', style: TextStyle(color: Colors.white), ), onPressed: () { _selectAll = !_selectAll; setState(() { _selected = List<bool>.generate(listLength, (_) => _selectAll); }); }), ], ), body: _isGridMode ? GridBuilder( isSelectionMode: isSelectionMode, selectedList: _selected, onSelectionChange: (bool x) { setState(() { isSelectionMode = x; }); }, ) : ListBuilder( isSelectionMode: isSelectionMode, selectedList: _selected, onSelectionChange: (bool x) { setState(() { isSelectionMode = x; }); }, )); } } class GridBuilder extends StatefulWidget { const GridBuilder({ super.key, required this.selectedList, required this.isSelectionMode, required this.onSelectionChange, }); final bool isSelectionMode; final Function(bool)? onSelectionChange; final List<bool> selectedList; @override GridBuilderState createState() => GridBuilderState(); } class GridBuilderState extends State<GridBuilder> { void _toggle(int index) { if (widget.isSelectionMode) { setState(() { widget.selectedList[index] = !widget.selectedList[index]; }); } } @override Widget build(BuildContext context) { return GridView.builder( itemCount: widget.selectedList.length, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2), itemBuilder: (_, int index) { return InkWell( onTap: () => _toggle(index), onLongPress: () { if (!widget.isSelectionMode) { setState(() { widget.selectedList[index] = true; }); widget.onSelectionChange!(true); } }, child: GridTile( child: Container( child: widget.isSelectionMode ? Checkbox( onChanged: (bool? x) => _toggle(index), value: widget.selectedList[index]) : const Icon(Icons.image), )), ); }); } } class ListBuilder extends StatefulWidget { const ListBuilder({ super.key, required this.selectedList, required this.isSelectionMode, required this.onSelectionChange, }); final bool isSelectionMode; final List<bool> selectedList; final Function(bool)? onSelectionChange; @override State<ListBuilder> createState() => _ListBuilderState(); } class _ListBuilderState extends State<ListBuilder> { void _toggle(int index) { if (widget.isSelectionMode) { setState(() { widget.selectedList[index] = !widget.selectedList[index]; }); } } @override Widget build(BuildContext context) { return ListView.builder( itemCount: widget.selectedList.length, itemBuilder: (_, int index) { return ListTile( onTap: () => _toggle(index), onLongPress: () { if (!widget.isSelectionMode) { setState(() { widget.selectedList[index] = true; }); widget.onSelectionChange!(true); } }, trailing: widget.isSelectionMode ? Checkbox( value: widget.selectedList[index], onChanged: (bool? x) => _toggle(index), ) : const SizedBox.shrink(), title: Text('item $index')); }); } }