共计 5457 个字符,预计需要花费 14 分钟才能阅读完成。
办法一
Offset _offset = Offset.zero;
Scaffold(
body: Stack(
children: [_pageList[_currentIndex],
Positioned(
left: _offset.dx,
top: _offset.dy,
child: GestureDetector(onPanUpdate: (d) =>
setState(() => _offset += Offset(d.delta.dx, d.delta.dy)),
child: FloatingActionButton(onPressed: () {},
backgroundColor: Colors.orange,
child: Icon(Icons.add),
),
),
),
],
),
办法二
WidgetsBinding.instance
.addPostFrameCallback((_) => _insertOverlay(context));
void _insertOverlay(BuildContext context) {return Overlay.of(context).insert(OverlayEntry(builder: (context) {final size = MediaQuery.of(context).size;
print(size.width);
return Positioned(
width: 56,
height: 56,
top: size.height - 72,
left: size.width - 72,
child: Material(
color: Colors.transparent,
child: GestureDetector(onTap: () => print('ON TAP OVERLAY!'),
child: Container(
decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.redAccent),
),
),
),
);
}),
);
}
办法三
1. 场景
当初须要做一个 Test 按钮,悬浮在所有页面之上,并且能够拖拽。
2. 思路
1)悬浮按钮能够应用 flutter 提供的 Overlay + OverlayEntry 组合实现
2)拖拽性能能够应用 GestureDetector 手势按钮或者 Draggable 实现(PS:我做了一版 Draggable 实现的,然而发现它会有本来的 widget 浮在原地,显然不是我要的成果)
3)点击的时候我是让它弹出一个底部弹框,这里你们能够自由发挥,本篇文章不做多余赘述
PubScaffold(
child: MaterialApp(
theme: CustomTheme.lightTheme,
darkTheme: CustomTheme.darkTheme,
themeMode: currentTheme.currentTheme,
home: Scaffold(
body: Stack(
children: [_pageList[_currentIndex],
// Positioned(
// left: _offset.dx,
// top: _offset.dy,
// child: GestureDetector(// onPanUpdate: (d) =>
// setState(() => _offset += Offset(d.delta.dx, d.delta.dy)),
// child: FloatingActionButton(// onPressed: () {},
// backgroundColor: Colors.orange,
// child: Icon(Icons.add),
// ),
// ),
// ),
],
),
bottomNavigationBar: CurvedNavigationBar(
// key: _bottomNavigationKey,
index: 0,
height: 60.0,
items: <Widget>[Icon(Icons.home, size: 30),
Icon(Icons.list, size: 30),
Icon(Icons.compare_arrows, size: 30),
// Icon(Icons.call_split, size: 30),
],
color: Colors.white,
buttonBackgroundColor: Colors.white,
backgroundColor: Colors.blueAccent,
animationCurve: Curves.easeInOut,
animationDuration: Duration(milliseconds: 600),
onTap: (index) {setState(() {_currentIndex = index;});
},
// letIndexChange: (index) => true,
),
),
),
);
这里的 PubScaffold
就是我封装的一个悬浮按钮组件,把它包裹在 MaterialApp 里面,就能够实现悬浮在所有的组件之上的一个按钮啦(当然也能够不是按钮,具体款式能够本人定义)。上面咱们来看一下 PubScaffold
中的代码吧~
import 'dart:math';
import 'package:flutter/material.dart';
class PubScaffold extends StatefulWidget {
final Widget child;
PubScaffold({this.child});
@override
_PubScaffoldState createState() => _PubScaffoldState();
}
class _PubScaffoldState extends State<PubScaffold> {
bool draggable = false;
// 静止状态下的 offset
Offset idleOffset = Offset(0, 0);
// 本次挪动的 offset
Offset moveOffset = Offset(0, 0);
// 最初一次 down 事件的 offset
Offset lastStartOffset = Offset(0, 0);
int count = 0;
final List<String> testWidgetList = [
'测试 1',
'测试 2',
];
testAppFun(e) {// TODO: 你的代码逻辑}
// 显示一个底部弹窗,这里是一个测试列表
showTestList() {
showModalBottomSheet(
context: context,
enableDrag: false,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(topLeft: Radius.circular(20.0),
topRight: Radius.circular(20.0),
),
),
builder: (BuildContext context) {
return ListView(
children: testWidgetList
.map((e) => Container(
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Color(0xFFe3e3e3)),
),
),
child: ListTile(onTap: () => testAppFun(e),
title: Text(e),
),
),
)
.toList(),);
},
);
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
// 显示悬浮按钮
WidgetsBinding.instance
.addPostFrameCallback((_) => _insertOverlay(context));
return widget.child;
},
);
}
// 悬浮按钮,能够拖拽(可自定义款式)void _insertOverlay(BuildContext context) {return Overlay.of(context).insert(OverlayEntry(builder: (context) {final size = MediaQuery.of(context).size;
print(size.width);
return Positioned(
top: draggable ? moveOffset.dy : size.height - 102,
left: draggable ? moveOffset.dx : size.width - 72,
child: GestureDetector(
// 挪动开始
onPanStart: (DragStartDetails details) {setState(() {
lastStartOffset = details.globalPosition;
draggable = true;
});
if (count <= 1) {count++;}
},
// 挪动中
onPanUpdate: (DragUpdateDetails details) {setState(() {
moveOffset =
details.globalPosition - lastStartOffset + idleOffset;
if (count > 1) {moveOffset = Offset(max(0, moveOffset.dx), moveOffset.dy);
} else {moveOffset = Offset(max(0, moveOffset.dx + (size.width - 72)),
moveOffset.dy + (size.height - 102));
}
});
},
// 挪动完结
onPanEnd: (DragEndDetails detail) {setState(() {idleOffset = moveOffset * 1;});
},
child: TestContainer(onPress: () => showTestList(),),
),
);
}),
);
}
}
// 悬浮按钮的款式
class TestContainer extends StatelessWidget {
final Function onPress;
TestContainer({this.onPress});
@override
Widget build(BuildContext context) {
return Material(
color: Colors.transparent,
child: GestureDetector(
onTap: onPress,
child: Container(
width: 56,
height: 56,
alignment: Alignment.center,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.green[600],
),
child: Text(
"Test",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
);
}
}
1. 全局悬浮按钮
这里咱们用的是 flutter 自带的 material 库中的 Overlay 组件,具体应用办法如下:
void _insertOverlay(BuildContext context) {return Overlay.of(context).insert(OverlayEntry(builder: (context) {final size = MediaQuery.of(context).size;
print(size.width);
return Positioned(
top: draggable ? moveOffset.dy : size.height - 102,
left: draggable ? moveOffset.dx : size.width - 72,
child: GestureDetector(
// 挪动开始
onPanStart: (DragStartDetails details) {setState(() {
lastStartOffset = details.globalPosition;
draggable = true;
});
if (count <= 1) {count++;}
},
// 挪动中
onPanUpdate: (DragUpdateDetails details) {setState(() {
moveOffset =
details.globalPosition - lastStartOffset + idleOffset;
if (count > 1) {moveOffset = Offset(max(0, moveOffset.dx), moveOffset.dy);
} else {moveOffset = Offset(max(0, moveOffset.dx + (size.width - 72)),
moveOffset.dy + (size.height - 102));
}
});
},
// 挪动完结
onPanEnd: (DragEndDetails detail) {setState(() {idleOffset = moveOffset * 1;});
},
child: TestContainer(onPress: () => showTestList(),),
),
);
}),
);
}
正文完