繁体   English   中英

如何在 Flutter 的 Scaffold 中切换 AppBar?

[英]How to switch AppBar in the Flutter's Scaffold?

我有一种情况,当我在BottomNavigationBar小部件上切换页面时,我的Scaffold中的AppBar需要更改。 一个AppBar是一个普通的AppBar(title: Text('Saved')) ,另一个是AppBarTextField小部件( https://pub.dev/packages/appbar_textfield )。 从这个,我想保留在切换之前已经输入的文本。 但是使用下面的代码,每次我返回相关页面时,该栏都已重置:

import 'package:flutter/material.dart';
import 'package:gifs/screens/main/search.dart';
import 'package:gifs/screens/main/saved.dart';
import 'package:gifs/screens/main/search_appbar.dart';

import '../../models/search_result.dart';

class Navigation extends StatefulWidget {
  Navigation({required Key key}) : super(key: key);

  final SearchResult _searchResult = SearchResult();

  late List<PreferredSizeWidget> _appBars = [
    SearchAppBar(key: GlobalKey(debugLabel: 'search_appbar_ui'), searchResult: _searchResult),
    AppBar(title: Text('Saved'))
  ];

  late List<Widget> _pages = [
    Search(key: GlobalKey(debugLabel: 'search_ui'), searchResult: _searchResult),
    Saved(key: GlobalKey(debugLabel: 'saved_ui')),
  ];

  @override
  _NavigationState createState() => _NavigationState();
}

class _NavigationState extends State<Navigation> {

  int _currentIndex = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: widget._appBars[_currentIndex],
      body: IndexedStack(
        index: _currentIndex,
        children: widget._pages,
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Search'),
          BottomNavigationBarItem(icon: Icon(Icons.favorite), label: 'Saved'),
        ],
        onTap: (index) => {
          setState(() {
            _currentIndex = index;
          })
        }
      ),
    );
  }
}

这是SearchBar代码:

import 'package:flutter/material.dart';
import 'package:gifs/models/search_result.dart';
import 'package:appbar_textfield/appbar_textfield.dart';


class SearchAppBar extends StatefulWidget with PreferredSizeWidget {

  final SearchResult searchResult;

  const SearchAppBar({required Key key, required this.searchResult}) : super(key: key);

  @override
  _SearchAppBarState createState() => _SearchAppBarState();

  @override
  Size get preferredSize => Size.fromHeight(kToolbarHeight);
}

class _SearchAppBarState extends State<SearchAppBar> {

  @override
  void initState() {
    super.initState();
  }

    @override
    Widget build(BuildContext context) {
      return AppBarTextField(
        title: Text("Enter a search term"),
        onBackPressed: _onRestoreAllData,
        onClearPressed: _onRestoreAllData,
        onChanged: _onSearchChanged,
      );
    }

  void _onSearchChanged(String value) {
    widget.searchResult.searchTerm(value);
  }

  void _onRestoreAllData() {
    _onSearchChanged('');
  }

}

如您所见,我根据索引切换_appBars ,但每次切换后栏中的文本都会消失。 有没有办法保持其当前状态?

试试这个:我无法运行您自己的代码,但我在入门 flutter 应用程序中测试了我的解决方案并且它有效(代码在最后提供)

这是您修改后的Navigation小部件代码:

import 'package:flutter/material.dart';
import 'package:gifs/screens/main/search.dart';
import 'package:gifs/screens/main/saved.dart';
import 'package:gifs/screens/main/search_appbar.dart';

import '../../models/search_result.dart';

class Navigation extends StatefulWidget {
  Navigation({required Key key}) : super(key: key);

  @override
  _NavigationState createState() => _NavigationState();
}

class _NavigationState extends State<Navigation> {

  int _currentIndex = 0;
  
  final SearchResult _searchResult = SearchResult();

  List<PreferredSizeWidget> get _appBars => [
    SearchAppBar(
      key: GlobalKey(debugLabel: 'search_appbar_ui'), 
      searchResult: _searchResult,
      setSearchResult: (String value) {
        //set your string value of the SearchResult class
        setState(() => _searchResult.term = value);
      }
    ),
    AppBar(title: Text('Saved'))
  ];

