【问题标题】:Using json file to give appbar logo for flutter. Facing Loading issue while navigation使用 json 文件为颤振提供 appbar 标志。导航时面临加载问题
【发布时间】:2021-01-25 08:02:16
【问题描述】:

我想为 json 文件中的所有页面显示 appbar 徽标。现在的问题是如果我使用 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,
      ),
    );
  }

}

【问题讨论】:

  • 我将使用bool gotLogo = false 之类的东西,并在从服务器获取实际徽标后设置gotLogo = true。在 Widget 构建部分中,将使用类似 title: !_isSearching &amp;&amp; !gotLogo ? Text('Loading') : !_isSearching &amp;&amp; gotLogo ? FutureBuilder&lt;AppLogo&gt;(.....) : TextFormField(...) 的内容

标签: flutter loading appbar


【解决方案1】:

您可以采取一些方法来减少 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,这样你的logo图片就会被缓存,这样可以减少网络图片的加载时间。

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

小记:对于你_pages列表中的每一个页面,如果你想让页面持久化(不是每次tab切换后都重新加载),你可以使用AutomaticKeepAliveClientMixin来持久化每个页面的状态,或者使用IndexedStacklike:

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

【讨论】:

  • 非常感谢。它就像我想要的那样工作。但是有一个问题。当它第一次加载时,应用程序标志的位置从应用程序栏的中心开始,然后在几秒钟内它自动变为左侧。我希望它显示在左侧。我将 CachedNetworkImage 中的对齐方式用于“Alignment.centerLeft”,但它仍然不起作用。我只是按照您在代码中的建议进行更改。 @巴赫
猜你喜欢
  • 2019-01-05
  • 2019-07-01
  • 2020-10-26
  • 1970-01-01
  • 2020-05-10
  • 2020-12-24
  • 1970-01-01
  • 2019-12-06
  • 1970-01-01
相关资源
最近更新 更多