You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中为按钮实现InkWell悬停交互,解决仅支持鼠标的问题

实现跨设备的Flutter按钮悬停交互

原FFButtonWidget的内置hover配置仅对鼠标指针生效,要实现跨设备(含触摸设备)的悬停交互,可通过InkWell结合状态管理完成,以下是具体方案:

核心逻辑

  • 用StatefulWidget维护按钮的悬停状态
  • 通过InkWell的onHover监听鼠标悬停,同时用onTapDown/onTapUp/onPointerCancel模拟触摸设备的"悬停"效果
  • 根据悬停状态动态切换按钮的背景色与文字颜色

修改后的完整代码

Align(
  alignment: AlignmentDirectional(0.0, -1.0),
  child: Padding(
    padding: EdgeInsets.all(24.0),
    child: SingleChildScrollView(
      child: Column(
        mainAxisSize: MainAxisSize.max,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Padding(
            padding: EdgeInsets.all(20.0),
            child: _HoverableButton(
              onPressed: () async {
                context.pushNamed('Books_Curriculum');
              },
              text: 'Curriculum',
            ),
          ),
        ],
      ),
    ),
  ),
)

// 自定义悬停按钮组件
class _HoverableButton extends StatefulWidget {
  final VoidCallback onPressed;
  final String text;

  const _HoverableButton({
    required this.onPressed,
    required this.text,
  });

  @override
  State<_HoverableButton> createState() => _HoverableButtonState();
}

class _HoverableButtonState extends State<_HoverableButton> {
  bool _isHovered = false;

  @override
  Widget build(BuildContext context) {
    return InkWell(
      // 鼠标悬停状态监听
      onHover: (isHovering) {
        setState(() {
          _isHovered = isHovering;
        });
      },
      // 触摸设备按下时触发悬停状态
      onTapDown: (_) {
        setState(() {
          _isHovered = true;
        });
      },
      // 触摸抬起或取消时恢复原状态并执行点击逻辑
      onTapUp: (_) {
        setState(() {
          _isHovered = false;
        });
        widget.onPressed();
      },
      onPointerCancel: (_) {
        setState(() {
          _isHovered = false;
        });
      },
      borderRadius: BorderRadius.circular(12.0),
      child: FFButtonWidget(
        onPressed: () {}, // 点击逻辑交由InkWell处理
        text: widget.text,
        options: FFButtonOptions(
          width: () {
            if (MediaQuery.sizeOf(context).width < kBreakpointSmall) {
              return 300;
            } else if (MediaQuery.sizeOf(context).width < kBreakpointMedium) {
              return 600;
            } else if (MediaQuery.sizeOf(context).width < kBreakpointLarge) {
              return 700;
            } else {
              return 900;
            }
          }().toDouble(),
          height: () {
            if (MediaQuery.sizeOf(context).width < kBreakpointSmall) {
              return 40;
            } else if (MediaQuery.sizeOf(context).width < kBreakpointMedium) {
              return 50;
            } else if (MediaQuery.sizeOf(context).width < kBreakpointLarge) {
              return 60;
            } else {
              return 70;
            }
          }().toDouble(),
          padding: EdgeInsets.all(0.0),
          iconPadding: EdgeInsetsDirectional.fromSTEB(0.0, 0.0, 0.0, 0.0),
          // 动态切换背景色
          color: _isHovered ? Colors.black : Color(0xFFEFDB06),
          textStyle: TextStyle(
            // 动态切换文字颜色
            color: _isHovered ? Color(0xFFFCEC02) : Colors.black,
            fontWeight: FontWeight.w500,
            fontSize: () {
              if (MediaQuery.sizeOf(context).width < kBreakpointSmall) {
                return 20;
              } else if (MediaQuery.sizeOf(context).width < kBreakpointMedium) {
                return 24;
              } else if (MediaQuery.sizeOf(context).width < kBreakpointLarge) {
                return 28;
              } else {
                return 32;
              }
            }().toDouble(),
          ),
          elevation: 3.0,
          borderSide: BorderSide(
            color: Colors.transparent,
            width: 1.0,
          ),
          borderRadius: BorderRadius.circular(12.0),
          // 禁用内置hover配置,避免冲突
          hoverColor: null,
          hoverTextColor: null,
        ),
      ),
    );
  }
}

关键说明

  • 自定义_HoverableButton组件封装了跨设备悬停逻辑,方便后续复用
  • 鼠标设备通过原生onHover监听状态,触摸设备通过触摸事件模拟悬停效果
  • 动态修改按钮的color和文字颜色,实现黄底黑字→黑底黄字的切换
  • 禁用FFButtonWidget内置的hover配置,防止与自定义逻辑冲突

内容的提问来源于stack exchange,提问作者Ajoy Lawrence

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 05:35:11