如何在FutureBuilder完成数据加载前优先加载bottom navigation bar等静态元素
实现FutureBuilder加载前优先渲染底部导航栏的方案
问题根源
你现有代码中将包含bottomNavigationBar、悬浮按钮的完整Scaffold放在了FutureBuilder的请求成功分支中,因此导航栏等静态元素必须等接口返回后才会渲染,不符合预期。
实现思路
将所有静态不变的元素(底部导航栏、悬浮按钮、悬浮按钮位置配置等)放在外层Scaffold,仅把需要动态加载的内容区域交给FutureBuilder控制,进入页面时静态元素会第一时间渲染,只有中间内容区域会根据请求状态显示加载动画/错误提示/实际内容。
修改后代码
import 'dart:io'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'package:package/constants/AppConstants.dart'; import 'package:package/util/HttpActions.dart'; import 'BottomAppBar.dart'; import 'FAB.dart'; class HomePage extends StatefulWidget { final String jwt; const HomePage(this.jwt); @override _HomePage createState() => _HomePage(); factory HomePage.fromBase64(String jwt) => HomePage(jwt); } class _HomePage extends State<HomePage> { late final String jwt; // 提前定义请求Future,避免每次build重复发起请求 late Future<http.Response> _requestFuture; @override void initState() { super.initState(); jwt = widget.jwt; final uri = Uri.http( AppConstants.BASE_URL, AppConstants.SOME_URL, {'email': 'some.mail@gmail.com'}); // TODO change to proper link // 初始化时就发起请求 _requestFuture = http.get( uri, headers: { HttpHeaders.contentTypeHeader: HttpActions.APPLICATION_JSON_HEADER, HttpHeaders.authorizationHeader: jwt }, ); } @override Widget build(BuildContext context) => Scaffold( backgroundColor: const Color(0xFEF9F9FC), // 静态元素直接放在外层Scaffold,进入页面立刻渲染 floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, floatingActionButton: buildFAB(), bottomNavigationBar: BuildBottomAppBar(), // 仅body部分交给FutureBuilder动态控制 body: Center( child: FutureBuilder( future: _requestFuture, builder: (context, snapshot) { if (snapshot.hasData) { // 这里直接返回请求成功后你要展示的内容组件,不需要再套Scaffold return 你请求成功后的页面内容组件; } else if (snapshot.hasError) { return const Text("An error occurred"); } else { return const CircularProgressIndicator(); } } ), ), ); }
注意事项
- 不要直接在FutureBuilder的
future参数中创建请求实例,否则页面每次重绘都会重复发起接口请求,提前在initState中初始化请求即可避免该问题 - 成功分支无需再嵌套Scaffold,直接返回你原本要放在body区域的业务内容组件即可
内容的提问来源于stack exchange,提问作者kpoads
相关产品推荐
相关产品推荐

