Neumorphism は、背景と同系色の面に明るい影と暗い影を重ね、浮き上がりを表す見せ方です。この例では、タップごとに _isElevated を切り替え、AnimatedContainer で影の状態を遷移させます。
使い方
空の Flutter アプリの lib/main.dart を次の内容に置き換え、flutter run で起動します。追加パッケージは使いません。
import 'package:flutter/material.dart';
void main() => runApp(const MaterialApp(home: NeumorphismButton()));
class NeumorphismButton extends StatefulWidget {
const NeumorphismButton({super.key});
@override
State<NeumorphismButton> createState() => _NeumorphismButtonState();
}
class _NeumorphismButtonState extends State<NeumorphismButton> {
bool _isElevated = true;
@override
Widget build(BuildContext context) {
final background = Colors.grey[300]!;
return Scaffold(
backgroundColor: background,
body: Center(
child: Semantics(
button: true,
label: _isElevated ? '押し込む' : '浮かせる',
child: GestureDetector(
onTap: () => setState(() => _isElevated = !_isElevated),
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
height: 200,
width: 200,
decoration: BoxDecoration(
color: background,
borderRadius: BorderRadius.circular(50),
boxShadow: _isElevated
? [
BoxShadow(
color: Colors.grey[500]!,
offset: const Offset(4, 4),
blurRadius: 15,
spreadRadius: 1,
),
const BoxShadow(
color: Colors.white,
offset: Offset(-4, -4),
blurRadius: 15,
spreadRadius: 1,
),
]
: const [],
),
),
),
),
),
);
}
}
影と状態変更の仕組み
GestureDetector の onTap は、タップが成立したときに _isElevated を反転します。true のときは右下へずらした灰色の影と、左上へずらした白い影を重ねるため、角丸の四角形が背景から浮いて見える構成です。
AnimatedContainer は、指定した duration と curve を使って、変更されたプロパティの前後の値を自動的に補間します。ここでは boxShadow を空のリストへ切り替えることで、浮いた状態から影のないフラットな状態へ移します。null のプロパティはアニメーションされないため、元の boxShadow: null では影が消える遷移を補間できません。このコードだけでは、内側の影を使った凹み表現は描画しません。
Semantics は、見た目だけの角丸の四角形に現在の操作を説明するラベルを付けています。キーボード操作が必要な用途では、GestureDetector だけで完結させず、用途に応じて Material の ButtonStyleButton 系ウィジェットなども検討してください。
実行結果
2026-09-06 に、この記事と同じ main.dart を Flutter 3.44.6 / Dart 3.12.2 で Web Server に起動し、HeadlessChrome 152.0.0.0、480 × 360 の viewport で確認しました。初期表示では、中央の 200 × 200・半径 50 の角丸四角形に左上の白い影と右下の灰色の影があり、背景から浮いて見えました。

初期状態。影で浮いて見える。
中央(240, 180)をクリックすると、影がなくなり、角丸四角形は背景と同じ灰色に溶け込むフラットな状態になりました。

クリック後。影が消え、背景と同化する。
もう一度クリックすると、初期の影がある表示へ戻ることも確認しました。ブラウザコンソールにはエラーがなく、Dart Dev Compiler の起動情報だけが出力されました。
影を完全になくすとボタンの輪郭も背景に溶けるため、操作できることが伝わりにくくなります。重要な操作に使うなら、常時見える境界線やラベルを残す、または影を弱めるなど、状態にかかわらず操作対象を見つけられる工夫が必要です。