簡體   English   中英

flutter 中具有搜索功能的 sliver 應用欄

[英]sliver app bar with search functionality in flutter

希望你有美好的一天。 我想在下面實現這樣的東西=> gif image 1

誰的 gif 不清楚。它是來自名為Yelp的應用程序的屏幕截圖。 它是帶有擴展和折疊功能的銀色應用欄。 當它折疊搜索欄固定到標題。 無論如何,到目前為止我已經完成了這個 => gif image 2

當我折疊 sliver 應用欄時,我的搜索欄正在縮小。 我希望當我折疊 sliver 應用欄並修復上面標題中的搜索欄時,搜索不會縮小。 這是我的代碼

import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  double changingHeight;
  double appBarHeight;
  bool appBarSearchShow = false;
  final TextEditingController _filter = new TextEditingController();

  List<String> itemList = [];

  @override
  void initState() {
    for (int count = 0; count < 50; count++) {
      itemList.add("Item $count");
    }
    changingHeight = 300;
  }

  @override
  Widget build(BuildContext context) {
    appBarHeight = MediaQuery.of(context).padding.top + kToolbarHeight;
    return Scaffold(
      backgroundColor: Colors.white,
      body: NestedScrollView(
          headerSliverBuilder: (BuildContext context, bool innerBoxScrolled) {
            return <Widget>[createSilverAppBar()];
          },
          body: ListView.builder(
              itemCount: itemList.length,
              itemBuilder: (context, index) {
                return Card(
                  child: ListTile(
                    title: Text(itemList[index]),
                  ),
                );
              })),
    );
  }

  SliverAppBar createSilverAppBar() {
    return SliverAppBar(
      backgroundColor: Colors.white,
      expandedHeight: 300,
      floating: false,
      pinned: true,
      // title: appBarSearchShow == true
      //     ? CupertinoTextField(
      //         controller: _filter,
      //         keyboardType: TextInputType.text,
      //         placeholder: "Search..",
      //         placeholderStyle: TextStyle(
      //           color: Color(0xffC4C6CC),
      //           fontSize: 14.0,
      //           fontFamily: 'Brutal',
      //         ),
      //         prefix: Padding(
      //           padding: const EdgeInsets.fromLTRB(9.0, 6.0, 9.0, 6.0),
      //           child: Icon(
      //             Icons.search,
      //           ),
      //         ),
      //         decoration: BoxDecoration(
      //           borderRadius: BorderRadius.circular(8.0),
      //           color: Colors.white,
      //         ),
      //       )
      //     : Container(),
      flexibleSpace: LayoutBuilder(
          builder: (BuildContext context, BoxConstraints constraints) {
        if (constraints.biggest.height == appBarHeight) {
          appBarSearchShow = true;
        } else {
          appBarSearchShow = false;
        }
        return FlexibleSpaceBar(
          collapseMode: CollapseMode.parallax,
          titlePadding: EdgeInsets.only(bottom: 10),
          centerTitle: true,
          title: constraints.biggest.height != appBarHeight
              ? Container(
                  //margin: EdgeInsets.symmetric(horizontal: 10),
                  constraints: BoxConstraints(minHeight: 30, maxHeight: 30),
                  width: 220,
                  decoration: BoxDecoration(
                    boxShadow: <BoxShadow>[
                      BoxShadow(
                          color: Colors.grey.withOpacity(0.6),
                          offset: const Offset(1.1, 1.1),
                          blurRadius: 5.0),
                    ],
                  ),
                  child: CupertinoTextField(
                    controller: _filter,
                    keyboardType: TextInputType.text,
                    placeholder: 'Search',
                    placeholderStyle: TextStyle(
                      color: Color(0xffC4C6CC),
                      fontSize: 14.0,
                      fontFamily: 'Brutal',
                    ),
                    prefix: Padding(
                      padding: const EdgeInsets.fromLTRB(5.0, 5.0, 0.0, 5.0),
                      child: Icon(
                        Icons.search,
                        size: 18,
                      ),
                    ),
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(8.0),
                      color: Colors.white,
                    ),
                  ),
                )
              : Container(),
          background: Container(
            //height: constraints.maxHeight - 15,
            color: Colors.white,
            margin: EdgeInsets.only(bottom: 30),
            child: Image.asset(
              'assets/mainBackImage.jpg',
              fit: BoxFit.cover,
            ),
          ),
        );
      }),
    );
  }
}

任何幫助,將不勝感激。

這是使搜索欄固定並阻止其縮小的解決方案:

