- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
最近写代码的时候遇到了一个如下的需求:
整体来说,底部的条是一个浮动的悬浮窗,有如下的三个按钮:
首先是这个窗口该如何创建的问题,显然需要Overlay悬浮在整个窗口顶部.
但是不能直接写在initState内,这样会触发“Build时重绘”的错误。所以我们可以利用 WidgetsBinding ,来监听 Callback ,这样可以保证在首页Build完成时能够立刻绘制这个悬浮的窗口.
/rootpage
@override
void didChangeDependencies() {
print('root didChangeDependencies');
super.didChangeDependencies();
var widgetsBinding = WidgetsBinding.instance;
widgetsBinding.addPostFrameCallback((callback) {
print('addPostFrameCallback');
PNavigationBar.show(context, _tabController);
});
}
我将这个放入到了 didChangeDependencies 内,主要是想通过混入 TickerProviderStateMixin 能够在路由回来时重新触发 didChangeDependencies ,不过理想很丰满。最后在实验的过程中反倒没有触发,没有找到原因,希望有感兴趣的大佬可以指点一下.
理论参考: Flutter 小而美系列|TickerProviderStateMixin 对生命周期的影响 - 掘金 (juejin.cn) 。
首先说最简单的TabView部分 。
@override
Widget build(BuildContext context) {
return Scaffold(
body: TabBarView(
controller: _tabController,
children: [
HomePage(),
UserPage(),
],
),
);
}
这里需要一个TabController,相信比较熟悉的朋友们也知道,需要混入TickerProviderStateMixin,才可以声明 。
画框的部分是主要部分.
(具体的代码在本文最后) 。
整个PNavigationBar的实现非常简单,定义了一个show,一个remove,一个refresh方法,这样可以保证任何组件任何页面都可以随时控制PNavigationBar的出现和消失.
因为NavigationBar是存在切换图标的功能的,而我们通过Image.asset获取的图标却没办法更新,所以我们需要手动调用 overlayEntry.markNeedsBuild 方法,来对整个底部组件进行重绘 。
相信大家也会有最初跟我一样的疑问,因为TabBar与TabView,还有TabController的数必须一致,而我们中间有一个自定义的加号按钮,我在这里的实现非常简单粗暴,当然如果有更好的方法欢迎大佬指教.
我这里只是通过简单的运算,来将两个组件分别控制在左边和右边,之后加号按钮在中间.
当然整个TabBar的渲染逻辑其实是有问题的,想要更深入地改TabBar的排列方式,必须需要自己手写一个TabBar。默认的排列方式就是放到 Expanded 内的,具体参考了以下这篇博客:
Flutter系列之设置TabBar的tab紧凑排列_flutter tabbar间隔-CSDN博客 。
最难的部分就是这里,主要在于如何控制路由到其他界面就可以消失,再pop回来就可以显示.
我们希望这些功能都可以在RootPage这一层实现,而不在各种子页面的push和pop中增添代码负担.
具体实现起来最初我的尝试是 didChangeDependencies ,但是最后实验下来并没有结果,我自己也并不知道原因。(小白是这样的) 。
而我最终决定采用原始的NavigationObserver方法,这里感谢这个组件替我实现了这个功能:
lifecycle_lite | Flutter Package (pub.dev) 。
于是可以通过简单的onShow和onHide就可以实现啦! 。
当然还有很多细节都没有提到,写这个功能时遇到的问题也有不少,本人技术有限,能力有限。等代码再优化的时候可以作为库开源给大家。现在就暂且以这种博客的形式分享组件和代码.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:picturebook/pages/test/test_page.dart';
import '../color_utils.dart';
class PNavigationBar {
static OverlayEntry? overlayEntry;
static show(BuildContext context, TabController tabController) {
var overlayState = Overlay.of(context);
overlayEntry = OverlayEntry(
maintainState: true,
builder: (BuildContext context) {
final size = MediaQuery.of(context).size;
final height = size.height;
final width = size.width;
final boxWidth = width * 0.46;
final boxHeight = 60.h;
final iconHeight = 45.h;
return Positioned(
bottom: height * 0.06,
left: (width - boxWidth) / 2,
right: (width - boxWidth) / 2,
child: Stack(
children: [
Container(
decoration: BoxDecoration(
color: ColorUtils.orange,
borderRadius: BorderRadius.circular(boxHeight / 2),
),
width: boxWidth,
height: boxHeight,
child: TabBar(
controller: tabController,
indicatorColor: Colors.transparent,
padding: EdgeInsets.zero,
onTap: (index) {
tabController.animateTo(index);
overlayEntry?.markNeedsBuild();
},
tabs: [
Padding(
padding: EdgeInsets.only(right: iconHeight / 3),
child: Container(
width: iconHeight,
height: iconHeight,
decoration: BoxDecoration(
color: Colors.white30,
borderRadius: BorderRadius.circular(iconHeight / 2),
),
child: Center(
child: Image.asset(
tabController.index == 0
? 'assets/home_1.png'
: 'assets/home_0.png',
width: iconHeight * 0.5,
)),
),
),
Padding(
padding: EdgeInsets.only(left: iconHeight / 3),
child: Container(
width: iconHeight,
height: iconHeight,
decoration: BoxDecoration(
color: Colors.white30,
borderRadius: BorderRadius.circular(iconHeight / 2),
),
child: Center(
child: Image.asset(
tabController.index == 1
? 'assets/user_1.png'
: 'assets/user_0.png',
width: iconHeight * 0.5,
)),
),
),
],
)),
Align(
alignment: Alignment.center,
child: Padding(
padding: EdgeInsets.only(top: (boxHeight - iconHeight) / 2),
child: InkWell(
onTap: () {
print('push');
Navigator.push(
context,
MaterialPageRoute(builder: (context) => TestPage()),
);
},
child: Container(
width: iconHeight,
height: iconHeight,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(iconHeight / 2),
),
child: Center(
child: Image.asset(
'assets/add.png',
width: iconHeight * 0.5,
)),
),
),
),
),
],
),
);
},
);
overlayState.insert(overlayEntry!);
}
static remove() {
if (overlayEntry != null) {
overlayEntry!.remove();
}
}
static refresh(){
overlayEntry?.markNeedsBuild();
}
}
下面是使用的实例,非常优美简洁:
import 'package:flutter/material.dart';
import 'package:lifecycle_lite/lifecycle_mixin.dart';
import 'package:picturebook/pages/home_page.dart';
import 'package:picturebook/pages/user_page.dart';
import 'package:picturebook/utils/navigation/navigation_util.dart';
class RootPage extends StatefulWidget {
const RootPage({super.key});
@override
State<RootPage> createState() => _RootPageState();
}
class _RootPageState extends State<RootPage>
with TickerProviderStateMixin, LifecycleStatefulMixin {
late TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(length: 2, vsync: this)..addListener(() {
PNavigationBar.refresh();
});
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
var widgetsBinding = WidgetsBinding.instance;
widgetsBinding.addPostFrameCallback((callback) {
PNavigationBar.show(context, _tabController);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: TabBarView(
controller: _tabController,
children: [
HomePage(),
UserPage(),
],
),
);
}
@override
void whenHide() {
PNavigationBar.remove();
}
@override
void whenShow() {
PNavigationBar.show(context, _tabController);
}
}
最后此篇关于【Flutter】如何优美地实现一个悬浮NavigationBar的文章就讲到这里了,如果你想了解更多关于【Flutter】如何优美地实现一个悬浮NavigationBar的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我需要管理嵌入在使用标准、浅色、模糊层的 NavigationController 中的两个 ViewController 之间的转换。应用程序这部分中的所有 ViewController 看起来都非
我有一个包含 3 个不同 NavigationController 的 Storyboard: 在第一个 NavigationController 的根 Controller 中,我在代码中添加了一个
先说说我的情况。我在我的 appDelegate 中设置了 UINavigationBar 颜色,例如: [[UINavigationBar appearance] setBarTintColor:[
这两种说法有什么区别。为了隐藏导航栏,我使用以下语句之一在 viewWillAppear 方法中隐藏导航栏,如下所示: -(void)viewWillAppear:(BOOL)animated {
目前我找不到任何方法来更改 SwiftUI 中导航栏的颜色/背景。有小费吗? 最佳答案 为了改变所有 View Controller 的导航栏颜色,你必须在 AppDelegate.swift 中设置
我可以自定义 QlPreviewController Controller 中导航栏的颜色吗? 我尝试过以下 [[UINavigationBar appearanceWhenContainedIn:
我正在开发一款带有 webview 布局的安卓游戏。我想在用户玩游戏时隐藏导航栏。我找到了一些解决方案,但是当我触摸屏幕时,导航栏出现了。 我做错了什么?这是我的无效解决方案: int mUIFla
我的导航栏上有这种奇怪的行为: 而且我不知道如何解决它。 我在 Storyboard上的设置是: 我希望条形颜色清晰,以便获得完美的模糊效果。 有任何想法吗? 感谢您的关注。 最佳答案 尝试这些设置可
我正在尝试实现一种 AlertWindow 类的东西,我正在使用 WindowsManager 的实例从服务。 View 可见且可访问。但是屏幕上 NavigationBar 上的后退/主页按钮似乎没
我想隐藏NavigationBar和stateBar以显示全屏图像,但似乎navigationBar并未完全隐藏: 代码如下: [[UIApplication sharedApplication]
我找不到关于如何使用 完成此操作的任何文档组件...基本上,当我的一个场景加载时,我希望能够传递一个 route.navBarColor到我的导航器,它将自动更改栏的背景颜色。 我尝试使用 {nav
我正在向导航栏层添加渐变,并且效果很好。当我推送另一个 View Controller 和弹出 View Controller 时,问题就来了。父 View Controller 有右边的条形按钮项目
我在 iOS 7 模拟器和设备上都遇到了一个奇怪的图形问题。 在按下 TableView 中的单元格后,我以编程方式从 Storyboard 中调用 segue: [self performSegue
我有一个 NavigationViewController,它的根是一个普通的 UIViewController。我通过以下方式以编程方式呈现 TableViewController: self.pe
我有 2 个 VC。在这两种情况下,我都将代码编写为 NavigationController 外观,但是当我从第二个 VC 返回到第一个时,我的一切都是黑色的...... 第一位风投: overri
我正在使用带有 UITableView 的普通 View Controller ,它嵌入到导航 Controller 中,导航 Controller 嵌入到标签栏 Controller 中: 标签栏
我的 Storyboard中有一个导航栏,并设置了以下约束: Horizontal Space - (-16) - View Navigation Bar Horizontal Space - (-1
我的结构如下: ContainerView --embed segue--> NavigationController --> UITableViewController A --push segue
嘿,我在 UINavigationController 中有一堆 UIViewController。通常,标题(或 NavigationItem 的标题)决定了 NavigationBar 中显示的标
Second Image 问题是当我弹出我的 Controller 时,导航栏变成黑色,这非常烦人。需要帮助! 最佳答案 当您弹出屏幕时,您会回到上一屏幕。在预览屏幕中,您必须在 viewWillAp
我是一名优秀的程序员,十分优秀!