Skip to content

Instantly share code, notes, and snippets.

@AlexV525
Created March 5, 2024 02:57
Show Gist options
  • Save AlexV525/c1788ba97f3445f53ef232164a063335 to your computer and use it in GitHub Desktop.
Save AlexV525/c1788ba97f3445f53ef232164a063335 to your computer and use it in GitHub Desktop.
Followed custom menu
// [Author] Alex (https://github.com/AlexV525)
// [Date] 2024/03/15 10:57
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Press to head over the list page.'),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const _ListPage()),
);
},
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
class _ListPage extends StatefulWidget {
const _ListPage();
@override
State<_ListPage> createState() => _ListPageState();
}
class _ListPageState extends State<_ListPage> {
final manager = _ItemDeleteMenuManager();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text('List page'),
),
body: ListView.separated(
itemCount: 50,
itemBuilder: (context, index) {
final link = LayerLink();
return CompositedTransformTarget(
link: link,
child: TextButton(
onPressed: () => print(index),
onLongPress: () {
manager.show(
context: context,
item: index,
link: link,
onItemRemoved: () {
print('Removed');
},
);
},
child: Text('$index'),
),
);
},
separatorBuilder: (_, __) => const Divider(),
),
);
}
}
class _ItemDeleteMenuManager {
_ItemDeleteMenuManager();
final _itemEntries = <Object, OverlayEntry>{};
OverlayState _getState(BuildContext context) {
return Overlay.of(context, rootOverlay: true);
}
void show({
required BuildContext context,
required Object item,
required LayerLink link,
required void Function() onItemRemoved,
VoidCallback? onCancel,
}) {
dismiss(context: context, item: item);
final entry = OverlayEntry(
builder: (context) => Stack(
children: [
Positioned.fill(
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTapDown: (_) {
dismiss(context: context, item: item);
},
),
),
CompositedTransformFollower(
link: link,
targetAnchor: Alignment.topCenter,
followerAnchor: Alignment.bottomCenter,
child: ColoredBox(
color: Theme.of(context).colorScheme.inversePrimary,
child: Row(
mainAxisSize: MainAxisSize.min,
children: AdaptiveTextSelectionToolbar.getAdaptiveButtons(
context,
[
ContextMenuButtonItem(
onPressed: () {
dismiss(context: context, item: item);
},
label: '删除',
),
],
).toList(),
),
),
),
],
),
);
_getState(context).insert(entry);
_itemEntries[item] = entry;
}
void dismiss({required BuildContext context, required Object item}) {
_itemEntries[item]?.remove();
_itemEntries.remove(item);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment