43

更新(2021/05/11):

Flutter 现在原生具有 Hover Events 实现的小部件。

有一个 MouseCursor 用于像 RaisedButton 这样的小部件和像 hoverColor 或 hoverElevation 这样的属性。

https://api.flutter.dev/flutter/rendering/MouseCursor-class.html

如已接受的答案中所述,您还可以在其他任何地方使用 InkWell。


原始问题:

如何在 Flutter 中更改光标外观?我知道使用Listener()小部件,我们可以侦听鼠标事件,但我还没有找到任何有关颤动 web 悬停事件的信息。有人找到解决方案了吗?

4

9 回答 9

76

我很难找到关于现在内置支持的文档。这对我有帮助:https ://github.com/flutter/flutter/issues/58260

这对我有用,无需更改 index.html 等。

MouseRegion(
  cursor: SystemMouseCursors.click,
    child: GestureDetector(
      child: Icon(
        Icons.add_comment,
        size: 20,
        ),
      onTap: () {},
    ),
  ),

另见官方文档:https ://api.flutter.dev/flutter/rendering/MouseCursor-class.html

Widget build(BuildContext context) {
  return Center(
    child: MouseRegion(
      cursor: SystemMouseCursors.text,
      child: Container(
        width: 200,
        height: 100,
        decoration: BoxDecoration(
          color: Colors.blue,
          border: Border.all(color: Colors.yellow),
        ),
      ),
    ),
  );
}

在这里https://api.flutter.dev/flutter/material/MaterialStateMouseCursor-class.html官方文档中的另一个精彩示例“......定义了一个鼠标光标,当它的小部件被禁用时解析为 SystemMouseCursors.forbidden。 "

于 2020-06-18T06:28:04.357 回答
20

开发通道构建版本 1.19.0–3.0.pre 开始,内置了对指针光标的支持。使用与下面相同的方法,不同之处在于应用于 Flutter 应用程序容器元素flt-glass-pane。使用波纹管方法只会复制行为。

为了覆盖pointer光标,您可以使用波纹管方法,但应用于flt-glass-pane元素。

解决方法如下:

  1. 您必须设置一个id(例如app-container在应用程序的index.html模板的整个主体上)。

这就是您的index.html的样子:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>My awesome app</title>
</head>
<body id="app-container">
  <script src="main.dart.js" type="application/javascript"></script>
</body>
</html>
  1. 接下来,您必须创建一个包装 dart 类。我称它为hand_cursor.dart
import 'package:flutter_web/gestures.dart';
import 'package:flutter_web/widgets.dart';
import 'package:universal_html/html.dart' as html;
// see https://pub.dev/packages/universal_html

class HandCursor extends MouseRegion {

  // get a reference to the body element that we previously altered 
  static final appContainer = html.window.document.getElementById('app-container');

  HandCursor({Widget child}) : super(
    onHover: (PointerHoverEvent evt) {
      appContainer.style.cursor='pointer';
      // you can use any of these: 
      // 'help', 'wait', 'move', 'crosshair', 'text' or 'pointer'
      // more options/details here: http://www.javascripter.net/faq/stylesc.htm
    },
    onExit: (PointerExitEvent evt) {
      // set cursor's style 'default' to return it to the original state
      appContainer.style.cursor='default';
    },
    child: child
  );

}
  1. 之后,无论您想在何处显示手形光标,都必须将元素包装在此 HandCursor 包装器中。请参阅下面的awesome_button.dart类:
import 'package:awesome_app/widgets/containers/hand_cursor.dart';
import 'package:flutter_web/material.dart';
import 'package:flutter_web/widgets.dart';

class AwesomeButton extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        HandCursor(
          child: IconButton(
            onPressed: () {
              // do some magic
            },
            icon: Icon(Icons.star)
          ),
        )
      ],
    );
  }

}

可以在这里找到一个简短的解释。

可以在此处找到更通用的更新,该更新适用于使用 Flutter 的通道创建的新 Web 项目。

我希望它有所帮助。

于 2019-09-06T21:25:00.547 回答
10

您可以使用具有 onHover 事件的 InkWell

InkWell(
    onTap: () {},
    onHover: (value) {
      setState(() {
        isHovered = value;
      });
    },
    child: Container(
      width: 50,
      height: 72,
      color: Colors.black   
    )
);

确保有一些onTap,即使是一个空函数,否则它被认为是禁用的,并且悬停不起作用

于 2020-11-30T23:49:04.813 回答
9

以前的方法已弃用。这是更新的代码

import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart';
import 'package:universal_html/prefer_sdk/html.dart' as html;