  List<Widget> get _pages => [
    Search(key: GlobalKey(debugLabel: 'search_ui'), searchResult: _searchResult),
    Saved(key: GlobalKey(debugLabel: 'saved_ui')),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: widget._appBars[_currentIndex],
      body: IndexedStack(
        index: _currentIndex,
        children: widget._pages,
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Search'),
          BottomNavigationBarItem(icon: Icon(Icons.favorite), label: 'Saved'),
        ],
        onTap: (index) => {
          setState(() {
            _currentIndex = index;
          })
        }
      ),
    );
  }
}

关于我所做的注释:

  • 我将您的_appBars_pages_searchResult变量移动到您的 state class 并删除了后期初始化并使它们成为吸气剂。
  • 我使用 setSearchResult function 运行 setState 以保留字段输入的值(请参阅下一个代码片段注释)

这是您修改后的SearchAppBar小部件代码:

import 'package:flutter/material.dart';
import 'package:gifs/models/search_result.dart';
import 'package:appbar_textfield/appbar_textfield.dart';


class SearchAppBar extends StatefulWidget with PreferredSizeWidget {

  final SearchResult searchResult;
  final ValueChanged<String> setSearchResult;

  const SearchAppBar({required Key key, required this.searchResult, required this.setSearchResult}) : super(key: key);

  @override
  _SearchAppBarState createState() => _SearchAppBarState();

  @override
  Size get preferredSize => Size.fromHeight(kToolbarHeight);
}

class _SearchAppBarState extends State<SearchAppBar> {

  @override
  void initState() {
    super.initState();
  }

    @override
    Widget build(BuildContext context) {
      return AppBarTextField(
        title: Text("Enter a search term"),
        onBackPressed: _onRestoreAllData,
        onClearPressed: _onRestoreAllData,
        onChanged: _onSearchChanged,
        // Give your string value of the SearchResult class
        // as an initial value to your text field.
        // If this was a regular TextFormField() widget you would
        // have been able to use the initialValue param, but I'm not
        // sure if there's a better alternative than using the 
        // controller for this package
        controller: TextEditingController()..text = widget.searchResult.term,
      );
    }

  void _onSearchChanged(String value) {
    widget.setSearchResult(value);
  }

  void _onRestoreAllData() {
    _onSearchChanged('');
  }

}

关于我所做的注释:

  • 我在AppBarTextFieldonChanged参数中调用了widget.setSearchResult function 来更新父小部件中的值
  • 非常重要:我将widget.searchResult的字符串值作为初始值分配给文本字段,这样当您重新访问页面时,它会再次分配给文本字段而不会丢失。

如果您想尝试一下,这是我在沙盒应用程序中的代码:(将其放在 dartpad 中并运行它,您应该会看到它在工作)

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: _title,
      home: MyStatefulWidget(),
    );
  }
}

class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({Key? key}) : super(key: key);

  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  String searchResult = '';

  List<PreferredSizeWidget> get _appBars => [
        SearchAppBar(
          setSearchResult: (String value) =>
              setState(() => searchResult = value),
          searchResult: searchResult,
        ),
        AppBar(title: const Text('Saved')),
      ];

  int _selectedIndex = 0;
  static const TextStyle optionStyle =
      TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
  static const List<Widget> _widgetOptions = <Widget>[
    Text(
      'Index 0: Home',
      style: optionStyle,
    ),
    Text(
      'Index 1: Business',
      style: optionStyle,
    ),
  ];

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: _appBars[_selectedIndex],
      body: Center(
        child: _widgetOptions.elementAt(_selectedIndex),
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
            backgroundColor: Colors.red,
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.business),
            label: 'Business',
            backgroundColor: Colors.green,
          ),
        ],
        currentIndex: _selectedIndex,
        selectedItemColor: Colors.amber[800],
        onTap: _onItemTapped,
      ),
    );
  }
}

class SearchAppBar extends StatefulWidget with PreferredSizeWidget {
  final String searchResult;
  final ValueChanged<String> setSearchResult;

  const SearchAppBar({required this.setSearchResult, this.searchResult = ''});

  @override
  _SearchAppBarState createState() => _SearchAppBarState();

  @override
  Size get preferredSize => const Size.fromHeight(56);
}

class _SearchAppBarState extends State<SearchAppBar> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      onChanged: _onSearchChanged,
      controller: TextEditingController()..text = widget.searchResult,
//       initialValue: widget.searchResult,
    );
  }

  void _onSearchChanged(String value) {
    widget.setSearchResult(value);
  }
}

希望这可以帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM