使用 json 文件为 flutter 提供 appbar 徽标。导航时面临加载问题

Using json file to give appbar logo for flutter. Facing Loading issue while navigation

我想为 json 文件中的所有页面显示应用栏徽标。现在的问题是如果我使用 Futurebuilder 然后在每次页面加载时,appbar 标志在显示之前等待。我尝试使用共享偏好但遇到问题。也许我做错了。我是颤振的新手。如果可能,请用简单的方式给出答案,以便我理解。或者任何人都可以通过为 appbar 创建该部分来帮助我。这会很有帮助。

Here is my json file for logo

import 'dart:convert';
import 'package:models/app_logo.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import './home_screen.dart';
import './login_screen.dart';
import '../constants.dart';
import '../screens/courses_screen.dart';
import '../screens/my_courses_screen.dart';
import '../screens/my_wishlist_screen.dart';
import '../screens/account_screen.dart';
import '../widgets/filter_widget.dart';
import '../providers/auth.dart';
import 'package:http/http.dart' as http;

class TabsScreen extends StatefulWidget {
  @override
  _TabsScreenState createState() => _TabsScreenState();
}

class _TabsScreenState extends State<TabsScreen> {
  List<Widget> _pages = [
    HomeScreen(),
    LoginScreen(),
    LoginScreen(),
    LoginScreen(),
  ];
  var _isInit = true;
  var _isLoading = false;

  int _selectedPageIndex = 0;
  bool _isSearching = false;
  final searchController = TextEditingController();

  Future<AppLogo> futureLogo;

  Future<AppLogo> fetchMyLogo() async {
    var url = BASE_URL + '/app_logo';
    try {
      final response = await http.get(url);
      print(response.body);
      if (response.statusCode == 200) {
        // If the server did return a 200 OK response,
        // then parse the JSON.
        print(response.body);
        return AppLogo.fromJson(jsonDecode(response.body));
      }
      // print(extractedData);
    } catch (error) {
      throw (error);
    }
  }

  @override
  void initState() {
    super.initState();
    this.fetchMyLogo();
    // Provider.of<Auth>(context).tryAutoLogin().then((_) {});
  }

  @override
  void didChangeDependencies() {
    if (_isInit) {
      setState(() {
        _isLoading = true;
      });

      final _isAuth = Provider.of<Auth>(context, listen: false).isAuth;

      if (_isAuth) {
        _pages = [
          HomeScreen(),
          MyCoursesScreen(),
          MyWishlistScreen(),
          AccountScreen(),
        ];
      }
    }
    _isInit = false;
    super.didChangeDependencies();
  }

  void _handleSubmitted(String value) {
    final searchText = searchController.text;
    if (searchText.isEmpty) {
      return;
    }

    searchController.clear();
    Navigator.of(context).pushNamed(
      CoursesScreen.routeName,
      arguments: {
        'category_id': null,
        'seacrh_query': searchText,
        'type': CoursesPageData.Search,
      },
    );
    // print(searchText);
  }

  void _selectPage(int index) {
    setState(() {
      _selectedPageIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        iconTheme: IconThemeData(
          color: kSecondaryColor, //change your color here
        ),
        title: !_isSearching
            ? FutureBuilder<AppLogo>(
          future: fetchMyLogo(),
          builder: (context, snapshot) {
            if (snapshot.connectionState ==
                ConnectionState.waiting) {
              return Center(
                child: Container(),
              );
            } else {
              if (snapshot.error != null) {
                return Center(
                  child: Text("Error Occured"),
                );
              } else {
                return Image.network(
                  snapshot.data.darkLogo,
                  fit: BoxFit.contain,
                  height: 27,
                );
              }
            }
          },
        )
        : TextFormField(
          decoration: InputDecoration(
            labelText: 'Search Here',
            prefixIcon: Icon(
              Icons.search,
              color: Colors.grey,
            ),
          ),
          controller: searchController,
          onFieldSubmitted: _handleSubmitted,
        ),
        backgroundColor: kBackgroundColor,
          actions: <Widget>[
            IconButton(
                icon: Icon(
                  Icons.search,
                  color: kSecondaryColor,
                ),
                onPressed: () {
                  setState(() {
                    _isSearching = !_isSearching;
                  });
                }),
          ],
      ),
      body: _pages[_selectedPageIndex],
      floatingActionButton: FloatingActionButton(
        onPressed: () => _showFilterModal(context),
        child: Icon(Icons.filter_list),
        backgroundColor: kDarkButtonBg,
      ),
      bottomNavigationBar: BottomNavigationBar(
        onTap: _selectPage,
        items: [
          BottomNavigationBarItem(
            backgroundColor: kBackgroundColor,
            icon: Icon(Icons.school),
            title: Text('Course'),
          ),
          BottomNavigationBarItem(
            backgroundColor: kBackgroundColor,
            icon: Icon(Icons.shopping_basket),
            title: Text('My Course'),
          ),
          BottomNavigationBarItem(
            backgroundColor: kBackgroundColor,
            icon: Icon(Icons.favorite_border),
            title: Text('Wishlist'),
          ),
          BottomNavigationBarItem(
            backgroundColor: kBackgroundColor,
            icon: Icon(Icons.account_circle),
            title: Text('Account'),
          ),
        ],
        backgroundColor: kBackgroundColor,
        unselectedItemColor: kSecondaryColor,
        selectedItemColor: kSelectItemColor,
        currentIndex: _selectedPageIndex,
        type: BottomNavigationBarType.fixed,
      ),
    );
  }

}

您可以通过一些方法来减少徽标在 AppBar 中的加载时间。由于此 AppBar 在选项卡之间是通用的,因此您应该只加载一次,避免每次更改选项卡时都重新加载。

首先是用StreamBuilder代替FutureBuilder来减少加载次数

// Create a StreamController
final _controller = StreamController<AppLogo>();

// Run fetchMyLogo() in your initState() like in your code

// In your fetchMyLogo(), add the result to the stream
fetchMyLogo() async {

    // ... other lines

    if (response.statusCode == 200) {
      // If the server did return a 200 OK response,
      // then parse the JSON.
      var logo = AppLogo.fromJson(jsonDecode(response.body));
      _controller.add(logo);
    }

// Then, listen to this logo in your StreamBuilder
 @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(

        // ... other lines

        title: !_isSearching
            ? StreamBuilder<AppLogo>(
          stream: _controller.stream,
          builder: (context, snapshot) {

          // ... other lines

其次是使用 cached_network_image 而不是 Image.network,以便缓存您的徽标图像,从而减少网络图像的加载时间。

return CachedNetworkImage(
          imageUrl: snapshot.data.darkLogo,
          fit: BoxFit.contain,
          height: 27,
       );

小提示:对于你_pages列表中的每个页面,如果你想让页面持久化(而不是在每次标签更改后重新加载),你可以使用 AutomaticKeepAliveClientMixin 来保持每个页面的状态,或者使用 IndexedStack 像:

// The IndexedStack will load all pages initially
body: IndexedStack(
        children: _pages,
        index: _selectedPageIndex,
      ),
// ... other lines