Debian 下 Flutter 界面设计实战指南
一 环境准备与项目创建
二 设计语言与主题搭建
三 布局思路与常用组件
四 桌面端适配要点
五 实战示例 登录页骨架
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: const LoginPage(),
);
}
}
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final _formKey = GlobalKey<FormState>();
final _username = TextEditingController();
final _password = TextEditingController();
bool _loading = false;
void _submit() async {
if (_formKey.currentState!.validate()) {
setState(() => _loading = true);
// TODO: 登录逻辑
await Future.delayed(const Duration(seconds: 2));
setState(() => _loading = false);
}
}
@override
void dispose() {
_username.dispose();
_password.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
final isWide = width >= 600;
return Scaffold(
appBar: AppBar(title: const Text('登录')),
body: Center(
child: SizedBox(
width: isWide ? 400 : width * 0.9,
child: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(height: 32),
Text('欢迎回来',
style: Theme.of(context).textTheme.headlineSmall),
const SizedBox(height: 8),
Text('请登录您的账户',
style: Theme.of(context).textTheme.bodyMedium),
const SizedBox(height: 32),
TextFormField(
controller: _username,
decoration: const InputDecoration(
labelText: '用户名',
prefixIcon: Icon(Icons.person_outline),
border: OutlineInputBorder(),
),
validator: (v) =>
(v == null || v.isEmpty) ? '请输入用户名' : null,
),
const SizedBox(height: 16),
TextFormField(
controller: _password,
obscureText: true,
decoration: const InputDecoration(
labelText: '密码',
prefixIcon: Icon(Icons.lock_outline),
border: OutlineInputBorder(),
),
validator: (v) =>
(v == null || v.isEmpty) ? '请输入密码' : null,
),
const SizedBox(height: 24),
FilledButton(
onPressed: _loading ? null : _submit,
child: _loading
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2, color: Colors.white),
)
: const Text('登录'),
),
const SizedBox(height: 16),
TextButton(
onPressed: () {/* TODO: 忘记密码 */},
child: const Text('忘记密码?'),
),
],
),
),
),
),
),
);
}
}