полоса приложений с функцией поиска во флаттере - PullRequest
3 голосов
/ 03 августа 2020

надеюсь, у тебя хороший день. Я хочу добиться чего-то вроде этого ниже => gif-изображение 1

, для которых gif непонятен. Это снимок экрана из приложения под названием Yelp. это полосатая панель приложения с расширением и сворачиванием. когда он сворачивается, панель поиска фиксируется на заголовке. в любом случае я уже сделал это => gif image 2

моя панель поиска сжимается, когда я сворачиваю панель приложения. Я хочу, чтобы поиск не сжимался, когда я сворачиваю полосу приложения и исправляю строку поиска в заголовке выше. это мой код

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,
            ),
          ),
        );
      }),
    );
  }
}

любая помощь приветствуется.

1 Ответ

7 голосов
/ 03 августа 2020

Это решение, чтобы зафиксировать панель поиска и предотвратить ее сжатие:

Вы можете использовать два SilverAppBar s, один для фонового изображения и один для поиска бар. Первый 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,
          ),
        ),
      ),
    );
  }

Результат:

res

This is a solution to make a layout based on 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;
}

Результат:

res2

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...