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

Flutter 如何实现点击切换凸起/凹陷状态的新拟态按钮设计

实现新拟态按钮点击切换凸起/凹陷效果的方案

核心问题原因

Flutter 原生的BoxShadow仅支持外阴影,没有内置内阴影属性,这是无法直接实现凹陷效果的根本原因。

实现方案

这里提供两种常用实现方式,第一种借助第三方包快速实现,第二种为无第三方依赖的手动实现方案:

方案1:借助inner_shadow第三方包快速实现

  1. 首先在pubspec.yaml中添加依赖:
dependencies:
  flutter:
    sdk: flutter
  inner_shadow: ^1.0.0 # 可替换为当前最新版本
  1. 完整实现代码如下:
import 'package:flutter/material.dart';
import 'package:inner_shadow/inner_shadow.dart';

class NeumorphismButton extends StatefulWidget {
  const NeumorphismButton({super.key});

  @override
  State<NeumorphismButton> createState() => _NeumorphismButtonState();
}

class _NeumorphismButtonState extends State<NeumorphismButton> {
  final double _offset = 4.0;
  bool _isPressed = false;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: GestureDetector(
        // 处理按压状态切换
        onTapDown: (_) => setState(() => _isPressed = true),
        onTapUp: (_) => setState(() => _isPressed = false),
        onTapCancel: () => setState(() => _isPressed = false),
        onTap: () {
          // 这里添加按钮点击后的业务逻辑
        },
        // 根据按压状态返回不同样式
        child: _isPressed 
        // 凹陷状态:内阴影
        ? InnerShadow(
            shadows: [
              BoxShadow(
                color: Colors.grey.shade500,
                offset: Offset(_offset, _offset),
                blurRadius: 8.0,
              ),
              BoxShadow(
                color: Colors.grey.shade100,
                offset: Offset(_offset * -1, _offset * -1),
                blurRadius: 8.0,
              ),
            ],
            child: Container(
              height: 300.0,
              width: 300.0,
              decoration: BoxDecoration(
                color: Colors.grey.shade300,
                borderRadius: BorderRadius.circular(50.0),
              ),
            ),
          )
        // 凸起状态:原有的外阴影
        : Container(
            height: 300.0,
            width: 300.0,
            decoration: BoxDecoration(
              color: Colors.grey.shade300,
              borderRadius: BorderRadius.circular(50.0),
              boxShadow: <BoxShadow>[
                BoxShadow(
                  color: Colors.grey.shade100,
                  offset: Offset(_offset * -1, _offset * -1),
                  blurRadius: 8.0,
                ),
                BoxShadow(
                  color: Colors.grey.shade500,
                  offset: Offset(_offset, _offset),
                  blurRadius: 8.0,
                ),
              ],
            ),
          ),
      ),
    );
  }
}

方案2:无第三方依赖手动实现

如果不想引入额外包,可以用渐变层模拟内阴影效果,核心逻辑是在凹陷状态下叠加渐变,分别模拟左上暗边和右下亮边:

// 凹陷状态的Container替换为以下代码
Container(
  height: 300.0,
  width: 300.0,
  decoration: BoxDecoration(
    color: Colors.grey.shade300,
    borderRadius: BorderRadius.circular(50.0),
    gradient: LinearGradient(
      begin: Alignment.topLeft,
      end: Alignment.bottomRight,
      colors: [
        Colors.grey.shade400,
        Colors.grey.shade300,
        Colors.grey.shade200,
      ],
      stops: const [0.1, 0.3, 1],
    ),
  ),
)

该方案的还原度略低于第三方包,但不需要引入额外依赖,适合简单场景使用。

状态切换逻辑说明

  • 用_isPressed布尔变量存储按钮当前状态
  • 通过GestureDetector的onTapDown、onTapUp、onTapCancel三个回调监听用户按压动作,实时更新状态触发UI重绘
  • 可以根据需求调整_offset、阴影blurRadius、颜色深浅等参数,匹配设计稿效果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 16:36:03