chaoperty_floating_loader 0.1.5
chaoperty_floating_loader: ^0.1.5 copied to clipboard
Global overlay loader with transparent overlay and GIF. Motions: once, ping-pong, loop-wrap. Optional dim background/card. Callable from anywhere via navigatorKey.
example/lib/main.dart
import 'dart:math';
import 'package:chaoperty_floating_loader/src/app_loader.dart';
import 'package:flutter/material.dart';
import 'package:chaoperty_floating_loader/chaoperty_floating_loader.dart';
class DemoPage extends StatefulWidget {
const DemoPage({super.key});
@override
State<DemoPage> createState() => _DemoPageState();
}
class _DemoPageState extends State<DemoPage> {
bool _busy = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Global Floating Loader Demo')),
body: LoadingOverlay(
loading: _busy,
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 520),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// 1) แนวนอน: from → to แบบกำหนดเอง + เด้งปลายทาง
FilledButton(
onPressed: () {
ChaoAppLoader.show(
// asset: 'assets/images/my_duck.png', // หรือ .gif ก็ได้
// assetFromPackage: false, // สำคัญ! บอกว่าไม่ใช่ของแพ็กเกจ
packAsset: ChaoPackAsset.duckFrontWalkGif,
message: 'Once: 0.20 → 0.85 (bounce)',
slideAcross: true,
motion: Motion.once,
fromAt: 0.20,
toAt: 0.85,
bounceAtEdges: true,
slideMs: 4200, // ยิ่งมากยิ่งช้า
verticalFactor: 0.70,
gifWidth: 120, // คุมขนาด GIF เฉพาะ
gifHeight: 110,
);
Future.delayed(
const Duration(milliseconds: 4300),
ChaoAppLoader.hide,
);
},
child: const Text('Once (fromAt → toAt)'),
),
const SizedBox(height: 10),
// 2) แนวนอน: ไปซ้ายสุด เริ่มอีกฟากให้อัตโนมัติ
FilledButton.tonal(
onPressed: () {
ChaoAppLoader.show(
message: 'Once: → 0.05 (auto from right)',
slideAcross: true,
motion: Motion.once,
toAt: 0.05,
slideMs: 1800,
verticalFactor: 0.62,
);
Future.delayed(
const Duration(milliseconds: 1800),
ChaoAppLoader.hide,
);
},
child: const Text('Once (toAt only)'),
),
const SizedBox(height: 10),
// 3) แนวนอน: ping-pong ช่วงกลาง
OutlinedButton(
onPressed: () {
ChaoAppLoader.show(
message: 'Ping-Pong: 0.30 ↔ 0.80 + bounce',
slideAcross: true,
motion: Motion.pingPong,
rangeMinAt: 0.30,
rangeMaxAt: 0.80,
bounceAtEdges: true,
slideMs: 1400,
verticalFactor: 0.66,
);
Future.delayed(
const Duration(seconds: 5), ChaoAppLoader.hide);
},
child: const Text('Ping-Pong (rangeMin/Max)'),
),
const SizedBox(height: 10),
// 4) แนวนอน: loop wrap วิ่ง L → R
OutlinedButton(
onPressed: () {
ChaoAppLoader.show(
message: 'Loop wrap (L → R)',
slideAcross: true,
motion: Motion.loopWrap,
slideToRight: true,
startAt: Random().nextDouble(),
slideMs: 2400,
verticalFactor: 0.72,
size: 90,
);
Future.delayed(
const Duration(seconds: 5), ChaoAppLoader.hide);
},
child: const Text('Loop Wrap (Left → Right)'),
),
const SizedBox(height: 16),
const Divider(),
const SizedBox(height: 16),
// 5) แนวตั้งอย่างเดียว (บน → ล่าง)
FilledButton(
onPressed: () {
ChaoAppLoader.show(
message: 'Vertical once: 0.10 → 0.85',
vSlideAcross: true,
vMotion: Motion.once,
vFromAt: 0.10,
vToAt: 0.85,
slideMs: 2600,
// ไม่วิ่งแนวนอน → slideAcross=false (default)
);
Future.delayed(
const Duration(milliseconds: 2600),
ChaoAppLoader.hide,
);
},
child: const Text('Vertical Once'),
),
const SizedBox(height: 10),
// 6) ทแยง: แนวนอน loop + แนวตั้ง ping-pong
FilledButton.tonal(
onPressed: () {
ChaoAppLoader.show(
message: 'Diagonal: loop X + ping-pong Y',
slideAcross: true,
motion: Motion.loopWrap,
slideToRight: true,
startAt: 0.2,
vSlideAcross: true,
vMotion: Motion.pingPong,
vRangeMinAt: 0.65,
vRangeMaxAt: 0.80,
slideMs: 2400, // คุมความเร็วทั้ง 2 แกนพร้อมกัน
);
Future.delayed(
const Duration(seconds: 5), ChaoAppLoader.hide);
},
child: const Text('Diagonal (X loop + Y ping-pong)'),
),
const SizedBox(height: 24),
const Divider(),
const SizedBox(height: 12),
Text('LoadingOverlay (เฉพาะหน้านี้)',
style: Theme.of(context).textTheme.titleMedium),
const SizedBox(height: 8),
Row(
mainAxisSize: MainAxisSize.min,
children: [
const Text('Busy overlay: '),
Switch(
value: _busy,
onChanged: (v) => setState(() => _busy = v),
),
],
),
const SizedBox(height: 8),
ElevatedButton(
onPressed: () async {
setState(() => _busy = true);
await Future.delayed(const Duration(seconds: 2));
if (mounted) setState(() => _busy = false);
},
child: const Text('Run busy task (2s)'),
),
],
),
),
),
),
);
}
}