class HandCursor extends MouseRegion {
  static final appContainer = html.window.document.getElementById('app-container');
  HandCursor({Widget child})
      : super(
          onHover: (PointerHoverEvent evt) {
            appContainer.style.cursor = 'pointer';
          },
          onExit: (PointerExitEvent evt) {
            appContainer.style.cursor = 'default';
          },
          child: child,
        );
}

在您的 pubspec.yaml 文件中,将 Universal_html 作为包添加为依赖项。版本可能会改变。

dependencies:
  flutter:
    sdk: flutter
  universal_html: ^1.1.4

您仍然希望将 app-container 的 ID 附加到您的 html 正文。这是我的html文件。

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Your App Title</title>
</head>
<body id="app-container">
  <script src="main.dart.js" type="application/javascript"></script>
</body>
</html>

您想将 HandCursor 小部件的代码放在它自己的文件中。你可以称它为 hand_cursor.dart。要在您希望手显示的小部件上使用它,请将其导入您正在处理的文件中并将所需的小部件包装在 HandCursor 小部件中。

于 2019-11-14T01:15:30.817 回答
7

从 Flutter beta version1.19.0-4.1.pre开始,添加 idbody并设置 cursor 不起作用。因为flt-glass-pane是替换光标。所以解决方案是直接将 cursor 设置为flt-glass-pane.

以下是正在运行的更新。

class HandCursor extends MouseRegion {
    static final appContainer = html.window.document.querySelectorAll('flt-glass-pane')[0];
    HandCursor({Widget child}) : super(
        onHover: (PointerHoverEvent evt) {
            appContainer.style.cursor='pointer';
        },
        onExit: (PointerExitEvent evt) {
            appContainer.style.cursor='default';
        },
        child: child
    );    
}
于 2020-06-19T04:14:37.533 回答
4

我相信鼠标事件不会在网络上运行,Listener Widget 在 Google I/O 2019 上进行了演示并与鼠标一起使用,但那是作为 ChromeOS 应用程序而不是网络应用程序。

根据GitHub 上的 Flutter 网站

此时,桌面 UI 交互还没有完全完成,因此使用 flutter_web 构建的 UI 可能感觉就像是移动应用程序,即使在桌面浏览器上运行也是如此。

于 2019-06-05T16:24:14.930 回答
3
final appContainer 
     = html.document.getElementsByTagName('body')[0] as html.Element;

            GestureDetector(
                        child: MouseRegion(
                          child: Text(
                            'https://github.com/yumi0629',
                            style: textStyle,
                          ),
                          onHover: (_) => appContainer.style.cursor = 'pointer',
                          onExit: (_) => appContainer.style.cursor = 'default',
                        ),
                        onTap: () {
                          print('open');
                          js.context.callMethod(
                              'open', ['https://github.com/yumi0629']);
                        },
                      )
于 2020-03-25T01:59:28.243 回答
2

康斯坦丁·斯坦改编的答案

对于那些想要具有类似于InkWell小部件和边框半径选项的点击效果的人:

添加到您的 pubspec.yaml 文件

dependencies:
  universal_html: ^1.1.4

然后在 index.html 文件中添加如下标签<body id="app-container">

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Your App Title</title>
</head>
<body id="app-container">
  <script src="main.dart.js" type="application/javascript"></script>
</body>
</html>

最后创建以下小部件并使用封装的所有必要小部件:

import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:universal_html/prefer_sdk/html.dart' as html;

class InkWellMouseRegion extends InkWell {
  InkWellMouseRegion({
    Key key,
    @required Widget child,
    @required GestureTapCallback onTap,
    double borderRadius = 0,
  }) : super(
          key: key,
          child: !kIsWeb ? child : HoverAware(child: child),
          onTap: onTap,
          borderRadius: BorderRadius.circular(borderRadius),
        );
}

class HoverAware extends MouseRegion {

  // get a reference to the body element that we previously altered 
  static final appContainer = html.window.document.getElementById('app-container');

  HoverAware({Widget child}) : super(
    onHover: (PointerHoverEvent evt) {
      appContainer.style.cursor='pointer';
      // you can use any of these: 
      // 'help', 'wait', 'move', 'crosshair', 'text' or 'pointer'
      // more options/details here: http://www.javascripter.net/faq/stylesc.htm
    },
    onExit: (PointerExitEvent evt) {
      // set cursor's style 'default' to return it to the original state
      appContainer.style.cursor='default';
    },
    child: child
  );

}
于 2019-12-18T19:26:02.210 回答
0

我所知道的最简单的方法

InkWell(
        onTap: (){},
        mouseCursor: MaterialStateMouseCursor.clickable,
        ...
于 2022-01-14T12:36:09.190 回答