装饰组件
什么是装饰组件
StatelessWidget
是无状态组件,状态不可变的 widget
class MyApp extends StatelessWidget{
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const Center(
child: Text(
"我是一个文本内容",
textDirection: TextDirection.ltr,
),
);
}
}
StatefulWidget
是有状态组件,持有的状态可能在 widget
生命周期改变
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return Container();
}
}
MaterialApp 和 Scaffold 两个组件装饰 App
1、MaterialApp
MaterialApp
是一个方便的 Widget
,它封装了应用程序实现 Material Design
所需要的一些 Widget
。一
般作为顶层 widget
使用。
常用的属性:
属性 | 含义 |
---|---|
home | 主页 |
title | 标题 |
color | 颜色 |
theme | 主题 |
routes | 路由 |
2、Scaffold
Scaffold
是 Material Design
布局结构的基本实现。此类提供了用于显示 drawer
、snackbar
和底部 sheet
的 API
。
Scaffold
有下面几个主要属性:
属性 | 含义 |
---|---|
appBar | 显示在界面顶部的一个 AppBar |
body | 当前界面所显示的主要内容 Widget |
drawer | 抽屉菜单控件 |
Flutter StatelessWidget 、StatefulWidget
tip
在 Flutter
中自定义组件其实就是一个类,这个类需要继承 StatelessWidget/StatefulWidget
。
StatelessWidget
是无状态组件,状态不可变的 widget
StatefulWidget
是有状态组件,持有的状态可能在 widget
生命周期改变。
StatefulWidget实现一个计数器的功能
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
), // ThemeData
home: Scaffold(
appBar: AppBar(
title: const Text("Flutter App")
), // AppBar
body: const HomePage(),
), // Scaffold
); // MaterialApp
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int countNum=0;
@override
Widget build(BuildContext context) {
return Center(
child: Column(
children: [
const SizedBox(height: 40), // SizedBox
Text("$countNum",
style: Theme.of(context).textTheme.titleLarge
), // Text
const SizedBox(height: 100,),
ElevatedButton(
onPressed: (){
setState(() {
countNum++;
});
},
child: const Text("增加")
) // ElevatedButton
],
),
);
}
}
StatefulWidget实现一个动态列表
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
), // ThemeData
home: Scaffold(
appBar: AppBar(
title: const Text("Flutter App")
),
body: const HomePage(),
), // Scaffold
); // MaterialApp
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<String> list = [];
@override
Widget build(BuildContext context) {
return ListView(
children: [
Column(
children: list.map((value) {
return ListTile(
title: Text(value),
);
})
.toList(),
), // Column
const SizedBox(
height: 40,
), // SizedBox
Padding(
padding: const EdgeInsets.all(40),
child: ElevatedButton(
onPressed: () {
setState(() {
list.add("新增一条数据");
});
},
child: const Text("增加")
), // ElevatedButton
) // Padding
],
); // ListView
}
}
Scaffold属性 BottomNavigationBar 自定义底部导航
BottomNavigationBar 组件介绍
BottomNavigationBar
是底部导航条,可以让我们定义底部 Tab
切换,bottomNavigationBar
是 Scaffold
组件的参数。
BottomNavigationBar
常见的属性:
属性 | 类型 | 含义 |
---|---|---|
items | List 底部导航条按钮集合 | |
iconSize | icon | |
currentIndex | 默认选中第几个 | |
onTap | 选中变化回调函数 | |
fixedColor | 选中的颜色 | |
type | BottomNavigationBarType | BottomNavigationBarType.fixed BottomNavigationBarType.shifting |
BottomNavigationBar 自定义底部导航
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: const Text("Flutter App")
),
body: const Center(
child: Text("我是一个文本"),
),
bottomNavigationBar: BottomNavigationBar(
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: "首页"
),
BottomNavigationBarItem(
icon: Icon(Icons.category),
label: "分类"
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: "设置"
),
]
),
),
);
}
}
BottomNavigationBar 底部菜单选中
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
), // ThemeData
home: const Tabs(),
); // MaterialApp
}
}
class Tabs extends StatefulWidget {
const Tabs({super.key});
@override
State<Tabs> createState() => _TabsState();
}
class _TabsState extends State<Tabs> {
int _currentIndex = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Flutter App")
), // AppBar
body: const Center(
child: Text("我是一个文本"),
), // Center
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
onTap: (v) {
setState(() {
_currentIndex = v;
});
},
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: "首页"
), // BottomNavigationBarItem
BottomNavigationBarItem(
icon: Icon(Icons.category),
label: "分类"
), // BottomNavigationBarItem
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: "设置"
), // BottomNavigationBarItem
]
), // BottomNavigationBar
); // Scaffold
}
}
Scaffold 属性 FloatingActionButton实现类似闲鱼App底部导航凸起按钮
FloatingActionButton 详解
FloatingActionButton
简称 FAB
,可以实现浮动按钮,也可以实现类似 闲鱼app
的底部凸起导航
属性 | 类型 | 含义 |
---|---|---|
child | [] | 子视图,一般为Icon,不推荐使用文字 |
tooltip | FAB 被长按时显示,也是无障碍功能 | |
backgroundColor | 背景颜色 | |
elevation | 未点击的时候的阴影 | |
hignlightElevation | 点击时阴影值,默认12.0 | |
onPressed | 点击事件回调 | |
shape | 可以定义FAB的形状等 | |
mini | 是否是mini类型默认false |
import 'package:flutter/material.dart';
import './tabs/home.dart';
import './tabs/category.dart';
import './tabs/message.dart';
import './tabs/setting.dart';
import './tabs/user.dart';
class Tabs extends StatefulWidget {
const Tabs({super.key});
@override
State<Tabs> createState() => _TabsState();
}
class _TabsState extends State<Tabs> {
int _currentIndex = 0;
final List<Widget> _pages = const [
HomePage(),
CategoryPage(),
MessagePage(),
SettingPage(),
UserPage()
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Flutter App")
), // AppBar
body: _pages[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
fixedColor: Colors.red, //选中的颜色
// iconSize:35, //底部菜单大小
currentIndex: _currentIndex, //第几个菜单选中
type: BottomNavigationBarType.fixed, //如果底部有4个或者4个以上的菜单的时候就需要配置这个参数
onTap: (index) {
//点击菜单触发的方法
//注意
setState(() {
_currentIndex = index;
});
},
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: "首页"
), // BottomNavigationBarItem
BottomNavigationBarItem(
icon: Icon(Icons.category),
label: "分类"
), // BottomNavigationBarItem
BottomNavigationBarItem(
icon: Icon(Icons.message),
label: "消息"
), // BottomNavigationBarItem
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: "设置"
), // BottomNavigationBarItem
BottomNavigationBarItem(
icon: Icon(Icons.people),
label: "用户"
) // BottomNavigationBarItem
]
),
floatingActionButton: Container(
height: 60,
width: 60,
padding: const EdgeInsets.all(4),
margin: const EdgeInsets.only(top: 4),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(30)
), // BoxDecoration
child: FloatingActionButton(
backgroundColor: _currentIndex == 2 ? Colors.red:Colors.blue,
onPressed: () {
setState(() {
_currentIndex = 2;
});
},
child: const Icon(Icons.add),
), // FloatingActionButton
), // Container
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
); // Scaffold
}
}
Scaffold 属性 抽屉菜单 Drawer
在 Scaffold
组件里面传入 drawer
参数可以定义左侧边栏,传入 endDrawer
可以定义右侧边栏。侧边栏默认是隐藏的,我们可以通过手指滑动显示侧边栏,也可以通过点击按钮显示侧边栏。
return Scaffold(
appBar: AppBar(
title: Text("Flutter App"),
),
drawer: Drawer(
child: Text('左侧边栏'),
),
endDrawer: Drawer(
child: Text('右侧侧边栏'),
),
);
DrawerHeader
属性 | 类型 | 含义 |
---|---|---|
decoration | BoxDecoration | 设置顶部背景颜色 |
child | 配置子元素 | |
padding | EdgeInsets | 内边距 |
margin | EdgeInsets | 外边距 |
drawer: Drawer(
child: Column(
children: <Widget>[
DrawerHeader(
decoration: const BoxDecoration(
color: Colors.yellow,
image: DecorationImage(
image: NetworkImage("https://www.au-sonpo.co.jp/common/img/id0026.jpeg"),
fit: BoxFit.cover
) // DecorationImage
), // BoxDecoration
child: ListView(
children: <Widget>[
Text('我是一个头部')
],
), // ListView
), // DrawerHeader
const ListTile(
title: Text("个人中心"),
leading: CircleAvatar(
child: Icon(Icons.people)
), // CircleAvatar
), // ListTile
const Divider(),
const ListTile(
title: Text("系统设置"),
leading: CircleAvatar(
child: Icon(Icons.settings)
), // CircleAvatar
) // DrawerHeader
],
) // Column
) // Drawer
UserAccountsDrawerHeader
属性 | 类型 | 含义 |
---|---|---|
decoration | BoxDecoration | 设置顶部背景颜色 |
accountName | 账户名称 | |
accountEmail | EdgeInsets | 账户邮箱 |
currentAccountPicture | EdgeInsets | 用户头像 |
otherAccountsPictures | EdgeInsets | 用来设置当前账户其他账户头像 |
margin | EdgeInsets | 外边距 |
drawer: Drawer(
child: Column(
children: <Widget>[
UserAccountsDrawerHeader(
accountName:const Text("ACE") ,
accountEmail:const Text("97527027@qq.com") ,
currentAccountPicture: const CircleAvatar(
backgroundImage: NetworkImage("https://www.au-sonpo.co.jp/common/img/id0026.jpeg"),
), // CircleAvatar
decoration: const BoxDecoration(
color: Colors.yellow,
image:DecorationImage(
image: NetworkImage("https://www.au-sonpo.co.jp/common/img/id0026.jpeg"),
fit:BoxFit.cover
)
), // BoxDecoration
otherAccountsPictures: <Widget>[
Image.network("https://www.au-sonpo.co.jp/common/img/id0026.jpeg"),
Image.network("https://www.au-sonpo.co.jp/common/img/id0026.jpeg"),
Image.network("https://www.au-sonpo.co.jp/common/img/id0026.jpeg")
], // otherAccountsPictures
), // UserAccountsDrawerHeader
const ListTile(
title: Text("个人中心"),
leading: CircleAvatar(
child: Icon(Icons.people)
),
), // ListTile
const Divider(),
const ListTile(
title: Text("系统设置"),
leading: CircleAvatar(
child: Icon(Icons.settings)
),
) // ListTile
],
) // Column
) // Drawer
AppBar TabBar TabBarView
AppBar 自定义顶部按钮图标、颜色
属性 | 类型 | 含义 |
---|---|---|
leading | 在标题前面显示的一个控件,在首页通常显示应用的 logo;在其他界面通常显示为返回按钮 | |
title | 标题,通常显示为当前界面的标题文字,可以放组件 | |
actions | 通常使用 IconButton 来表示,可以放按钮组 | |
bottom | 通常放 tabBar ,标题下面显示一个 Tab 导航栏 | |
backgroundColor | 导航背景颜色 | |
iconTheme | 图标样式 | |
centerTitle | 标题是否居中显示 |
AppBar(
backgroundColor:Colors.red,
leading:IconButton(
icon: const Icon(Icons.menu),
onPressed: (){
print('menu Pressed');
}
),
title: const Text('FlutterDemo'),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.search),
onPressed: (){
print('Search Pressed');
}
),
IconButton(
icon: const Icon(Icons.more_horiz),
onPressed: (){
print('more_horiz Pressed');
}
)
],
)
AppBar 结合 TabBar 实现顶部 Tab 切换
TabBar常见属性:
属性 | 类型 | 含义 |
---|---|---|
tabs | 显示的标签内容,一般使用 Tab 对象,也可以是其他的 Widget | |
controller | TabController 对象 | |
isScrollable | 是否可滚动 | |
indicatorColor | 指示器颜色 | |
indicatorWeight | 指示器高度 | |
indicatorPadding | 底部指示器的 Padding | |
indicator | 指示器 decoration ,例如边框等 | |
indicatorSize | 指示器大小计算方式: TabBarIndicatorSize.label 跟 文字 等宽 TabBarIndicatorSize.tab 跟每个 tab 等宽 | |
labelColor | 选中 label 颜色 | |
labelStyle | 选中 label 的 Style | |
labelPadding | 每个 label 的 padding 值 | |
unselectedLabelColor | 未选中 label 颜色 | |
unselectedLabelStyle | 未选中 label 的 Style |
Tabbar TabBarView 实现类似头条顶部导航
- 混入 SingleTickerProviderStateMixin
class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin{}
- 定义 TabController
late TabController _tabController;
void initState() {
super.initState();
_tabController = TabController(length: 8, vsync: this);
_tabController.addListener(() {
if (_tabController.animation!.value == _tabController.index) {
print(_tabController.index); //获取点击或滑动页面的索引值
}
});
}
- 配置 TabBar 和 TabBarView
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
late TabController _tabController;
@override
void initState() {
// TODO: implement initState
super.initState();
_tabController=TabController(length: 3, vsync: this);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Flutter App"),
bottom: TabBar(
controller: _tabController,
tabs: const [
Tab(child:Text("热门")),
Tab(child:Text("推荐")),
Tab(child:Text("视频"))
],
), // TabBar
), // AppBar
body: TabBarView(
controller: _tabController,
children: const [
Text("热门"),
Text("推荐"),
Text("视频")
]
) // TabBarView
); // Scaffold
}
}
- BottomNavigationBar 的页面中使用 Tabbar
import 'package:flutter/material.dart';
import '../../tools/KeepAliveWrapper.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
late TabController _tabController;
@override
void dispose() { //生命周期函数
// TODO: implement dispose
super.dispose();
_tabController.dispose();
}
@override
void initState() {
super.initState();
_tabController = TabController(length: 8, vsync: this);
_tabController.addListener(() {
if (_tabController.animation!.value == _tabController.index) {
print(_tabController.index); //获取点击或滑动页面的索引值
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(40),
child: AppBar(
backgroundColor: const Color.fromARGB(255, 253, 247, 247),
elevation: 10,
title: SizedBox(
height: 30,
child: TabBar(
// isScrollable: true, //如果多个按钮的话可以滑动
indicatorColor: Colors.red,
labelColor: Colors.red,
unselectedLabelColor: Colors.white,
indicatorSize: TabBarIndicatorSize.label,
controller: _tabController, //注意
tabs: const [
Tab(
child: Text("热销",
style: TextStyle(color: Colors.black)
) // Text
), // Tab
Tab(
child:
Text("推荐",
style: TextStyle(color: Colors.black)
) // Text
) // Tab
]
), // TabBar
)
)
),
body: TabBarView(
controller: _tabController, //注意
children: [
KeepAliveWrapper(
child: ListView(
children: const <Widget>[
ListTile(title: Text("第一个tab")),
ListTile(title: Text("第一个tab")),
ListTile(title: Text("第一个tab")),
...
ListTile(title: Text("最后一个tab")),
],
)
), // KeepAliveWrapper 自定义缓存组件
KeepAliveWrapper(
child: ListView(
children: const <Widget>[
ListTile(title: Text("第二个tab")),
ListTile(title: Text("第二个tab")),
ListTile(title: Text("第二个tab"))
],
)
), // KeepAliveWrapper 自定义缓存组件
]
),
);
}
}
- preferredSize 组件
Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(50),
child: AppBar(
....
)
), // PreferredSize
body: Text('preferredSize 组件'),
)