flutter_joon_flat 1.0.1
flutter_joon_flat: ^1.0.1 copied to clipboard
Flutter Widget 扁平化扩展库:把嵌套的 widget 树转成链式调用。
import 'package:flutter/material.dart';
import 'package:flutter_joon_flat/flutter_joon_flat.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'flutter_joon_flat 示例',
theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true),
home: const DemoPage(),
);
}
}
class DemoPage extends StatefulWidget {
const DemoPage({super.key});
@override
State<DemoPage> createState() => _DemoPageState();
}
class _DemoPageState extends State<DemoPage> {
bool _toggle = true;
bool _hasError = false;
int _tapCount = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('flutter_joon_flat 全模块示例'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
_section('核心链式', _coreChain()),
_section('1. layout — 布局', _layoutSection()),
_section('2. decoration — 装饰', _decorationSection()),
_section('3. gesture — 手势', _gestureSection()),
_section('4. visibility — 可见性', _visibilitySection()),
_section('5. transform — 变换', _transformSection()),
_section('6. interactive — 交互', _interactiveSection()),
_section('7. conditional — 条件链', _conditionalSection()),
],
),
);
}
Widget _section(String title, Widget content) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(top: 24, bottom: 8),
child: Text(title, style: Theme.of(context).textTheme.titleMedium?.copyWith(color: Colors.deepPurple)),
),
content,
],
);
}
/// 核心示例:Text('Hi').p(16).bg(Colors.white).onTap(() {}).center()
Widget _coreChain() {
return const Text('Hi')
.p(16)
.bg(Colors.white)
.rounded(JoonRadius.lg)
.onTap(() => setState(() => _tapCount++))
.center();
}
/// layout: p, px, py, align, center, size, expanded, safeArea
Widget _layoutSection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('p(12)').p(12).bg(Colors.blue.shade100).roundedMd(),
const SizedBox(height: 8),
const Text('px(20) py(8)').px(20).py(8).bg(Colors.green.shade100).roundedMd(),
const SizedBox(height: 8),
const Text('center()').p(8).bg(Colors.orange.shade100).center(),
const SizedBox(height: 8),
const Text('align(Alignment.centerRight)').p(8).bg(Colors.purple.shade100).align(Alignment.centerRight),
const SizedBox(height: 8),
const Text('size(200, 40)').size(width: 200, height: 40).bg(Colors.teal.shade100).center(),
const SizedBox(height: 8),
Row(
children: [
const Text('expanded').p(8).bg(Colors.indigo.shade100).expanded(),
4.ww,
const Text('flex:2').p(8).bg(Colors.pink.shade100).expanded(2),
],
),
const SizedBox(height: 8),
Row(children: [const Text('8.ww'), 8.ww, const Text('间距'), 10.ww, const Text('10.hw↓')]),
10.hw,
const Text('10.hw 上方间距').p(4),
],
);
}
/// decoration: bg, rounded, shadow, clip, card
Widget _decorationSection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('bg + roundedLg').p(12).bg(Colors.amber.shade200).roundedLg(),
const SizedBox(height: 8),
const Text('roundedXl + shadowLg').p(12).bg(Colors.white).roundedXl().shadowLg(),
const SizedBox(height: 8),
const Text('clipCircle').p(16).bg(Colors.cyan).clipCircle(),
const SizedBox(height: 8),
const Text('card()').p(16).card(color: Colors.white, shapeRadius: 8),
],
);
}
/// gesture: onTap, onLongPress
Widget _gestureSection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('onTap (点击计数: $_tapCount)')
.p(12)
.bg(Colors.blue.shade200)
.roundedLg()
.onTap(() => setState(() => _tapCount++)),
const SizedBox(height: 8),
const Text('onLongPress 长按试试')
.p(12)
.bg(Colors.orange.shade200)
.roundedLg()
.onLongPress(() => ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('长按触发')))),
],
);
}
/// visibility: opacity, visible, offstage, showIf
Widget _visibilitySection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('opacity(0.6)').p(12).bg(Colors.green.shade200).opacity(0.6),
const SizedBox(height: 8),
Row(
children: [
const Text('showIf(_toggle)').p(8).bg(Colors.purple.shade200).showIf(_toggle),
const SizedBox(width: 8),
TextButton(
onPressed: () => setState(() => _toggle = !_toggle),
child: Text(_toggle ? '隐藏' : '显示'),
),
],
),
const SizedBox(height: 8),
const Text('visible(false) 占位隐藏').p(8).bg(Colors.grey.shade300).visible(false),
],
);
}
/// transform: rotate, scale, translate, flip
Widget _transformSection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('rotate(0.1)').p(8).bg(Colors.amber.shade200).rotate(0.1),
const SizedBox(height: 8),
const Text('scale(1.2)').p(8).bg(Colors.teal.shade200).scale(1.2),
const SizedBox(height: 8),
const Text('translate(20, 0)').p(8).bg(Colors.indigo.shade200).translate(20, 0),
const SizedBox(height: 8),
const Text('flipX()').p(8).bg(Colors.pink.shade200).flipX(),
],
);
}
/// interactive: semantics(无 Material 依赖)
Widget _interactiveSection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('semantics(label)').p(12).bg(Colors.blue.shade100).semantics(label: '示例标签'),
const SizedBox(height: 8),
const Text('semantics(button: true)').p(12).bg(Colors.green.shade100).roundedLg().semantics(button: true, label: '按钮'),
],
);
}
/// conditional: when, branch, apply
Widget _conditionalSection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('when(_toggle, 加绿底)')
.p(8)
.when(_toggle, (w) => w.bg(Colors.green.shade200))
.rounded(4),
const SizedBox(height: 8),
Row(
children: [
const Text('branch(错误?)').p(8).branch(_hasError, (w) => w.bg(Colors.red.shade200), (w) => w.bg(Colors.blue.shade200)).roundedMd(),
const SizedBox(width: 8),
TextButton(
onPressed: () => setState(() => _hasError = !_hasError),
child: Text(_hasError ? '正常' : '错误'),
),
],
),
const SizedBox(height: 8),
const Text('apply((w) => w.p(4).bg(grey))')
.apply((w) => w.p(4).bg(Colors.grey.shade300))
.roundedMd(),
],
);
}
}