rainbow_edge_lighting 1.0.0
rainbow_edge_lighting: ^1.0.0 copied to clipboard
Animated rainbow edge lighting painter for Flutter widgets with smooth fade and disabled border blending.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:rainbow_edge_lighting/rainbow_edge_lighting.dart';
void main() => runApp(const DemoApp());
class DemoApp extends StatelessWidget {
const DemoApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: LightingDemoPage(),
);
}
}
/// ---- 유틸: 색상 루프를 자연스럽게 닫고(HSL로 생성) 부드러운 연결을 만든다 ----
/// HSL로 n개의 색을 생성(루프형). [sat], [light]로 채도/밝기 조절
List<Color> hslSweep({
int count = 10,
double sat = 0.8,
double light = 0.55,
}) {
assert(count >= 2);
final list = <Color>[];
for (int i = 0; i < count; i++) {
final h = i / count; // 0..1
final c = HSLColor.fromAHSL(1, h * 360, sat, light).toColor();
list.add(c);
}
return smoothLoop(list);
}
class LightingDemoPage extends StatefulWidget {
const LightingDemoPage({super.key});
@override
State<LightingDemoPage> createState() => _LightingDemoPageState();
}
class _LightingDemoPageState extends State<LightingDemoPage> {
bool _enabled = true;
@override
Widget build(BuildContext context) {
final w = MediaQuery.of(context).size.width;
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
backgroundColor: Colors.black,
title: const Text("Rainbow Edge Lighting Demo"),
),
body: ListView(
padding: const EdgeInsets.all(20),
children: [
// 1) 기본 레인보우(자연스러운 루프) — HSL 12색 + 루프 닫기
_title("1. 기본 무지개 (부드러운 루프)"),
RainbowEdgeLighting(
radius: 34,
thickness: 3,
speed: 0.3,
enabled: true,
colors: hslSweep(count: 12, sat: 0.9, light: 0.55),
clip: true,
// 모서리 깔끔하게
child: Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(24),
),
child: const Text("Rainbow Edge!",
style: TextStyle(color: Colors.white)),
),
),
const SizedBox(height: 36),
// 2) 네온 블루(양 끝 색 동일) — seam 제거
_title("2. 네온 블루 (이음선 제거)"),
RainbowEdgeLighting(
radius: 16,
thickness: 4,
speed: 1,
colors: smoothLoop(const [
Color(0xFFB3E5FC), // 연한 스카이블루
Color(0xFF81D4FA), // 하늘색
Color(0xFF4FC3F7), // 밝은 파랑
Color(0xFF29B6F6), // 시원한 블루
Color(0xFF26C6DA), // 아쿠아 블루
Color(0xFF29B6F6), // 시원한 블루
Color(0xFF4FC3F7), // 밝은 파랑
Color(0xFF81D4FA),
]),
clip: true,
child: Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(16),
),
child: const Icon(Icons.ac_unit, size: 48, color: Colors.white),
),
),
const SizedBox(height: 36),
// 3) 불타는 원형 링 — 완전 원형이면 radius를 절반 이상으로 + clip
_title("3. 불타는 Fire Ring (원형)"),
Center(
child: RainbowEdgeLighting(
radius: 100,
// 충분히 크게(원형 클리핑에 영향 X, painter만 둥글게)
thickness: 6,
speed: 0.8,
colors:
smoothLoop(const [Colors.red, Colors.orange, Colors.yellow]),
clip: true,
child: Container(
width: 140,
height: 140,
decoration: const BoxDecoration(
color: Colors.black,
shape: BoxShape.circle, // 내부도 완전 원
),
alignment: Alignment.center,
child: const Icon(Icons.local_fire_department,
size: 60, color: Colors.white),
),
),
),
const SizedBox(height: 36),
// 4) 은은한 파스텔 — 완만한 속도, 채도/밝기 낮춤
_title("4. 은은한 파스텔 (느리게)"),
RainbowEdgeLighting(
radius: 30,
thickness: 5,
speed: 0.06,
colors: hslSweep(count: 8, sat: 0.35, light: 0.85),
clip: true,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 22),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(30),
),
child: const Text("Pastel Glow",
style: TextStyle(color: Colors.white)),
),
),
const SizedBox(height: 36),
// 5) 스태디움(필) — 가로로 긴 버튼에 큰 radius
_title("5. 스태디움(필) 모양"),
RainbowEdgeLighting(
radius: 40,
thickness: 4,
speed: 0.25,
colors: [
Color(0xFFFFCDD2), // 연핑크
Color(0xFFEF9A9A), // 부드러운 연빨강
Color(0xFFE57373), // 밝은 레드
Color(0xFFF44336), // 선명한 레드
Color(0xFFFF7043), // 오렌지 레드
Color(0xFFF44336), // 선명한 레드
Color(0xFFE57373), // 밝은 레드
Color(0xFFEF9A9A),
],
clip: true,
child: Container(
width: w - 40,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(40),
),
alignment: Alignment.center,
child: const Text("Stadium / Pill",
style: TextStyle(color: Colors.white)),
),
),
const SizedBox(height: 36),
// 7) 토글 — 켜고 끄기(크로스페이드로 자연스럽게 연결)
_title("7. 토글 스위치로 켜고 끄기 (크로스페이드)"),
Center(
child: Column(
children: [
RainbowEdgeLighting(
radius: 40,
thickness: 4,
speed: 0.2,
enabled: _enabled,
showBorderWhenDisabled: true,
disabledBorderColor: Colors.white24,
colors: hslSweep(count: 9, sat: 0.9, light: 0.6),
clip: true,
child: Container(
width: 100,
height: 100,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(40),
),
child: Icon(
Icons.power_settings_new,
size: 40,
color: _enabled ? Colors.white : Colors.grey,
),
),
),
const SizedBox(height: 16),
Switch(
value: _enabled,
activeColor: Colors.pink,
onChanged: (v) => setState(() => _enabled = v),
),
],
),
),
],
),
);
}
Widget _title(String t) => Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Text(t, style: const TextStyle(color: Colors.white)),
);
}