您可以使用兩個SilverAppBar ,一個用於背景圖像,一個用於搜索欄。 第一個SilverAppBar沒有標題和標高,也沒有固定。 第二個SilverAppBar已固定並具有高度,其標題是SearchBar

 @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: NestedScrollView(
          headerSliverBuilder: (BuildContext context, bool innerBoxScrolled) {
            return <Widget>[
              createSilverAppBar1(),
              createSilverAppBar2()
            ];
          },
          body: ListView.builder(
              itemCount: itemList.length,
              itemBuilder: (context, index) {
                return Card(
                  child: ListTile(
                    title: Text(itemList[index]),
                  ),
                );
              })),
    );
  }

  SliverAppBar createSilverAppBar1() {
    return SliverAppBar(
      backgroundColor: Colors.redAccent,
      expandedHeight: 300,
      floating: false,
      elevation: 0,
      flexibleSpace: LayoutBuilder(
          builder: (BuildContext context, BoxConstraints constraints) {
            return FlexibleSpaceBar(
              collapseMode: CollapseMode.parallax,
              background: Container(
                color: Colors.white,
                child: Image.asset(
                  'assets/mainBackImage.jpg',
                  fit: BoxFit.cover,
                ),
              ),
            );
          }),
    );
  }

  SliverAppBar createSilverAppBar2() {
    return SliverAppBar(
      backgroundColor: Colors.redAccent,
      pinned: true,
      title: Container(
        margin: EdgeInsets.symmetric(horizontal: 10),
        height: 40,
        decoration: BoxDecoration(
          boxShadow: <BoxShadow>[
            BoxShadow(
                color: Colors.grey.withOpacity(0.6),
                offset: const Offset(1.1, 1.1),
                blurRadius: 5.0),
          ],
        ),
        child: CupertinoTextField(
          controller: _filter,
          keyboardType: TextInputType.text,
          placeholder: 'Search',
          placeholderStyle: TextStyle(
            color: Color(0xffC4C6CC),
            fontSize: 14.0,
            fontFamily: 'Brutal',
          ),
          prefix: Padding(
            padding: const EdgeInsets.fromLTRB(5.0, 5.0, 0.0, 5.0),
            child: Icon(
              Icons.search,
              size: 18,
              color: Colors.black,
            ),
          ),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(8.0),
            color: Colors.white,
          ),
        ),
      ),
    );
  }

結果:

資源

這是基於gif 圖像 1進行布局的解決方案

使用Stack ,您可以將搜索欄堆疊在背景之上。 搜索欄的偏移量將是expandedHeight - shrinkOffset - 20 ,因為它應該取決於應用欄縮小的程度以及應用欄未縮小時的總高度。 20 是搜索欄高度的一半,減去它以使搜索欄向上移動一半高度。

@override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: NestedScrollView(
          headerSliverBuilder: (BuildContext context, bool innerBoxScrolled) {
            return <Widget>[
              SliverPersistentHeader(
                delegate: MySliverAppBar(expandedHeight: 200, filter: _filter),
                pinned: true,
              ),
            ];
          },
          body: ListView.builder(
              itemCount: itemList.length,
              itemBuilder: (context, index) {
                return Card(
                  child: ListTile(
                    title: Text(itemList[index]),
                  ),
                );
              })),
    );
  }

class MySliverAppBar extends SliverPersistentHeaderDelegate {
  final double expandedHeight;
  final TextEditingController filter;
  MySliverAppBar({@required this.expandedHeight, @required this.filter});
  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    var searchBarOffset = expandedHeight - shrinkOffset - 20;
    return Stack(
      fit: StackFit.expand,
      overflow: Overflow.visible,
      children: [
        Container(
          child: Image.network(
            'assets/mainBackImage.jpg',
            fit: BoxFit.cover,
          ),
        ),
        (shrinkOffset < expandedHeight - 20) ? Positioned(
          top: searchBarOffset,
          left: MediaQuery.of(context).size.width / 4,
          child: Card(
            elevation: 10,
            child: SizedBox(
            height: 40,
            width: MediaQuery.of(context).size.width / 2,
            child: CupertinoTextField(
              controller: filter,
              keyboardType: TextInputType.text,
              placeholder: 'Search',
              placeholderStyle: TextStyle(
                color: Color(0xffC4C6CC),
                fontSize: 14.0,
                fontFamily: 'Brutal',
              ),
              prefix: Padding(
                padding: const EdgeInsets.fromLTRB(5.0, 5.0, 0.0, 5.0),
                child: Icon(
                  Icons.search,
                  size: 18,
                  color: Colors.black,
                ),
              ),
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(8.0),
                color: Colors.white,
              ),
            ),
          ),
          ),
        ) : Container(
          margin: EdgeInsets.symmetric(
              horizontal: MediaQuery.of(context).size.width / 4,
              vertical: (kToolbarHeight - 40) / 4
          ),
          child: Card(
            elevation: 10,
            child: CupertinoTextField(
              controller: filter,
              keyboardType: TextInputType.text,
              placeholder: 'Search',
              placeholderStyle: TextStyle(
                color: Color(0xffC4C6CC),
                fontSize: 14.0,
                fontFamily: 'Brutal',
              ),
              prefix: Padding(
                padding: const EdgeInsets.fromLTRB(5.0, 5.0, 0.0, 5.0),
                child: Icon(
                  Icons.search,
                  size: 18,
                  color: Colors.black,
                ),
              ),
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(8.0),
                color: Colors.white,
              ),
            ),
          ),
        ),
      ],
    );
  }

  @override
  double get maxExtent => expandedHeight;

  @override
  double get minExtent => kToolbarHeight;

  @override
  bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
}

結果:

資源2

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM