Appearance
Flutter UI组件
Flutter提供了丰富的UI组件(Widgets)来构建美观、功能强大的用户界面。本章将详细介绍各种UI组件的使用方法、特性和最佳实践。
基础UI组件
文本组件
dart
import 'package:flutter/material.dart';
class TextComponentsDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Text Components')),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 基础文本
Text(
'基础文本',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 16),
// 标题文本
Text(
'标题文本示例',
style: Theme.of(context).textTheme.headlineSmall,
),
SizedBox(height: 8),
// 正文文本
Text(
'这是正文文本示例,通常用于描述性内容的展示。',
style: Theme.of(context).textTheme.bodyMedium,
),
SizedBox(height: 16),
// 样式化文本
Text(
'粗体、斜体、下划线文本',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.italic,
decoration: TextDecoration.underline,
color: Colors.blue,
),
),
SizedBox(height: 16),
// 富文本
RichText(
text: TextSpan(
style: TextStyle(color: Colors.black87, fontSize: 16),
children: [
TextSpan(text: '富文本示例:'),
TextSpan(
text: '重要部分',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.red,
),
),
TextSpan(text: ' 普通部分'),
TextSpan(
text: ' 链接样式',
style: TextStyle(
color: Colors.blue,
decoration: TextDecoration.underline,
),
),
],
),
),
SizedBox(height: 16),
// 自适应文本
Container(
width: 200,
child: Text(
'这是一个很长的文本示例,用于演示文本溢出处理。当文本超出容器宽度时,会有不同的处理方式。',
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 14),
),
),
],
),
),
);
}
}
按钮组件
dart
class ButtonComponentsDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Button Components')),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
// ElevatedButton (Material Design)
ElevatedButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('ElevatedButton pressed')),
);
},
child: Text('Elevated Button'),
),
SizedBox(height: 16),
// OutlinedButton
OutlinedButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('OutlinedButton pressed')),
);
},
child: Text('Outlined Button'),
),
SizedBox(height: 16),
// TextButton
TextButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('TextButton pressed')),
);
},
child: Text('Text Button'),
),
SizedBox(height: 16),
// IconButton
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
onPressed: () {
print('Favorite button pressed');
},
icon: Icon(Icons.favorite),
color: Colors.red,
),
IconButton(
onPressed: () {
print('Share button pressed');
},
icon: Icon(Icons.share),
color: Colors.blue,
),
IconButton(
onPressed: () {
print('More button pressed');
},
icon: Icon(Icons.more_vert),
),
],
),
SizedBox(height: 16),
// FloatingActionButton
FloatingActionButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('FloatingActionButton pressed')),
);
},
child: Icon(Icons.add),
backgroundColor: Colors.green,
),
SizedBox(height: 16),
// 自定义样式的按钮
Container(
width: double.infinity,
height: 50,
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.purple,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
shadowColor: Colors.purpleAccent,
elevation: 5,
),
child: Text(
'Custom Styled Button',
style: TextStyle(fontSize: 16),
),
),
),
],
),
),
);
}
}
图片组件
dart
class ImageComponentsDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Image Components')),
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
// 网络图片
Container(
height: 200,
width: double.infinity,
child: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.network(
'https://via.placeholder.com/600x400/4A90E2/FFFFFF?text=Network+Image',
fit: BoxFit.cover,
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Container(
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(12),
),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: null,
),
SizedBox(height: 8),
Text('Loading...'),
],
),
),
);
},
errorBuilder: (context, error, stackTrace) {
return Container(
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(12),
),
child: Icon(
Icons.error_outline,
size: 50,
color: Colors.red,
),
);
},
),
),
),
SizedBox(height: 16),
// 本地图片 (需要在pubspec.yaml中声明资源)
/*
Image.asset(
'assets/images/sample_image.jpg',
width: 200,
height: 150,
fit: BoxFit.cover,
),
*/
// 圆形图片
Container(
width: 120,
height: 120,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(color: Colors.blue, width: 3),
),
child: ClipOval(
child: Image.network(
'https://via.placeholder.com/200x200/FF6B6B/FFFFFF?text=Avatar',
fit: BoxFit.cover,
),
),
),
SizedBox(height: 16),
// 圆角矩形图片
Container(
width: 200,
height: 150,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
image: DecorationImage(
image: NetworkImage(
'https://via.placeholder.com/400x300/50C878/FFFFFF?text=Rounded+Image',
),
fit: BoxFit.cover,
),
),
),
SizedBox(height: 16),
// 带遮罩的图片
Stack(
children: [
Container(
width: 300,
height: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
image: DecorationImage(
image: NetworkImage(
'https://via.placeholder.com/600x400/9B59B6/FFFFFF?text=Masked+Image',
),
fit: BoxFit.cover,
),
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.vertical(bottom: Radius.circular(12)),
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.transparent, Colors.black54],
),
),
padding: EdgeInsets.all(16),
child: Text(
'图片标题',
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
],
),
),
),
);
}
}
表单组件
输入框组件
dart
class FormComponentsDemo extends StatefulWidget {
@override
_FormComponentsDemoState createState() => _FormComponentsDemoState();
}
class _FormComponentsDemoState extends State<FormComponentsDemo> {
final _formKey = GlobalKey<FormState>();
final _textEditingController = TextEditingController();
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
bool _obscurePassword = true;
String? _selectedOption;
bool _checkboxValue = false;
bool _switchValue = false;
double _sliderValue = 50.0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Form Components')),
body: Form(
key: _formKey,
child: SingleChildScrollView(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
// 基础文本输入框
TextFormField(
controller: _textEditingController,
decoration: InputDecoration(
labelText: '姓名',
hintText: '请输入您的姓名',
prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
),
validator: (value) {
if (value == null || value.isEmpty) {
return '姓名不能为空';
}
if (value.length < 2) {
return '姓名至少需要2个字符';
}
return null;
},
),
SizedBox(height: 16),
// 邮箱输入框
TextFormField(
controller: _emailController,
decoration: InputDecoration(
labelText: '邮箱',
hintText: 'example@email.com',
prefixIcon: Icon(Icons.email),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value == null || value.isEmpty) {
return '邮箱不能为空';
}
if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)) {
return '请输入有效的邮箱地址';
}
return null;
},
),
SizedBox(height: 16),
// 密码输入框
TextFormField(
controller: _passwordController,
decoration: InputDecoration(
labelText: '密码',
hintText: '请输入密码',
prefixIcon: Icon(Icons.lock),
suffixIcon: IconButton(
icon: Icon(
_obscurePassword ? Icons.visibility : Icons.visibility_off,
),
onPressed: () {
setState(() {
_obscurePassword = !_obscurePassword;
});
},
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
),
obscureText: _obscurePassword,
validator: (value) {
if (value == null || value.isEmpty) {
return '密码不能为空';
}
if (value.length < 6) {
return '密码至少需要6个字符';
}
return null;
},
),
SizedBox(height: 16),
// 下拉选择框
DropdownButtonFormField<String>(
value: _selectedOption,
decoration: InputDecoration(
labelText: '请选择选项',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
),
items: ['选项1', '选项2', '选项3', '选项4'].map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String? newValue) {
setState(() {
_selectedOption = newValue;
});
},
validator: (value) {
if (value == null) {
return '请选择一个选项';
}
return null;
},
),
SizedBox(height: 16),
// 复选框
Row(
children: [
Checkbox(
value: _checkboxValue,
onChanged: (bool? value) {
setState(() {
_checkboxValue = value ?? false;
});
},
),
Text('同意服务条款'),
],
),
SizedBox(height: 16),
// 开关
Row(
children: [
Text('推送通知'),
Spacer(),
Switch(
value: _switchValue,
onChanged: (bool value) {
setState(() {
_switchValue = value;
});
},
),
],
),
SizedBox(height: 16),
// 滑块
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('音量控制: ${_sliderValue.toInt()}'),
Slider(
value: _sliderValue,
min: 0,
max: 100,
divisions: 10,
label: _sliderValue.round().toString(),
onChanged: (double value) {
setState(() {
_sliderValue = value;
});
},
),
],
),
SizedBox(height: 24),
// 提交按钮
SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
onPressed: _submitForm,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
child: Text(
'提交',
style: TextStyle(fontSize: 16, color: Colors.white),
),
),
),
],
),
),
),
);
}
void _submitForm() {
if (_formKey.currentState!.validate()) {
// 显示表单数据
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('表单数据'),
content: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text('姓名: ${_textEditingController.text}'),
Text('邮箱: ${_emailController.text}'),
Text('密码: ${'*' * _passwordController.text.length}'),
Text('选择: $_selectedOption'),
Text('复选框: $_checkboxValue'),
Text('开关: $_switchValue'),
Text('滑块: ${_sliderValue.toInt()}'),
],
),
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('确定'),
),
],
);
},
);
}
}
@override
void dispose() {
_textEditingController.dispose();
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}
}
列表组件
ListView和ListTile
dart
class ListComponentsDemo extends StatefulWidget {
@override
_ListComponentsDemoState createState() => _ListComponentsDemoState();
}
class _ListComponentsDemoState extends State<ListComponentsDemo> {
final List<Map<String, dynamic>> _items = [
{
'id': 1,
'title': '项目 1',
'subtitle': '这是第一个项目的描述',
'icon': Icons.home,
'color': Colors.blue,
},
{
'id': 2,
'title': '项目 2',
'subtitle': '这是第二个项目的描述',
'icon': Icons.favorite,
'color': Colors.red,
},
{
'id': 3,
'title': '项目 3',
'subtitle': '这是第三个项目的描述',
'icon': Icons.settings,
'color': Colors.green,
},
{
'id': 4,
'title': '项目 4',
'subtitle': '这是第四个项目的描述',
'icon': Icons.notifications,
'color': Colors.orange,
},
{
'id': 5,
'title': '项目 5',
'subtitle': '这是第五个项目的描述',
'icon': Icons.person,
'color': Colors.purple,
},
];
bool _showLeading = true;
bool _showTrailing = true;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('List Components'),
actions: [
PopupMenuButton<String>(
onSelected: (String value) {
setState(() {
if (value == 'toggle-leading') {
_showLeading = !_showLeading;
} else if (value == 'toggle-trailing') {
_showTrailing = !_showTrailing;
}
});
},
itemBuilder: (BuildContext context) {
return [
PopupMenuItem(
value: 'toggle-leading',
child: Text(_showLeading ? '隐藏图标' : '显示图标'),
),
PopupMenuItem(
value: 'toggle-trailing',
child: Text(_showTrailing ? '隐藏箭头' : '显示箭头'),
),
];
},
),
],
),
body: ListView.builder(
itemCount: _items.length,
itemBuilder: (context, index) {
final item = _items[index];
return Card(
margin: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
child: ListTile(
leading: _showLeading
? CircleAvatar(
backgroundColor: item['color'],
child: Icon(item['icon'], color: Colors.white),
)
: null,
title: Text(
item['title'],
style: TextStyle(fontWeight: FontWeight.bold),
),
subtitle: Text(item['subtitle']),
trailing: _showTrailing ? Icon(Icons.arrow_forward_ios, size: 16) : null,
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('点击了 ${item['title']}')),
);
},
onLongPress: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('确认删除'),
content: Text('确定要删除 ${item['title']} 吗?'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('取消'),
),
TextButton(
onPressed: () {
setState(() {
_items.removeAt(index);
});
Navigator.of(context).pop();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('已删除 ${item['title']}')),
);
},
child: Text('删除', style: TextStyle(color: Colors.red)),
),
],
);
},
);
},
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: _addItem,
child: Icon(Icons.add),
),
);
}
void _addItem() {
setState(() {
_items.add({
'id': _items.length + 1,
'title': '新项目 ${_items.length + 1}',
'subtitle': '这是新添加项目的描述',
'icon': Icons.new_releases,
'color': Colors.teal,
});
});
}
}
ExpansionTile
dart
class ExpansionTileDemo extends StatelessWidget {
final List<Map<String, dynamic>> _categories = [
{
'title': '水果',
'children': ['苹果', '香蕉', '橙子', '葡萄'],
'icon': Icons.local_grocery_store,
},
{
'title': '蔬菜',
'children': ['胡萝卜', '西红柿', '黄瓜', '白菜'],
'icon': Icons.eco,
},
{
'title': '电子产品',
'children': ['手机', '电脑', '平板', '耳机'],
'icon': Icons.phone_android,
},
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Expansion Tile Demo')),
body: ListView.builder(
itemCount: _categories.length,
itemBuilder: (context, index) {
final category = _categories[index];
return Card(
margin: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
child: ExpansionTile(
leading: Icon(category['icon']),
title: Text(
category['title'],
style: TextStyle(fontWeight: FontWeight.bold),
),
children: category['children']
.map((child) => Padding(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
children: [
Icon(Icons.circle, size: 8, color: Colors.grey),
SizedBox(width: 8),
Text(child),
],
),
))
.toList(),
),
);
},
),
);
}
}
导航组件
BottomNavigationBar
dart
class BottomNavigationDemo extends StatefulWidget {
@override
_BottomNavigationDemoState createState() => _BottomNavigationDemoState();
}
class _BottomNavigationDemoState extends State<BottomNavigationDemo> {
int _selectedIndex = 0;
final List<Widget> _pages = [
HomePage(),
SearchPage(),
ProfilePage(),
SettingsPage(),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(
index: _selectedIndex,
children: _pages,
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
activeIcon: Icon(Icons.home, color: Colors.blue),
label: '首页',
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
activeIcon: Icon(Icons.search, color: Colors.blue),
label: '搜索',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
activeIcon: Icon(Icons.person, color: Colors.blue),
label: '我的',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
activeIcon: Icon(Icons.settings, color: Colors.blue),
label: '设置',
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.blue,
unselectedItemColor: Colors.grey,
onTap: _onItemTapped,
type: BottomNavigationBarType.fixed,
),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.home, size: 64, color: Colors.blue),
SizedBox(height: 16),
Text('首页', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
],
),
);
}
}
class SearchPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.search, size: 64, color: Colors.green),
SizedBox(height: 16),
Text('搜索', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
],
),
);
}
}
class ProfilePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.person, size: 64, color: Colors.orange),
SizedBox(height: 16),
Text('我的', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
],
),
);
}
}
class SettingsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.settings, size: 64, color: Colors.purple),
SizedBox(height: 16),
Text('设置', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
],
),
);
}
}
AppBar和Drawer
dart
class NavigationDrawerDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Navigation with Drawer'),
actions: [
IconButton(
icon: Icon(Icons.search),
onPressed: () {
print('Search button pressed');
},
),
IconButton(
icon: Icon(Icons.more_vert),
onPressed: () {
print('More options pressed');
},
),
],
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
DrawerHeader(
decoration: BoxDecoration(
color: Colors.blue,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: [
CircleAvatar(
radius: 30,
backgroundColor: Colors.white,
child: Icon(Icons.person, size: 30, color: Colors.blue),
),
SizedBox(height: 8),
Text(
'用户名',
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Text(
'user@example.com',
style: TextStyle(
color: Colors.white70,
fontSize: 14,
),
),
],
),
),
ListTile(
leading: Icon(Icons.home),
title: Text('首页'),
onTap: () {
Navigator.pop(context);
// 处理导航
},
),
ListTile(
leading: Icon(Icons.favorite),
title: Text('收藏'),
onTap: () {
Navigator.pop(context);
// 处理导航
},
),
ListTile(
leading: Icon(Icons.history),
title: Text('历史记录'),
onTap: () {
Navigator.pop(context);
// 处理导航
},
),
Divider(),
ListTile(
leading: Icon(Icons.settings),
title: Text('设置'),
onTap: () {
Navigator.pop(context);
// 处理导航
},
),
ListTile(
leading: Icon(Icons.help),
title: Text('帮助'),
onTap: () {
Navigator.pop(context);
// 处理导航
},
),
],
),
),
body: Center(
child: Text('主内容区域'),
),
);
}
}
对话框组件
AlertDialog和SnackBar
dart
class DialogComponentsDemo extends StatefulWidget {
@override
_DialogComponentsDemoState createState() => _DialogComponentsDemoState();
}
class _DialogComponentsDemoState extends State<DialogComponentsDemo> {
final GlobalKey<ScaffoldMessengerState> _scaffoldKey = GlobalKey();
@override
Widget build(BuildContext context) {
return ScaffoldMessenger(
key: _scaffoldKey,
child: Scaffold(
appBar: AppBar(title: Text('Dialog Components')),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: _showAlertDialog,
child: Text('显示确认对话框'),
),
ElevatedButton(
onPressed: _showCustomDialog,
child: Text('显示自定义对话框'),
),
ElevatedButton(
onPressed: _showSnackBar,
child: Text('显示Snack Bar'),
),
ElevatedButton(
onPressed: _showBottomSheet,
child: Text('显示底部面板'),
),
],
),
),
),
);
}
void _showAlertDialog() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('确认操作'),
content: Text('您确定要执行此操作吗?此操作不可逆。'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: Text('取消'),
),
ElevatedButton(
onPressed: () {
Navigator.of(context).pop(true);
_showSnackBar();
},
child: Text('确定'),
),
],
);
},
);
}
void _showCustomDialog() {
showDialog(
context: context,
builder: (BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Container(
padding: EdgeInsets.all(16),
constraints: BoxConstraints(minHeight: 200, minWidth: 300),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.star,
size: 48,
color: Colors.orange,
),
SizedBox(height: 16),
Text(
'自定义对话框',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
Text(
'这是一个自定义样式的对话框示例',
textAlign: TextAlign.center,
),
SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('关闭'),
),
],
),
],
),
),
);
},
);
}
void _showSnackBar() {
_scaffoldKey.currentState?.showSnackBar(
SnackBar(
content: Text('这是一个 SnackBar 消息'),
action: SnackBarAction(
label: '撤销',
onPressed: () {
print('撤销操作');
},
),
duration: Duration(seconds: 3),
),
);
}
void _showBottomSheet() {
showModalBottomSheet(
context: context,
isScrollControlled: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
builder: (BuildContext context) {
return Container(
padding: EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 40,
height: 4,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(2),
),
),
SizedBox(height: 16),
Text(
'底部面板',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 16),
ListTile(
leading: Icon(Icons.share),
title: Text('分享'),
onTap: () {
Navigator.pop(context);
_showSnackBar();
},
),
ListTile(
leading: Icon(Icons.favorite),
title: Text('收藏'),
onTap: () {
Navigator.pop(context);
_showSnackBar();
},
),
ListTile(
leading: Icon(Icons.settings),
title: Text('设置'),
onTap: () {
Navigator.pop(context);
_showSnackBar();
},
),
],
),
);
},
);
}
}
状态指示器组件
ProgressIndicator
dart
class ProgressIndicatorDemo extends StatefulWidget {
@override
_ProgressIndicatorDemoState createState() => _ProgressIndicatorDemoState();
}
class _ProgressIndicatorDemoState extends State<ProgressIndicatorDemo> {
double _progressValue = 0.0;
bool _isLoading = false;
void _simulateProgress() {
setState(() {
_isLoading = true;
_progressValue = 0.0;
});
Timer.periodic(Duration(milliseconds: 100), (timer) {
if (_progressValue >= 1.0) {
timer.cancel();
setState(() {
_isLoading = false;
});
} else {
setState(() {
_progressValue += 0.05;
});
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Progress Indicators')),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// Linear Progress Indicator
Column(
children: [
Text('Linear Progress'),
SizedBox(height: 8),
LinearProgressIndicator(
value: _isLoading ? _progressValue : null,
minHeight: 8,
borderRadius: BorderRadius.circular(4),
),
SizedBox(height: 8),
Text('${(_progressValue * 100).round()}%'),
],
),
// Circular Progress Indicator
Column(
children: [
Text('Circular Progress'),
SizedBox(height: 8),
SizedBox(
width: 60,
height: 60,
child: CircularProgressIndicator(
value: _isLoading ? _progressValue : null,
strokeWidth: 6,
),
),
SizedBox(height: 8),
Text(_isLoading ? '加载中...' : '已完成'),
],
),
// Custom Progress Indicator
Column(
children: [
Text('Custom Progress'),
SizedBox(height: 8),
Container(
width: 200,
height: 20,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(10),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: LinearProgressIndicator(
value: _progressValue,
backgroundColor: Colors.transparent,
valueColor: AlwaysStoppedAnimation<Color>(Colors.green),
),
),
),
],
),
ElevatedButton(
onPressed: _simulateProgress,
child: Text('开始模拟进度'),
),
],
),
),
);
}
}
总结
Flutter提供了丰富的UI组件,从基础的文本、按钮、图片到复杂的表单、列表、导航组件。合理使用这些组件可以构建出功能丰富、用户体验良好的应用程序。在实际开发中,应该根据具体需求选择合适的组件,并注意组件的性能和用户体验。