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 这个作用是界面绘制完成的监听回调 必须在绘制完成后添加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.创建
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
typedef CallBlock = void Function();
class Application {
///应用全局 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;
///拖动结束
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是不能重复使用的,所以Key一般用来做唯一标识。组件在更新的时候,其状态的保存主要是通过判断组件的类型或者key值是否一致。
GlobalKey
:
局部键(LocalKey):ValueKey、ObjectKey、UniqueKey
全局键(GlobalKey):GlobalObjectKey
GlobalKey是全局唯一的键,一般而言,GlobalKey有如下几种用途:
用途1:获取配置、状态以及组件位置尺寸等信息
(1)_globalKey.currentWidget:获取当前组件的配置信息(存在widget树中)
(2)_globalKey.currentState:获取当前组件的状态信息(存在Element树中)
(3)_globalKey.currentContext:获取当前组件的大小以及位置信息。
用途2:实现控件的局部刷新
将需要单独刷新的widget从复杂的布局中抽离出去,然后通过传GlobalKey引用,这样就可以通过GlobalKey实现跨组件的刷新了。
navigatorKey
:
navigatorKey 相当于 Navigator.of(context) ,如果应用程序想实现无 context 跳转,那么可以通过设置该key, 通过 navigatorKey.currentState.overlay.context 获取全局context。
3.2 overlay[2]
Overlay是一个可以管理的堆栈。我们可以通过将一个Widget插入这个堆栈中,这样就可以让此Widget浮在其他的Widget之上,从而实现悬浮窗效果。我们可以通过OverlayEntry对象的配置来管理Overlay的层级关系。
OverlayEntry 是一个定义Widget
网友评论