Flutter:更新附加到 MouseRegion 的 OverlayEntry 的 LayerLink

问题描述 投票:0回答:0

我有一个 ListView.builder,其中包含包含在 MouseRegion 中的 ListTiles。当使用鼠标进入 MouseRegion 时,附加到此 MouseRegion 的 Overlay 应显示在此 MouseRegion 的右上角。只能同时显示一个 Overlay,并且始终是附加到悬停的 MouseRegion 的那个。由于 Overlay 包含可点击的 IconButtons,因此当通过 Overlay 退出 MouseRegion 时,Overlay 仍应显示。

如果每个 ListEntry 使用两个计时器都有自己的 Overlay,我找到了解决方案。

链接到我之前的问题

但后来我遇到了如何在移动设备上处理它的问题。在此处点击 ListTile,将显示此 ListTile 的叠加层,并且另一个 ListTile 的叠加层可能会消失。我用我的方法没有找到最后一个任务的解决方案。

然后我只用一个(全局)覆盖进行了尝试,这对我来说似乎很合乎逻辑,因为同时只显示一个覆盖,那么移动设备的解决方案就很容易了。但是:适用于 web 的代码并非 100% 有效。当您使用鼠标非常快时,覆盖层不会消失。

正如您在以下最小版本中看到的,我正在使用回调更新 CompositedTransformFollower 的 layerLink。我也尝试使用提供者来执行此操作,但后来我总是遇到错误:无法在此 ListWidget 小部件上方找到正确的提供者。

感谢您的帮助:-)

import 'dart:async';
import 'package:flutter/material.dart';

void main() {
 runApp(const MyApp());
}

class MyApp extends StatelessWidget {
 const MyApp({Key? key}) : super(key: key);

 @override
 Widget build(BuildContext context) {
   return const MaterialApp(
     home: MyHomePage(),
   );
 }
}

class MyHomePage extends StatefulWidget {
 const MyHomePage({Key? key}) : super(key: key);

 @override
 State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
 LayerLink? layerLinkHovering;
 LayerLink? layerLinkShowing;
 OverlayEntry? entry;
 Timer? showTimer;
 Timer? hideTimer;
 bool overlayIsActive = false;
 OverlayState? overlay;

 OverlayEntry buildOverlayEntry() {
   print('buildOverlayEntry');
   return OverlayEntry(
     builder: (context) => Positioned(
       right: 1,
       child: CompositedTransformFollower(
         link: layerLinkShowing!,
         showWhenUnlinked: false,
         offset: const Offset(0, -20),
         followerAnchor: Alignment.topRight,
         targetAnchor: Alignment.topRight,
         child: buildOverlay(),
       ),
     ),
   );
 }

 void showOverlay() {
   print('showOverlay');
   overlay = Overlay.of(context);
   entry = buildOverlayEntry();
   overlay!.insert(entry!);
   overlayIsActive = true;
   layerLinkShowing = layerLinkHovering;
 }

 void hideOverlay() {
   print('hideOverlay');
   entry?.remove();
   entry = null;
   overlayIsActive = false;
 }

 void enterListTile(LayerLink l) {
   print('enterListTile');
   layerLinkHovering = l;
   if (!overlayIsActive) {
     showTimer = Timer(const Duration(milliseconds: 100), showOverlay);
   } else if (layerLinkHovering == layerLinkShowing) {
     hideTimer!.cancel();
   } else {
     showTimer = Timer(const Duration(milliseconds: 100), showOverlay);
   }
 }

 void exitListTile() {
   print('exitListTile');
   hideTimer = Timer(const Duration(milliseconds: 100), hideOverlay);
 }

 Widget? buildOverlay() {
   print('build Overlay');
   return MouseRegion(
     onEnter: (e) {
       print('onEnterOverlay');
       hideTimer?.cancel();
     },
     onExit: (e) {
       print('onExitOverlay');
       hideTimer = Timer(const Duration(milliseconds: 100), hideOverlay);
     },
     child: Material(
       child: Row(
         children: [
           IconButton(
             icon: const Icon(Icons.delete),
             onPressed: () {},
             tooltip: 'delete message',
           ),
           IconButton(
             icon: const Icon(Icons.edit),
             onPressed: () {},
             tooltip: 'edit message (in progress)',
           ),
           IconButton(
             icon: const Icon(Icons.chat_bubble_rounded),
             onPressed: () {},
             tooltip: 'start thread (in progress)',
           ),
           IconButton(icon: const Icon(Icons.emoji_emotions), onPressed: () {}, tooltip: 'in progress'),
         ],
       ),
     ),
   );
 }

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       title: const Text('MinimalListTile'),
     ),
     body: ListView.builder(
       scrollDirection: Axis.vertical,
       shrinkWrap: true,
       itemCount: 20,
       itemBuilder: (BuildContext context, int index) {
         LayerLink layerLink = LayerLink();
         return CompositedTransformTarget(
           link: layerLink,
           child: MouseRegion(
             onEnter: (e) {
               print('onEnter');
               enterListTile(layerLink);
             },
             onExit: (e) {
               print('onExit');
               exitListTile();
             },
             child: ListTile(
               leading: const Icon(Icons.list),
               title: Text("List item $index"),
               onTap: () {
                 // TODO: implement for Mobile-Platform (easy)
               },
             ),
           ),
         );
       },
     ),
   );
 }
}
flutter timer overlay
© www.soinside.com 2019 - 2024. All rights reserved.