实战
图片加载
yaml
flutter:
assets:
- assets/1.pngdart
@override
Widget build(BuildContext context) {
return Scaffold(
// body: const HttpStudy(),
// body: _dyWidget,
body: Stack(
children: [
Positioned.fill(
// Positioned.fill 会填充整个屏幕/父组件
child: Image.asset('assets/1.png', fit: BoxFit.cover,),
),
// 图片上添加遮罩
Positioned.fill(
child: Container(
decoration: const BoxDecoration(color: Colors.black87),
),
),
],
),
);
}屏幕适配
dart
import 'package:flutter/cupertino.dart';
// 屏幕宽度适配
class ScreenHelper {
static late MediaQueryData _mediaQueryData;
static late double screenWith;
static late double screenHeight;
static late double ratio;
///根据设计稿实际宽度初始化
///basewidth设计稿宽度
static init(BuildContext context, {double basewidth = 375}) {
_mediaQueryData = MediaQuery.of(context);
screenWith = _mediaQueryData.size.width;
screenHeight = _mediaQueryData.size.height;
ratio = screenWith / basewidth;
}
///获取设计稿对应的大小
static double getPx(double size) {
return ScreenHelper.ratio * size;
}
}
//扩展int以方便使用
extension IntFix on int {
// eg:200.px
double get px {
return ScreenHelper.getPx(toDouble());
}
}
//扩展int以方便使用
extension DoubleFix on double {
// eg:200.0.px
double get px {
return ScreenHelper.getPx(this);
}
}
// 使用
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context){
ScreenHelper.init(context);
return Container(
width:200.px,
height:200.1.px,
)
}
}首页tab页面切换
- PageView + BottomNavigationBar 实现首页tab页面切换
- AutomaticKeepAliveClientMixin 保持页面状态
dart
class _MyHomePageState extends State<MyHomePage> with AutomaticKeepAliveClientMixin{
// with AutomaticKeepAliveClientMixin 保持页面状态
final PageController _pageController = PageController(
// 打开页面默认显示第0页
initialPage: 0,
);
int _currentIndex = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
controller: _pageController,
// 禁用左右滑动切换页面
// physics: NeverScrollableScrollPhysics(),
children: [Text('页面1'), Text('页面2'), Text('页面3')],
onPageChanged: (index) {
setState(() {
_currentIndex = index;
});
},
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
// 选中后样式
type: BottomNavigationBarType.fixed,
fixedColor: Colors.blue,
onTap: (index) {
setState(() {
_currentIndex = index;
});
_pageController.jumpToPage(index);
},
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
activeIcon: Icon(Icons.home_outlined),
label: '首页',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
activeIcon: Icon(Icons.business_outlined),
label: '业务',
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
activeIcon: Icon(Icons.school_outlined),
label: '学习',
),
],
),
);
}
// 保持页面状态
@override
bool get wantKeepAlive => true;
}轮播图
移除 ListView 顶部灵动岛间距
dart
MediaQuery.removePadding(context:context, removeTop: true, child:_listView)ListView 滚动时设置 AppBar 背景颜色
dart
return Scaffold(
body: MediaQuery.removePadding(
context: context,
removeTop: true,
child: NotificationListener(
onNotification: (notification) {
// 当 ListView 滚动时,会触发多种通知(如开始、更新、结束等)
// 这里只处理滚动更新通知,打印当前滚动位置(notification.metrics.pixels)
if (notification is ScrollUpdateNotification) {
// ListView 里面还会有 ListView 滚动
// depth 表示嵌套层级,判断最外层的滚动
if(notification.depth == 0) {
print(notification.metrics.pixels);
final offsetTop = notification.metrics.pixels;
// 滚动距离 / appbar高度
double alpha = offsetTop / 100;
if(alpha > 1) {
alpha = 1;
} else if(alpha < 0) {
alpha = 0;
}
setState(() {
// _appBarAlpha = alpha;
});
}
}
// 返回 true 表示继续处理其他通知,返回 false 表示停止处理
return true;
},
child: ListView(children: [Text('页面1'), Text('页面2'), Text('页面3')]),
),
),
);ListView 水平方向滚动
dart
ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 10,
itemBuilder: (context, index) {
return Container(
width: 100,
height: 100,
color: Colors.primaries[index % Colors.primaries.length],
);
},
)ExpansionTile 展开收缩
dart
return Scaffold(
body: ListView(
children: [
ExpansionTile(
title: Text('标题'),
children: [
FractionallySizedBox(
// 设置宽度为1,即占满父容器宽度
widthFactor: 1,
child: Container(
decoration: const BoxDecoration(color: Colors.red),
child: Text('内容'),
),
),
],
),
ExpansionTile(
title: Text('标题'),
children: [
FractionallySizedBox(
// 设置宽度为1,即占满父容器宽度
widthFactor: 1,
child: Container(
decoration: const BoxDecoration(color: Colors.red),
child: Text('内容'),
),
),
],
),
],
),
);GridView 网格布局
dart
Widget build(BuildContext context) {
return Scaffold(
body: GridView.count(
// 每行多少列
crossAxisCount: 2,
children: [
// EdgeInsets 设置外边距
Container(height: 80,margin: const EdgeInsets.all(5), decoration: BoxDecoration(color: Colors.red)),
Container(height: 80,margin: const EdgeInsets.all(5), decoration: BoxDecoration(color: Colors.red)),
Container(height: 80,margin: const EdgeInsets.all(5), decoration: BoxDecoration(color: Colors.red)),
Container(height: 80,margin: const EdgeInsets.all(5), decoration: BoxDecoration(color: Colors.red)),
],
),
);
}下拉刷新和上拉加载更多
dart
import 'package:flutter_easyrefresh/easy_refresh.dart';
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late EasyRefreshController _controller;
@override
void initState() {
super.initState();
_controller = EasyRefreshController();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: EasyRefresh.custom(
controller: _controller,
header: ClassicalHeader(
refreshText: '下拉刷新',
refreshReadyText: '释放刷新',
refreshingText: '正在刷新...',
refreshedText: '刷新完成',
moreText: '上拉加载更多',
moreReadyText: '释放加载',
loadingText: '正在加载...',
noMoreText: '没有更多数据',
),
footer: ClassicalFooter(
loadText: '加载更多',
loadReadyText: '释放加载',
loadingText: '正在加载...',
loadedText: '加载完成',
noMoreText: '没有更多数据',
),
onRefresh: () async {
// 刷新回调
await Future.delayed(Duration(seconds: 2));
_controller.finishRefresh();
},
onLoad: () async {
// 加载回调
await Future.delayed(Duration(seconds: 2));
_controller.finishLoad(noMore: true);
},
slivers: <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
height: 50,
child: Text('item $index'),
);
},
childCount: 20,
),
),
],
),
);
}
}RefreshIndicator 下拉刷新
dart
import 'package:flutter/material.dart';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: RefreshIndicator(
onRefresh: () async {
// 模拟刷新耗时(如网络请求),延迟 2 秒后再继续,让用户看到刷新动画。
await Future.delayed(Duration(seconds: 2));
return;
},
child: ListView.builder(
itemCount: 20,
itemBuilder: (context, index) {
return ListTile(
title: Text('item $index'),
);
},
),
),
);
}
}ScrollController 滚动加载更多
dart
import 'package:flutter/material.dart';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late ScrollController _scrollController;
@override
void initState() {
super.initState();
_scrollController = ScrollController();
_scrollController.addListener(() {
// 滚动到底部,加载更多
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
// 模拟加载耗时(如网络请求),延迟 2 秒后再继续,让用户看到加载动画。
Future.delayed(Duration(seconds: 2)).then((value) {
setState(() {
// 加载更多数据
//...
});
});
}
});
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
controller: _scrollController,
itemCount: 20,
itemBuilder: (context, index) {
return ListTile(
title: Text('item $index'),
);
},
),
);
}
}