Last active
March 1, 2020 00:18
-
-
Save ffeu/340f744192da3c2678cd663e7d2e19d1 to your computer and use it in GitHub Desktop.
PopupMenuItem vs ListView, ReorderableListView and ReorderableList (problem in PopupMenuItem vs ReorderableListView) (flutter 1.0.0, flutter_reorderable_list 0.1.1)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'package:flutter_reorderable_list/flutter_reorderable_list.dart'; | |
class MyHomePage extends StatefulWidget { | |
@override | |
_MyHomePageState createState() => _MyHomePageState(); | |
} | |
class _MyHomePageState extends State<MyHomePage> { | |
List<MyItem> _sampleItems; | |
int _selectedView; | |
@override | |
void initState() { | |
super.initState(); | |
_selectedView = 0; | |
_sampleItems = []; | |
for(int i = 1; i < 100; i++) { | |
_sampleItems.add(MyItem(i.toString(), randomIcons[i], "Item $i")); | |
} | |
} | |
Widget _buildOptions(MyItem item) { | |
return PopupMenuButton( | |
itemBuilder: (BuildContext context) { | |
return [ | |
new PopupMenuItem(child: new Text("edit"), value: "edit"), | |
new PopupMenuItem(child: new Text("delete"), value: "delete"), | |
]; | |
}, | |
onSelected: (selected) async { | |
await showDialog(context: context, | |
builder: (BuildContext context) { | |
return SimpleDialog( | |
title: Text(selected), | |
contentPadding: EdgeInsets.all(25.0), | |
children: <Widget>[Text("Item [${item.title}], Operation [$selected].")], | |
); | |
} | |
); | |
}, | |
); | |
} | |
Widget _buildListTile(BuildContext context, MyItem item, {ReorderableListener listener}) { | |
Widget options = _buildOptions(item); | |
if (listener != null) | |
options = Row( | |
mainAxisAlignment: MainAxisAlignment.end, | |
mainAxisSize: MainAxisSize.min, | |
children: <Widget>[ | |
options, | |
listener, | |
], | |
); | |
return ListTile(key: Key(item.key), | |
leading: Icon(item.icon), | |
title: Text(item.title), | |
trailing: options, | |
); | |
} | |
BoxDecoration _decoration(ReorderableItemState state) { | |
if (state == ReorderableItemState.dragProxy || | |
state == ReorderableItemState.dragProxyFinished) { | |
return BoxDecoration(color: Color(0xD0FFFFFF)); | |
} else { | |
bool placeholder = state == ReorderableItemState.placeholder; | |
return BoxDecoration( | |
border: Border( | |
top: !placeholder | |
? Divider.createBorderSide(context) | |
: BorderSide.none, | |
bottom: placeholder | |
? BorderSide.none | |
: Divider.createBorderSide(context)), | |
color: placeholder ? null : Colors.white); | |
} | |
} | |
Widget _buildReorderableItem(BuildContext context, int index) { | |
var item = _sampleItems[index]; | |
return ReorderableItem( | |
key: Key(item.key), | |
childBuilder: (BuildContext context, ReorderableItemState state) { | |
BoxDecoration decoration = _decoration(state); | |
return Container( | |
decoration: decoration, | |
child: Opacity( | |
opacity: state == ReorderableItemState.placeholder ? 0.0 : 1.0, | |
child: _buildListTile(context, item, | |
listener: ReorderableListener( | |
child: Center(child: Icon(Icons.reorder)))), | |
), | |
); | |
}, | |
); | |
} | |
int _indexOfKey(Key key) { | |
return _sampleItems.indexWhere((MyItem i) => Key(i.key) == key); | |
} | |
Widget _buildReorderableList(BuildContext context) { | |
return ReorderableList( | |
child: CustomScrollView( | |
slivers: <Widget>[ | |
SliverList( | |
delegate: SliverChildBuilderDelegate( | |
(BuildContext context, int index) { | |
return _buildReorderableItem(context, index); | |
}, | |
childCount: _sampleItems.length, | |
), | |
) | |
], | |
), | |
onReorder: (Key draggedItem, Key newPosition) { | |
int draggingIndex = _indexOfKey(draggedItem); | |
int newPositionIndex = _indexOfKey(newPosition); | |
final item = _sampleItems[draggingIndex]; | |
setState(() { | |
_sampleItems.removeAt(draggingIndex); | |
_sampleItems.insert(newPositionIndex, item); | |
}); | |
return true; | |
}, | |
); | |
} | |
Widget _buildReorderableListView(BuildContext context) { | |
return ReorderableListView( | |
children: _sampleItems | |
.map((MyItem item) => _buildListTile(context, item)).toList(), | |
onReorder: (oldIndex, newIndex) { | |
setState(() { | |
if (newIndex > _sampleItems.length) newIndex = _sampleItems.length; | |
if (oldIndex < newIndex) newIndex--; | |
MyItem item = _sampleItems[oldIndex]; | |
_sampleItems.remove(item); | |
_sampleItems.insert(newIndex, item); | |
}); | |
}, | |
); | |
} | |
Widget _buildListView(BuildContext context) { | |
return ListView( | |
children: _sampleItems | |
.map((MyItem item) => _buildListTile(context, item)).toList(), | |
); | |
} | |
void _radioChanged(int value) { | |
setState(() => _selectedView = value); | |
} | |
Widget _buildRadio(BuildContext context) { | |
return Column( | |
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |
children: <Widget>[ | |
RadioListTile<int>( | |
value: 0, | |
groupValue: _selectedView, | |
onChanged: _radioChanged, | |
title: Text("ListView"), | |
), | |
RadioListTile<int>( | |
value: 1, | |
groupValue: _selectedView, | |
onChanged: _radioChanged, | |
title: Text("ReorderableListView"), | |
), | |
RadioListTile<int>( | |
value: 2, | |
groupValue: _selectedView, | |
onChanged: _radioChanged, | |
title: Text("ReorderableList"), | |
), | |
], | |
); | |
} | |
Widget _view(BuildContext context) { | |
if (_selectedView == 1) | |
return _buildReorderableListView(context); | |
if (_selectedView == 2) | |
return _buildReorderableList(context); | |
return _buildListView(context); | |
} | |
Widget _buildBody(BuildContext context) { | |
return Container( | |
padding: EdgeInsets.all(10.0), | |
child: Column( | |
children: <Widget>[ | |
_buildRadio(context), | |
Expanded(child: _view(context)), | |
], | |
), | |
); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar(title: Text(title)), | |
body: _buildBody(context), | |
); | |
} | |
} | |
class MyApp extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: title, | |
theme: ThemeData( | |
primarySwatch: Colors.pink, | |
), | |
home: MyHomePage(), | |
); | |
} | |
} | |
void main() => runApp(MyApp()); | |
class MyItem { | |
MyItem(this.key, this.icon, this.title); | |
final String key; | |
final IconData icon; | |
final String title; | |
bool operator ==(o) => o is MyItem && o.key == key; | |
int get hashCode => key.hashCode; | |
} | |
const title = "PopupMenuItem test"; | |
List<IconData> randomIcons = [ | |
Icons.g_translate, Icons.backspace, Icons.backup, Icons.battery_alert, Icons.cached, Icons.cake, Icons.calendar_today, | |
Icons.camera_enhance, Icons.camera_front, Icons.camera_rear, Icons.camera_roll, Icons.camera, Icons.cancel, Icons.card_giftcard, Icons.card_membership, Icons.card_travel, Icons.casino, Icons.cast_connected, | |
Icons.calendar_view_day, Icons.call_end, Icons.call_made, Icons.call_merge, Icons.call_missed_outgoing, Icons.call_missed, Icons.call_received, Icons.call_split, Icons.call_to_action, Icons.call, Icons.camera_alt, | |
Icons.laptop, Icons.last_page, Icons.launch, Icons.layers_clear, Icons.layers, Icons.mail_outline, Icons.mail, Icons.map, Icons.markunread_mailbox, Icons.markunread, Icons.maximize, | |
Icons.cast, Icons.category, Icons.dashboard, Icons.data_usage, Icons.date_range, Icons.face, Icons.fast_forward, Icons.fast_rewind, Icons.fastfood, Icons.favorite_border, Icons.favorite, | |
Icons.gamepad, Icons.games, Icons.gavel, Icons.label_important, Icons.label_outline, Icons.label, Icons.landscape, Icons.language, Icons.laptop_chromebook, Icons.laptop_mac, Icons.laptop_windows, | |
Icons.wc, Icons.adb, Icons.add_a_photo, Icons.add_alarm, Icons.add_alert, Icons.add_box, Icons.add_call, Icons.add_circle_outline, Icons.add_circle, Icons.add_comment, Icons.add_location, | |
Icons.panorama_vertical, Icons.panorama_wide_angle, Icons.panorama, Icons.party_mode, Icons.pause_circle_filled, Icons.pause_circle_outline, Icons.pause, Icons.payment, Icons.radio_button_checked, Icons.radio_button_unchecked, Icons.radio, | |
Icons.nature_people, Icons.nature, Icons.navigate_before, Icons.navigate_next, Icons.navigation, Icons.pages, Icons.pageview, Icons.palette, Icons.pan_tool, Icons.panorama_fish_eye, Icons.panorama_horizontal, | |
Icons.ac_unit, Icons.access_alarm, Icons.access_alarms, Icons.access_time, Icons.accessibility_new, Icons.accessibility, Icons.accessible_forward, Icons.accessible, Icons.account_balance_wallet, Icons.account_balance, Icons.account_box, | |
Icons.delete_forever, Icons.delete_outline, Icons.delete_sweep, Icons.delete, Icons.departure_board, Icons.description, Icons.desktop_mac, Icons.desktop_windows, Icons.details, Icons.developer_board, Icons.developer_mode, | |
Icons.rate_review, Icons.satellite, Icons.save_alt, Icons.save, Icons.tab_unselected, Icons.tab, Icons.table_chart, Icons.tablet_android, Icons.tablet_mac, Icons.tablet, | |
Icons.tag_faces, Icons.tap_and_play, Icons.wallpaper, Icons.warning, Icons.watch_later, Icons.watch, Icons.wb_auto, Icons.wb_cloudy, Icons.wb_incandescent, Icons.wb_iridescent, Icons.wb_sunny, | |
Icons.account_circle, Icons.scanner, Icons.scatter_plot, Icons.schedule, Icons.school, Icons.score, Icons.screen_lock_landscape, Icons.screen_lock_portrait, Icons.screen_lock_rotation, Icons.screen_rotation, Icons.screen_share, | |
Icons.add_photo_alternate, Icons.add_shopping_cart, Icons.add_to_home_screen, Icons.add_to_photos, Icons.add_to_queue, Icons.add, Icons.adjust, Icons.edit_attributes, Icons.edit_location, Icons.edit, Icons.hd, | |
Icons.hdr_off, Icons.hdr_on, Icons.hdr_strong, Icons.hdr_weak, Icons.sd_card, Icons.sd_storage, Icons.beach_access, Icons.beenhere, Icons.center_focus_strong, Icons.center_focus_weak, Icons.dehaze, | |
Icons.device_hub, Icons.device_unknown, Icons.devices_other, Icons.devices, Icons.featured_play_list, Icons.featured_video, Icons.feedback, Icons.gesture, Icons.get_app, Icons.headset_mic, Icons.headset_off, | |
Icons.headset, Icons.healing, Icons.hearing, Icons.help_outline, Icons.help, Icons.keyboard_arrow_down, Icons.keyboard_arrow_left, Icons.keyboard_arrow_right, Icons.keyboard_arrow_up, Icons.keyboard_backspace, Icons.keyboard_capslock, | |
Icons.keyboard_hide, Icons.keyboard_return, Icons.keyboard_tab, Icons.keyboard_voice, Icons.keyboard, Icons.leak_add, Icons.leak_remove, Icons.lens, Icons.memory, Icons.menu, Icons.merge_type, | |
Icons.message, Icons.near_me, Icons.network_cell, Icons.network_check, Icons.network_locked, Icons.network_wifi, Icons.new_releases, Icons.next_week, Icons.people_outline, Icons.people, Icons.perm_camera_mic, | |
Icons.perm_contact_calendar, Icons.perm_data_setting, Icons.perm_device_information, Icons.perm_identity, Icons.perm_media, Icons.perm_phone_msg, Icons.perm_scan_wifi, Icons.person_add, Icons.person_outline, Icons.person_pin_circle, Icons.person_pin, | |
Icons.person, Icons.personal_video, Icons.pets, Icons.receipt, Icons.recent_actors, Icons.record_voice_over, Icons.redeem, Icons.redo, Icons.refresh, Icons.remove_circle_outline, Icons.remove_circle, | |
Icons.remove_from_queue, Icons.remove_red_eye, Icons.remove_shopping_cart, Icons.remove, Icons.reorder, Icons.repeat_one, Icons.repeat, Icons.replay_10, Icons.replay_30, Icons.replay_5, Icons.replay, | |
Icons.reply_all, Icons.reply, Icons.report_off, Icons.report_problem, Icons.report, Icons.restaurant_menu, Icons.restaurant, Icons.restore_from_trash, Icons.restore_page, Icons.restore, Icons.search, | |
Icons.security, Icons.select_all, Icons.send, Icons.sentiment_dissatisfied, Icons.sentiment_neutral, Icons.sentiment_satisfied, Icons.sentiment_very_dissatisfied, Icons.sentiment_very_satisfied, Icons.settings_applications, Icons.settings_backup_restore, Icons.settings_bluetooth, | |
Icons.settings_brightness, Icons.settings_cell, Icons.settings_ethernet, Icons.settings_input_antenna, Icons.settings_input_component, Icons.settings_input_composite, Icons.settings_input_hdmi, Icons.settings_input_svideo, Icons.settings_overscan, Icons.settings_phone, Icons.settings_power, | |
Icons.settings_remote, Icons.settings_system_daydream, Icons.settings_voice, Icons.settings, Icons.terrain, Icons.text_fields, Icons.text_format, Icons.text_rotate_up, Icons.text_rotate_vertical, Icons.text_rotation_angledown, Icons.text_rotation_angleup, Icons.battery_charging_full, | |
Icons.text_rotation_down, Icons.text_rotation_none, Icons.textsms, Icons.texture, Icons.verified_user, Icons.vertical_align_bottom, Icons.vertical_align_center, Icons.vertical_align_top, Icons.web_asset, Icons.web, Icons.weekend, | |
Icons.nfc, Icons.offline_bolt, Icons.offline_pin, Icons.change_history, Icons.chat_bubble_outline, Icons.chat_bubble, Icons.chat, Icons.check_box_outline_blank, Icons.check_box, Icons.check_circle_outline, Icons.check_circle, | |
]; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note as PopupMenuItem gets misplaced in ReorderableListView.