gpt4 book ai didi

flutter - 将小部件放置在边界框之外

转载 作者:行者123 更新时间:2023-12-02 01:41:23 25 4
gpt4 key购买 nike

我的应用程序显示各种 Container() Widget()位于某个 View 中的多个列中。

我尝试在 Container() 中放置一些图标提供删除、最小化等操作。不幸的是,这在 native 目标上看起来不太好。

因此,我想保持视觉外观不变,并在实际 Container() 上方显示操作菜单 一旦鼠标指针移到 Container() 上.

此菜单将位于所有其他小部件之上,是非模式的,一旦指针离开 Container() 的边界框,该菜单就会消失。 。 Containers()不应更改大小和位置。

使用MouseRegion() ,我会让菜单出现和消失。

我可以放一些Widget()Container() 的边界矩形之外[或其他小部件)?理想情况下,我想将其相对于另一个边界框放置。

更新 2022-03-24

创建了一个 OverlayMenu() 类,它呈现如下内容:

enter image description here

用法:

OverlayMenu(
actionWidget:
const Icon(Icons.settings, color: Colors.blue, size: 20),
callbacks: [
() {
// Click on icons 1 action
},
() {
// Click on icon 2 action
}
],
icons: [
Icons.delete, Icons.tv
],
leftOffset: StoreProvider.of<EModel>(context)
.state
.columnWidth
.toDouble())

以及OverlayMenu()的实现:

导入'package:flutter/material.dart';

class OverlayMenu {

List<IconData> icons;
List<Function> callbacks;
Widget actionWidget;

double leftOffset = 0.0;
bool mayShowMenu = true;

OverlayMenu({ required this.actionWidget, required this.icons, required this.callbacks, required this.leftOffset });

Widget insert( BuildContext context ) {

return MouseRegion(
onEnter: (_) {
if (mayShowMenu) {
_showOverlay( context );
}
},
onExit: (_) {
mayShowMenu = true;
},
child: const Icon(Icons.settings, color: Colors.blue, size: 20),
);

}


///
///
///
void _showOverlay(BuildContext outerContext ) async {
final renderBox = outerContext.findRenderObject() as RenderBox;
var size = renderBox.size;
var offset = renderBox.localToGlobal(Offset.zero);

assert( icons.length == callbacks.length, 'Need to provide as many icons as callbacks' );

List<Widget> actionElements = List.empty( growable: true );

for( var n=0; n<icons.length; n++ ) {

actionElements.add( GestureDetector(
onTap: () {
callbacks[ n ]();
},
child: Icon( icons[ n ], size: 22 ))
);

}

// Declaring and Initializing OverlayState
// and OverlayEntry objects
OverlayState? overlayState = Overlay.of(outerContext);
OverlayEntry? overlayEntry;
overlayEntry = OverlayEntry(builder: (context) {
// You can return any widget you like here
// to be displayed on the Overlay
return Stack(children: [
Positioned(
top: offset.dy,
left: offset.dx +
leftOffset -
40,
child: MouseRegion(
onExit: (_) {
overlayEntry?.remove();
print(DateTime.now().toString() + ' ovl: removed');
},
cursor: SystemMouseCursors.contextMenu,
child: Material(
child:Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
border: Border.all(
color: Colors.grey.shade300,
width: 1,
),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
spreadRadius: 4,
blurRadius: 4,
offset: const Offset( 4,4 ),
blurStyle: BlurStyle.normal),
]
),
child: SizedBox(
width: 60,
height: 60,
child: Wrap(spacing: 4, children: actionElements
))))),
),
]);
});

// Inserting the OverlayEntry into the Overlay
overlayState?.insert(overlayEntry);
mayShowMenu = true;

print(DateTime.now().toString() + ' ovl: inserted');

}

}

最佳答案

您可以用来实现您想要的目标的一种方法是 Overlay小部件,因为它是非模式的,也不需要更改布局/大小来命中可测试的项目。

根据你的问题,我认为这个流程就是想要的:

animated image showing sample

指针进入小部件后插入覆盖条目,并在指针离开后将其删除

  @override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Stack(
children: [
MouseRegion(
onEnter: (_) {
Overlay.of(context)!.insert(this._overlayEntry);
},
onExit: (_) => clear(),
child: FloatingActionButton(
key: buttonKey,
onPressed: () {},
),
),
],
),
),
);
}

这就是我们删除条目的方式,检查是否可以删除以及延迟(用于平滑):

  Future<void> clear() async {
if (!keepMenuVisible) {
await Future.delayed(Duration(milliseconds: 200));
if (!keepMenuVisible) {
_overlayEntry.remove();
}
}
}

额外的延迟是为了确保菜单不会 react 性地绝望,而是让它变得更加平滑。

keepMenuVisible 用于锁定菜单并在菜单本身悬停时保持其可见。

最后,我们创建条目并将项目相对于主小部件(在本例中为 FAB)放置:

  @override
void initState() {
super.initState();
WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
_overlayEntry = _createOverlayEntry();
});
}

OverlayEntry _createOverlayEntry() {
final renderBox = buttonKey.currentContext!.findRenderObject() as RenderBox;
var size = renderBox.size;
var offset = renderBox.localToGlobal(Offset.zero);

return OverlayEntry(
builder: (_) => Positioned(
left: offset.dx,
top: offset.dy + size.height + 5.0,
width: 200,
child: MouseRegion(
onEnter: (_) {
keepMenuVisible = true;
},
onHover: (_) {
keepMenuVisible = true;
},
onExit: (_) async {
keepMenuVisible = false;
clear();
},
child: Material(
elevation: 4.0,
child: ListView(
padding: EdgeInsets.zero,
shrinkWrap: true,
children: <Widget>[
ListTile(
onTap: () => print('tap action 1'),
title: Text('Action 1'),
),
ListTile(
onTap: () => print('tap action 2'),
title: Text('Action 2'),
)
],
),
),
),
),
);
}

查看完整示例 here

关于flutter - 将小部件放置在边界框之外,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71550736/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com