97 lines
4.1 KiB
Dart
97 lines
4.1 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||
import 'package:new_learn/core/providers/user_provider.dart';
|
||
|
||
/// ============================================================
|
||
/// Align 对齐布局演示页 + Riverpod 全局用户信息展示
|
||
///
|
||
/// 一、Align 两种使用方式:
|
||
/// 1. 直接运行本页面:把 main() 改为
|
||
/// runApp(const ProviderScope(child: MaterialApp(home: AlignDemoPage())));
|
||
/// 2. 复制 body 核心代码到任意 Scaffold 的 body 中:
|
||
///
|
||
/// body: Container(
|
||
/// width: 300,
|
||
/// height: 300,
|
||
/// color: Colors.grey[200],
|
||
/// child: Align(
|
||
/// alignment: Alignment.bottomLeft, // 子组件放到父盒子左下角
|
||
/// child: Container(...), // 用户信息卡片
|
||
/// ),
|
||
/// ),
|
||
///
|
||
/// 二、Flutter 核心布局规则(务必理解):
|
||
/// 1. 父组件给子组件传递【约束】(Constraints),子组件在约束范围内决定自身【大小】;
|
||
/// 2. Align 会把自身区域扩大到父组件允许的最大范围(宽高撑满),
|
||
/// 然后通过 alignment 把子组件放到指定位置;
|
||
/// 3. 子组件的 size(宽高)如果不写,Align 会取子组件的固有尺寸;
|
||
/// 一旦写了固定 width/height,就由子组件自己决定,Align 不再干预。
|
||
///
|
||
/// 三、Riverpod 全局状态用法(本次新增重点):
|
||
/// - AlignDemoPage 改成 ConsumerWidget(build 多一个 WidgetRef ref 参数);
|
||
/// - `ref.watch(currentUserProvider)` 订阅全局用户,登录后任何页面都拿到;
|
||
/// - `.value` 是 CurrentUserExtension?:登录了有值,未登录是 null;
|
||
/// - 登录页登录成功时会 set 这个 provider,本卡片自动刷新(无需手动 setState)。
|
||
///
|
||
/// 四、高频坑:
|
||
/// 1. 用了 ref 的组件必须继承 ConsumerWidget / ConsumerStatefulWidget,
|
||
/// 普通 StatelessWidget 拿不到 ref(编译报错);
|
||
/// 2. ref.watch 要在 build 里调用(声明式依赖),ref.read 才能放回调里;
|
||
/// 3. 加了 .w/.h/.sp 的 widget 不能再用 const(尺寸是运行期算的)。
|
||
/// ============================================================
|
||
class AlignDemoPage extends ConsumerWidget {
|
||
const AlignDemoPage({super.key});
|
||
|
||
@override
|
||
Widget build(BuildContext context, WidgetRef ref) {
|
||
// Riverpod 全局用户:登录后全 App 共享,未登录为 null
|
||
final user = ref.watch(currentUserProvider).value;
|
||
|
||
return Scaffold(
|
||
appBar: AppBar(title: const Text('Align 对齐布局 Demo11')),
|
||
// ---------- 下方即为核心代码,可直接复制到 Scaffold body ----------
|
||
body: Container(
|
||
width: 300.w,
|
||
height: 300.h,
|
||
color: Colors.grey[300],
|
||
child: Align(
|
||
alignment: Alignment.bottomLeft, // 子组件放到父盒子左下角
|
||
child: Container(
|
||
width: 240.w,
|
||
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 10.h),
|
||
decoration: BoxDecoration(
|
||
color: Colors.blue,
|
||
borderRadius: BorderRadius.circular(8.w),
|
||
),
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min, // 卡片高度跟随内容
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Text(
|
||
'用户:${user?.userName ?? '未登录'}',
|
||
style: TextStyle(
|
||
color: Colors.white,
|
||
fontSize: 18.sp,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
SizedBox(height: 6.h),
|
||
Text(
|
||
'班级:${user?.className ?? '-'}',
|
||
style: TextStyle(color: Colors.white, fontSize: 14.sp),
|
||
),
|
||
SizedBox(height: 4.h),
|
||
Text(
|
||
'积分:${user?.userPoints ?? 0}',
|
||
style: TextStyle(color: Colors.white, fontSize: 14.sp),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|