Skip to main content

装饰组件

什么是装饰组件

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

ScaffoldMaterial Design 布局结构的基本实现。此类提供了用于显示 drawersnackbar 和底部 sheetAPI

Scaffold 有下面几个主要属性:

属性含义
appBar显示在界面顶部的一个 AppBar
body当前界面所显示的主要内容 Widget
drawer抽屉菜单控件

Flutter StatelessWidget 、StatefulWidget

tip

Flutter 中自定义组件其实就是一个类,这个类需要继承 StatelessWidget/StatefulWidget

StatelessWidget 是无状态组件,状态不可变的 widget

StatefulWidget 是有状态组件,持有的状态可能在 widget 生命周期改变。

通俗的讲:如果我们想改变页面中的数据的话这个时候就需要用到 `StatefulWidget`

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 切换,bottomNavigationBarScaffold 组件的参数。

BottomNavigationBar 常见的属性:

属性类型含义
itemsList 底部导航条按钮集合
iconSizeicon
currentIndex默认选中第几个
onTap选中变化回调函数
fixedColor选中的颜色
typeBottomNavigationBarTypeBottomNavigationBarType.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,不推荐使用文字
tooltipFAB 被长按时显示,也是无障碍功能
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

属性类型含义
decorationBoxDecoration设置顶部背景颜色
child配置子元素
paddingEdgeInsets内边距
marginEdgeInsets外边距
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

属性类型含义
decorationBoxDecoration设置顶部背景颜色
accountName账户名称
accountEmailEdgeInsets账户邮箱
currentAccountPictureEdgeInsets用户头像
otherAccountsPicturesEdgeInsets用来设置当前账户其他账户头像
marginEdgeInsets外边距

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
controllerTabController 对象
isScrollable是否可滚动
indicatorColor指示器颜色
indicatorWeight指示器高度
indicatorPadding底部指示器的 Padding
indicator指示器 decoration ,例如边框等
indicatorSize指示器大小计算方式:
TabBarIndicatorSize.label文字 等宽
TabBarIndicatorSize.tab 跟每个 tab 等宽
labelColor选中 label 颜色
labelStyle选中 labelStyle
labelPadding每个 labelpadding
unselectedLabelColor未选中 label 颜色
unselectedLabelStyle未选中 labelStyle

Tabbar TabBarView 实现类似头条顶部导航

  1. 混入 SingleTickerProviderStateMixin
class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin{}
  1. 定义 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); //获取点击或滑动页面的索引值
}
});
}
  1. 配置 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
}
}
  1. 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 自定义缓存组件
]
),
);
}
}
  1. preferredSize 组件
Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(50),
child: AppBar(
....
)
), // PreferredSize
body: Text('preferredSize 组件'),
)