6.2 屏幕寬高
6.2.1 系統(tǒng)提供的方法
需要在有context容器中才能使用恩伺,也就是build方法中使用
Widget build(BuildContext context){
final size =MediaQuery.of(context).size;
final width =size.width;
final height =size.height;
}
6.2.2 使用起來最簡單的方法
需要提前定義睬塌,要不然拿不到,方法報錯
import 'dart:ui';
final width = window.physicalSize.width;
final height = window.physicalSize.height;
6.3去掉debug標簽
import 'package:flutter/material.dart';
import './pages/tabs.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
);
}
}
6.4 PreferredSize
此控件不對其子控件施加任何約束,并且不以任何方式影響孩子的布局扎阶。
此控件對自定義AppBar.bottom和AppBar非常有用鳍徽。
PreferredSize 可以改變 appBar 的高度
Scaffold(
// 通過 PreferredSize 來改變 appBar的高度
appBar: PreferredSize(
preferredSize: const Size.fromHeight(50),
child: AppBar(
),
),
)
6.5 保存頁面狀態(tài)
參考:https://blog.csdn.net/qq_14876133/article/details/125393405
AutomaticKeepAliveClientMixin緩存組件
AutomaticKeepAlive 的組件的主要作用是將列表項的根 RenderObject 的 keepAlive 按需自動標記 為 true 或 false潘拱。為了方便敘述,我們可以認為根 RenderObject 對應(yīng)的組件就是列表項的根 Widget参咙,代表整個列表項組件犀农,同時我們將列表組件的 Viewport區(qū)域 + cacheExtent(預(yù)渲染區(qū)域)稱為加載區(qū)域 :
- 當(dāng) keepAlive 標記為 false 時惰赋,如果列表項滑出加載區(qū)域時,列表組件將會被銷毀井赌。
- 當(dāng) keepAlive 標記為 true 時谤逼,當(dāng)列表項滑出加載區(qū)域后,Viewport 會將列表組件緩存起來仇穗;當(dāng)列表項進入加載區(qū)域時流部,Viewport 從先從緩存中查找是否已經(jīng)緩存,如果有則直接復(fù)用纹坐,如果沒有則重新創(chuàng)建列表項枝冀。
封裝組件代碼
import 'package:flutter/material.dart';
class KeepAliveWrapper extends StatefulWidget {
final bool keepAlive;
final Widget child;
const KeepAliveWrapper({Key? key, this.keepAlive = true, required this.child})
: super(key: key);
@override
State<StatefulWidget> createState() {
return _KeepAliveWrapperState();
}
}
class _KeepAliveWrapperState extends State<KeepAliveWrapper>
with AutomaticKeepAliveClientMixin {
@override
Widget build(BuildContext context) {
super.build(context);
return widget.child;
}
@override
void didUpdateWidget(covariant KeepAliveWrapper oldWidget) {
//狀態(tài)發(fā)生變化時調(diào)用
if (oldWidget.keepAlive != widget.keepAlive) {
//更新KeepAlive狀態(tài)
updateKeepAlive();
}
super.didUpdateWidget(oldWidget);
}
@override
bool get wantKeepAlive => widget.keepAlive;
}
在使用的時候,只需要把組件耘子,放到 KeepAliveWrapper 的child中即可果漾。
6.6 配置命名路由
routers.dart
import 'package:flutter/material.dart';
import '../pages/Tabs.dart';
import '../pages/search.dart';
import '../pages/first.dart';
Map routes = {
"/": (context) => const Tabs(),
"/s": (context, {arguments}) => Search(arguments: arguments),
"/f": (context) => const FirstPage(),
};
//固定寫法
var onGenerateRoute = (RouteSettings settings) {
// 統(tǒng)一處理
final String? name = settings.name;
final Function? pageContentBuilder = routes[name];
if (pageContentBuilder != null) {
if (settings.arguments != null) {
final Route route = MaterialPageRoute(
builder: (context) =>
pageContentBuilder(context, arguments: settings.arguments));
return route;
} else {
final Route route =
MaterialPageRoute(builder: (context) => pageContentBuilder(context));
return route;
}
}
};
main.dart
import 'package:flutter/material.dart';
import './tools/routers.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter Demo",
theme: ThemeData(primarySwatch: Colors.blue),
// home: const Tabs(),
initialRoute: "/",
onGenerateRoute: onGenerateRoute,
);
}
}
傳值
import 'package:flutter/material.dart';
class Message extends StatefulWidget {
const Message({super.key});
@override
State<Message> createState() => _MessageState();
}
class _MessageState extends State<Message> {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, "/s",
arguments: {"title": "我是標題", "content": "我是內(nèi)容"});
},
child: const Text("跳轉(zhuǎn)搜索頁面"))
],
),
);
}
}
接收值
import 'package:flutter/material.dart';
class Search extends StatefulWidget {
final Map arguments;
const Search({super.key, required this.arguments});
@override
State<Search> createState() => _SearchState();
}
class _SearchState extends State<Search> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.arguments["title"]),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(widget.arguments["content"]),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text("返回上一頁"))
],
),
);
}
}
6.7 fluttertoast
1、打開網(wǎng)站 https://pub.dev/
2谷誓、搜索 fluttertoast
3绒障、在pubspec.yaml中,的 dependencies 中捍歪,配置 fluttertoast: ^8.0.9
4户辱、導(dǎo)入包:import 'package:fluttertoast/fluttertoast.dart';
5、使用
Fluttertoast.showToast(
msg: "提示信息",
toastLength: Toast.LENGTH_SHORT, // 針對android平臺
gravity: ToastGravity.CENTER, // 方位
timeInSecForIosWeb: 1, // 提示時間
backgroundColor: Colors.red, // 背景顏色
textColor: Colors.white, // 文字顏色
fontSize: 16.0 // 字號
);
6.8 定時器
引入包:
import 'dart:async';
var t = Timer.periodic(const Duration(seconds: 3), (timer) {
print("定時執(zhí)行:" + DateTime.now().toString());
// 取消定時器
// timer.cancel;
});
// 組件銷毀的時候糙臼,取消定時器
void dispose() {
super.dispose();
t.cancel();
}
6.9 key
key
是用來作為Widget
庐镐、Element
和SemanticsNode
的標示,僅僅用來更新widget->key
相同的小部件的狀態(tài)变逃。
主要用于組件的排序必逆,例如listview中,拖動組件,橫豎屏切換
當(dāng)你想要跨widget
樹保留狀態(tài)時 , 應(yīng)該使用key
.
一名眉、LocalKey有三種類型粟矿,用作diff算法的核心所在,用Element和widget進行比較
- ValueKey 以一個數(shù)據(jù)作為Key璧针。如:數(shù)字嚷炉、字符
- ObjectKey 以O(shè)bject對象作為Key
- UniqueKey 可以保證Key的唯一性!(一旦使用Uniquekey那么就不存在Element復(fù)用 了L匠鳌)
二申屹、GlobalKey
- 1、GlobalKey可以獲取到對應(yīng)的Widget的State對象隧膏!
需求:當(dāng)我們頁面內(nèi)容很多時哗讥,而需要改變的內(nèi)容只有很少的一部分且在樹的底層的時候,我們?nèi)绾稳崿F(xiàn)增量更新胞枕?
通常情況下有兩種方式杆煞,
- 第一種是通過方法的回調(diào),去實現(xiàn)數(shù)據(jù)更新腐泻,
- 第二種是通過GlobalKey决乎,在StatelessWidget引用StatefulWidget。
//在statelessWidget中引用statefulWidget更新UI
class GlobalKeyDemo extends StatelessWidget{
// 1派桩、 定義GlobalKey
final GlobalKey<_ChildPageState> _globalKey = GlobalKey();
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('GlobalDemo'),
),
// 2构诚、給子控件設(shè)置key
body: ChildPage(
key: _globalKey,
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: (){
// 3、可以通過 globalKey.currentState 來獲取子組件的屬性和方法
_globalKey.currentState.data = 'old' + _globalKey.currentState.count.toString();
_globalKey.currentState.count++;
_globalKey.currentState.setState(() { });
},
),
);
}
}
class ChildPage extends StatefulWidget{
ChildPage({Key key}):super(key:key);
@override
_ChildPageState createState() => _ChildPageState();
}
class _ChildPageState extends State<ChildPage>{
int count = 0;
String data = 'hello Flutter';
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Column(
children: <Widget>[
Text(count.toString()),
Text(data),
],
),
);
}
}
6.10 Matrix4
參考:https://blog.csdn.net/liu__520/article/details/83796784
- scale:縮放比例 transform: Matrix4.diagonal3Values(2, 10, 1),
- transform: 移動
- rotationZ:繞Z軸旋轉(zhuǎn)
- rotationX:繞X軸旋轉(zhuǎn)
- rotationY:繞Y軸旋轉(zhuǎn)
- columns:設(shè)置一個新的矩陣
- compose:復(fù)合平移铆惑、旋轉(zhuǎn)范嘱、縮放,形成新的狀態(tài)
- copy:復(fù)制一個4*4的張量(矩陣)
- identity:恢復(fù)初始狀態(tài)员魏,也就是4*4的單位矩陣
- inverted:取相反的矩陣丑蛤,就是反著來
- outer(合并)、skew(扭曲)撕阎、skewX(x軸扭曲)受裹、skewY(y軸扭曲)、zero(置零矩陣)虏束、fromList(將一個16位的一維數(shù)組轉(zhuǎn)換成4*4的矩陣)
常用的如下:
6.10.1 縮放
Matrix4.diagonal3Values(1, 1, 1)
表示縮放的比例名斟,分別沿x,y,z三個方向,x軸正向向右魄眉,y軸正向向下,z軸正向從屏幕朝上闷袒,正值表示正向坑律,>1表示放大,小于1大于0表示縮小,負值表示反向晃择。
6.10.2 移動
Matrix4.translationValues
表示平移的距離冀值,分別沿x,y,z三個方向,
x軸正向向右宫屠,
y軸正向向下列疗,
z軸正向從屏幕朝上,
正值表示正向移動浪蹂,負值表示負向移動抵栈,
其中z軸移動在平面上無法看出小錯
6.10.3 旋轉(zhuǎn)
Matrix4.rotationZ(pi / 6)
繞著Z軸旋轉(zhuǎn),正向是順時針坤次,負向是逆時針古劲,
正向也就是從x軸正向往y軸正向旋轉(zhuǎn)
Matrix4.rotationX(pi / 6)
繞著X軸旋轉(zhuǎn),正向是順時針缰猴,負向是逆時針产艾,
正向也就是從y軸正向往z軸正向旋轉(zhuǎn)
Matrix4.rotationY(pi / 6)
繞著Y軸旋轉(zhuǎn),正向是順時針滑绒,負向是逆時針闷堡,
正向也就是從x軸正向往z軸正向旋轉(zhuǎn)
6.11 photo_view
圖片預(yù)覽插件
photo_view: ^0.13.0
簡單使用
Widget _buildPhotoView() {
_galleryItems = [
'assets/images/icon_avatar_staff.png',
'assets/images/icon_avatar_staff.png',
'assets/images/icon_avatar_staff.png'
];
return PhotoViewGallery.builder(
scrollPhysics: const BouncingScrollPhysics(),
builder: (BuildContext context, int index) {
return PhotoViewGalleryPageOptions(
imageProvider: AssetImage(_galleryItems[index]),
initialScale: PhotoViewComputedScale.contained * 0.9,
);
},
itemCount: _galleryItems.length,
backgroundDecoration: const BoxDecoration(color: Colors.white),
pageController: PageController(initialPage: _currentPageIndex),
onPageChanged: (i) {
_currentPageIndex = i;
_valueNotifier.notifyListeners();
},
);
}