neumorphic_flutter_kr
요약
간단한 UI의 대표 중 하나인 뉴로모픽 디자인을 한글 API로 쉽게 쓰는 Flutter 위젯/샘플입니다. 조정하시고, 코드를 긁어가시고, 인사이트도 얻어가세요!
뱃지란? README 상단에 표시되는 작은 상태 라벨로, 라이선스/버전/지원 플랫폼 등을 한눈에 보여줍니다. 위 배지는 라이선스(MIT), 요구 Flutter/Dart 버전, 지원 플랫폼 정보를 담고 있어요.
특징
- 한글 친화·직관 API: depth(깊이), lightSource(광원), radius(곡률), color(배경색)
- 최소 설정으로 자연스러운 양·음영 박스 효과(눌림/돌출)
- 경량 의존성, 웹/모바일/데스크톱 모두 지원
- 예제 앱에서 실시간 조정 + 코드 자동 생성/복사 제공
- 다크모드 토글·텍스트 스케일(접근성) 조절 지원
설치
pub.flutter-io.cn 등록 전에는 로컬 path 의존성으로 사용하세요.
dependencies:
neumorphic_flutter_kr:
path: ../neumorphic_flutter_kr
빠른 시작
import 'package:flutter/material.dart';
import 'package:neumorphic_flutter_kr/neumorphic_flutter_kr.dart';
class Demo extends StatelessWidget {
const Demo({super.key});
@override
Widget build(BuildContext context) {
return const Center(
child: NeumorphicBox(
padding: EdgeInsets.all(24),
child: Text('눌러보세요'),
),
);
}
}
복붙용: 단일 파일 데모(자급자족)
아래 코드는 새 Flutter 앱의 lib/main.dart에 그대로 붙여 넣어도 동작합니다. 추가 파일이 필요 없습니다.
import 'package:flutter/material.dart';
import 'package:neumorphic_flutter_kr/neumorphic_flutter_kr.dart';
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
ThemeMode _mode = ThemeMode.light;
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Neumorphic Lite Demo',
theme: ThemeData(useMaterial3: true, brightness: Brightness.light),
darkTheme: ThemeData(useMaterial3: true, brightness: Brightness.dark),
themeMode: _mode,
home: DemoPage(
themeMode: _mode,
onThemeModeChanged: (m) => setState(() => _mode = m),
),
);
}
}
class DemoPage extends StatefulWidget {
final ThemeMode themeMode;
final ValueChanged<ThemeMode> onThemeModeChanged;
const DemoPage({super.key, required this.themeMode, required this.onThemeModeChanged});
@override
State<DemoPage> createState() => _DemoPageState();
}
class _DemoPageState extends State<DemoPage> {
double _depth = 8;
double _radius = 12;
bool _pressed = false;
Color _bg = NeumorphicTheme.defaultBackground;
Alignment _light = NeumorphicTheme.defaultLightSource;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Neumorphic Lite'),
actions: [
const Icon(Icons.dark_mode, size: 18),
Switch(
value: widget.themeMode == ThemeMode.dark,
onChanged: (v) => widget.onThemeModeChanged(v ? ThemeMode.dark : ThemeMode.light),
),
],
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Preview
Expanded(
child: Center(
child: GestureDetector(
onTapDown: (_) => setState(() => _pressed = true),
onTapUp: (_) => setState(() => _pressed = false),
onTapCancel: () => setState(() => _pressed = false),
child: NeumorphicBox(
depth: _pressed ? -_depth.abs() : _depth,
radius: BorderRadius.all(Radius.circular(_radius)),
color: _bg,
lightSource: _light,
padding: const EdgeInsets.all(40),
child: Icon(_pressed ? Icons.touch_app : Icons.pan_tool, size: 60, color: Colors.blueGrey[700]),
),
),
),
),
const SizedBox(height: 16),
// Controls
Text('깊이(depth): ${_pressed ? -_depth.abs() : _depth}'),
Slider(
value: _depth,
min: -20,
max: 20,
divisions: 40,
label: _depth.round().toString(),
onChanged: (v) => setState(() => _depth = v),
),
Text('곡률(radius): ${_radius.round()}px'),
Slider(
value: _radius,
min: 0,
max: 40,
divisions: 40,
label: _radius.round().toString(),
onChanged: (v) => setState(() => _radius = v),
),
Row(
children: [
const Text('광원: '),
DropdownButton<Alignment>(
value: _light,
items: const [
DropdownMenuItem(value: Alignment.topLeft, child: Text('좌상')),
DropdownMenuItem(value: Alignment.topCenter, child: Text('상단')),
DropdownMenuItem(value: Alignment.topRight, child: Text('우상')),
DropdownMenuItem(value: Alignment.centerLeft, child: Text('좌측')),
DropdownMenuItem(value: Alignment.center, child: Text('중앙')),
DropdownMenuItem(value: Alignment.centerRight, child: Text('우측')),
DropdownMenuItem(value: Alignment.bottomLeft, child: Text('좌하')),
DropdownMenuItem(value: Alignment.bottomCenter, child: Text('하단')),
DropdownMenuItem(value: Alignment.bottomRight, child: Text('우하')),
],
onChanged: (a) => setState(() => _light = a ?? _light),
),
const SizedBox(width: 12),
ElevatedButton(
onPressed: () => setState(() => _bg = _bg == NeumorphicTheme.defaultBackground
? const Color(0xFFE3F2FD)
: NeumorphicTheme.defaultBackground),
child: const Text('배경색 토글'),
),
],
),
],
),
),
backgroundColor: _bg,
);
}
}
주의: 위 “단일 파일 데모”는 빠른 복붙용 간이 버전입니다. 전체 기능(코드 생성/샘플 갤러리 등)이 있는 풀 인터랙티브 데모는 이 저장소의 example/에서 실행하세요.
인터랙티브 데모 실행
실시간으로 깊이/곡률/광원/배경색을 조정하고, 생성된 코드를 복사할 수 있습니다.
cd example
flutter run -d chrome # 웹(크롬)
# 또는
flutter run -d ios # iOS 시뮬레이터
flutter run -d android # Android 에뮬레이터
시각 샘플(골든 테스트 이미지)
돌출(emboss)

눌림(pressed)

링크
- 지원 버전 안내: SUPPORT.md
- 변경 로그: CHANGELOG.md