flutter全局浮動按鈕
1.添加
import 'package:flutter/material.dart';
import 'first.dart';
import 'Application.dart';
void main() {
Application.initKey();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
// routes: RouteGenerator.routes,
navigatorKey: Application.globalKey,
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
OverlayEntry? overlayEntry;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
///WidgetsBinding.instance.addPostFrameCallback 這個作用是界面繪制完成的監(jiān)聽回調(diào) 必須在繪制完成后添加OverlayEntry
///MediaQuery.of(context).size.width 屏幕寬度
///MediaQuery.of(context).size.height 屏幕高度
print('開始添加');
// addOverlayEntry(MediaQuery.of(context).size.width - 180, MediaQuery.of(context).size.height - 180);
// addOverlayEntry( 180, 180);
Application.addOverlayEntry(10, 200);
Application.callBlock = () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FirstVC(),
));
};
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
children: [
],
),
);
}
}
2.創(chuàng)建
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
typedef CallBlock = void Function();
class Application {
///應(yīng)用全局 key
static GlobalKey<NavigatorState> ?globalKey ;//= GlobalKey<NavigatorState>();
static OverlayEntry ?overlayEntry;
static bool hideChild = false;
static CallBlock ? callBlock;
static double dx = 10;
static double dy = 200;
static bool isChange = false;
static changeChildShow (){
hideChild = false;
Future.delayed(Duration(milliseconds: 200)).then((e) {
Application.addOverlayEntry(dx, dy);
});
}
static initKey(){
GlobalKey<NavigatorState> globalKey = new GlobalKey<NavigatorState>();
Application.globalKey = globalKey;
}
static getStopColor(){
if (isChange) {
return Colors.transparent;
}
return Colors.black;
}
static Future addOverlayEntry(double left, double top) async {
Application.overlayEntry?.remove();
overlayEntry = OverlayEntry(
builder: (BuildContext context) => Positioned(
top: top,
left: left,
child: GestureDetector(
onTap: () async{
print('點擊');
if (callBlock != null) {
callBlock!();
hideChild = true;
}
},
child: Offstage(
offstage: hideChild,
child: Draggable(
onDragUpdate: (DragUpdateDetails details){
isChange = true;
},
onDragEnd: (DraggableDetails details) {
isChange = false;
///拖動結(jié)束
dx = details.offset.dx;
dy = details.offset.dy;
if (dx < 10) {
dx = 10;
}
else if (dx >= MediaQuery.of(context).size.width - 40) {
dx = MediaQuery.of(context).size.width-40;
}
else if (dx <= MediaQuery.of(context).size.width/2) {
dx = 10;
}
else if (dx > MediaQuery.of(context).size.width /2) {
dx = MediaQuery.of(context).size.width-40;
}
if (dy < 100) {
dy = 100;
}
if (dy > MediaQuery.of(context).size.height - 140) {
dy = MediaQuery.of(context).size.height - 140;
}
addOverlayEntry( dx, dy);
},
///feedback是拖動時跟隨手指滑動的Widget驾凶。
feedback: Container(width: 30,height: 30,color: Colors.black,),
///child是靜止時顯示的Widget柔袁,
child: Container(width: 30,height: 30,color: getStopColor(),)),
)
),
)
);
/// 賦值 方便移除
Application.overlayEntry = overlayEntry;
if (Application.globalKey!.currentState != null) {
Application.globalKey!.currentState!.overlay!.insert(overlayEntry!);
}
}
}
3.知識點
3.1 key [1]
key
:在Flutter中悴侵,Key是不能重復(fù)使用的,所以Key一般用來做唯一標(biāo)識。組件在更新的時候,其狀態(tài)的保存主要是通過判斷組件的類型或者key值是否一致斩松。
GlobalKey
:
局部鍵(LocalKey):ValueKey、ObjectKey担租、UniqueKey
全局鍵(GlobalKey):GlobalObjectKey
GlobalKey是全局唯一的鍵砸民,一般而言抵怎,GlobalKey有如下幾種用途:
用途1:獲取配置奋救、狀態(tài)以及組件位置尺寸等信息
(1)_globalKey.currentWidget:獲取當(dāng)前組件的配置信息(存在widget樹中)
(2)_globalKey.currentState:獲取當(dāng)前組件的狀態(tài)信息(存在Element樹中)
(3)_globalKey.currentContext:獲取當(dāng)前組件的大小以及位置信息。
用途2:實現(xiàn)控件的局部刷新
將需要單獨刷新的widget從復(fù)雜的布局中抽離出去反惕,然后通過傳GlobalKey引用尝艘,這樣就可以通過GlobalKey實現(xiàn)跨組件的刷新了。
navigatorKey
:
navigatorKey 相當(dāng)于 Navigator.of(context) 姿染,如果應(yīng)用程序想實現(xiàn)無 context 跳轉(zhuǎn)背亥,那么可以通過設(shè)置該key, 通過 navigatorKey.currentState.overlay.context 獲取全局context秒际。
3.2 overlay[2]
Overlay是一個可以管理的堆棧。我們可以通過將一個Widget插入這個堆棧中狡汉,這樣就可以讓此Widget浮在其他的Widget之上娄徊,從而實現(xiàn)懸浮窗效果。我們可以通過OverlayEntry對象的配置來管理Overlay的層級關(guān)系盾戴。
OverlayEntry 是一個定義Widget