Skip to content

title disappears when bottom is provided in SliverAppBar.large #115091

@JGeek00

Description

@JGeek00

#91605

I'm experimenting a weird behavior with the SliverAppBar.large (with .medium is the same) while using a widget on the bottom of it. I hope someone can help me. I don't know if it's an issue on the new appbars or it's my fault (probably the second, but I don't know how to solve it and I don't find any information on the Internet). See the examples below.

Example 1: TabBar under SliverAppBar

On this first example I want to use a TabBar with a SliverAppBar.large. With the SliverAppBar (normal) it works fine.

TabBar with SliverAppBar
https://user-images.githubusercontent.com/47545344/201158640-8f655be1-f594-47fd-a540-c469e88c070e.mp4

Code Sample
return DefaultTabController(
      length: 2,
      child: NestedScrollView(
        controller: scrollController,
        headerSliverBuilder: ((context, innerBoxIsScrolled) {
          return [
            SliverOverlapAbsorber(
              handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
              sliver: SliverSafeArea(
                top: false,
                sliver: SliverAppBar(
                  title: Text(AppLocalizations.of(context)!.clients),
                  pinned: true,
                  floating: true,
                  forceElevated: innerBoxIsScrolled,
                  actions: [
                    if (serversProvider.clients.loadStatus == 1) ...[
                      IconButton(
                        onPressed: () => {
                          Navigator.push(context, MaterialPageRoute(
                            builder: (context) => const SearchClients()
                          ))
                        }, 
                        icon: const Icon(Icons.search),
                        tooltip: AppLocalizations.of(context)!.searchClients,
                      ),
                      const SizedBox(width: 10),
                    ]
                  ],
                  bottom: TabBar(
                    controller: tabController,
                    unselectedLabelColor: Theme.of(context).colorScheme.onSurfaceVariant,
                    tabs: [
                      Tab(
                        icon: const Icon(Icons.devices),
                        text: AppLocalizations.of(context)!.activeClients,
                      ),
                      Tab(
                        icon: const Icon(Icons.add_rounded),
                        text: AppLocalizations.of(context)!.added,
                      ),
                    ]
                  )
                ),
              ),
            )
          ];
        }), 
        body: Container(
          decoration: BoxDecoration(
            color: Theme.of(context).scaffoldBackgroundColor,
            border: Border(
              top: BorderSide(
                color: Theme.of(context).colorScheme.onSurface.withOpacity(0.1)
              )
            )
          ),
          child: TabBarView(
            controller: tabController,
            children: [
              RefreshIndicator(
                onRefresh: fetchClients,
                child: ClientsList(
                  scrollController: scrollController,
                  loadStatus: serversProvider.clients.loadStatus,
                  data: serversProvider.clients.loadStatus == 1
                    ? serversProvider.clients.data!.autoClientsData : [],
                  fetchClients: fetchClients,
                ),
              ),
              RefreshIndicator(
                onRefresh: fetchClients,
                child: AddedList(
                  scrollController: scrollController,
                  loadStatus: serversProvider.clients.loadStatus,
                  data: serversProvider.clients.loadStatus == 1
                    ? serversProvider.clients.data!.clients : [], 
                  fetchClients: fetchClients,
                )
              ),
            ]
          )
        ),
      )
    );

TabBar with SliverAppBar.large
https://user-images.githubusercontent.com/47545344/201158826-64da326e-2e07-4744-90f6-beeb4c888fc0.mp4
The code is the same as before but replacing SliverAppBar with SliverAppBar.large

Example 2: SliverAppBar.large with a row of Chips under it.

With the normal AppBar it works fine.
https://user-images.githubusercontent.com/47545344/201159956-07150070-6b55-4ef3-b87a-6ab899b257c5.mp4

Code Sample
    return Scaffold(
      appBar: AppBar(
        title: Text(AppLocalizations.of(context)!.logs),
        actions: [
          logsProvider.loadStatus == 1 
            ? IconButton(
                onPressed: openFilersModal, 
                icon: const Icon(Icons.filter_list_rounded)
              )
            : const SizedBox(),
          IconButton(
            onPressed: () => {
              showModalBottomSheet(
                context: context, 
                builder: (context) => LogsConfigModal(
                  onConfirm: updateConfig,
                  onClear: clearQueries,
                ),
                backgroundColor: Colors.transparent,
                isScrollControlled: true
              )
            }, 
            icon: const Icon(Icons.settings)
          ),
          const SizedBox(width: 5),
        ],
        bottom: logsProvider.appliedFilters.searchText != null || logsProvider.appliedFilters.selectedResultStatus != 'all'
          ? PreferredSize(
              preferredSize: const Size(double.maxFinite, 50),
              child: Container(
                height: 50,
                width: double.maxFinite,
                padding: const EdgeInsets.only(bottom: 10),
                decoration: BoxDecoration(
                  border: Border(
                    bottom: BorderSide(
                      color: showDivider == true
                        ? Theme.of(context).dividerColor
                        : Colors.transparent,
                    )
                  )
                ),
                child: ListView(
                  scrollDirection: Axis.horizontal,
                  children: [
                    if (logsProvider.appliedFilters.searchText != null) ...[
                      const SizedBox(width: 15),
                      Chip(
                        avatar: Icon(
                          Icons.search,
                          size: 24,
                          color: Theme.of(context).primaryColor,
                        ),
                        label: Row(
                          children: [
                            Text(
                              logsProvider.appliedFilters.searchText!,
                              style: const TextStyle(
                                fontSize: 14,
                                fontWeight: FontWeight.w500
                              ),
                            ),
                          ],
                        ),
                        deleteIcon: Icon(
                          Icons.cancel_rounded,
                          size: 18,
                          color: Theme.of(context).colorScheme.onSurfaceVariant
                        ),
                        onDeleted: () {
                          logsProvider.setAppliedFilters(
                            AppliedFiters(
                              selectedResultStatus: logsProvider.appliedFilters.selectedResultStatus, 
                              searchText: null
                            )
                          );
                          logsProvider.setSearchText(null);
                          fetchLogs(
                            inOffset: 0,
                            searchText: ''
                          );
                        },
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(8),
                          side: BorderSide(
                            color: Theme.of(context).colorScheme.onSurfaceVariant
                          )
                        ),
                        backgroundColor: Theme.of(context).dialogBackgroundColor,
                      ),
                    ],
                    if (logsProvider.appliedFilters.selectedResultStatus != 'all') ...[
                      const SizedBox(width: 15),
                      Chip(
                        avatar: Icon(
                          Icons.shield_rounded,
                          size: 24,
                          color: Theme.of(context).primaryColor,
                        ),
                        label: Row(
                          children: [
                            Text(
                              translatedString[logsProvider.appliedFilters.selectedResultStatus]!,
                              style: const TextStyle(
                                fontSize: 14,
                                fontWeight: FontWeight.w500
                              ),
                            ),
                          ],
                        ),
                        deleteIcon: Icon(
                          Icons.cancel_rounded,
                          size: 18,
                          color: Theme.of(context).colorScheme.onSurfaceVariant
                        ),
                        onDeleted: () {
                          logsProvider.setAppliedFilters(
                            AppliedFiters(
                              selectedResultStatus: 'all', 
                              searchText: logsProvider.appliedFilters.searchText
                            )
                          );
                          logsProvider.setSelectedResultStatus('all');
                          fetchLogs(
                            inOffset: 0,
                            responseStatus: 'all'
                          );
                        },
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(8),
                          side: BorderSide(
                            color: Theme.of(context).colorScheme.onSurfaceVariant
                          )
                        ),
                        backgroundColor: Theme.of(context).dialogBackgroundColor,
                      ),
                    ],
                    const SizedBox(width: 15),
                  ],
                ),
              )
            )
        : null,
      ),
      body: // The body goes here
    );

With a SliverAppBar.large
https://user-images.githubusercontent.com/47545344/201160558-1e39e45b-98f8-4315-b571-a99ec67b3c4b.mp4

Code Sample
 return Scaffold(
      body: NestedScrollView(
        controller: scrollController,
        headerSliverBuilder: (_, __) => [
          SliverAppBar.large(
            title: Text(AppLocalizations.of(context)!.logs),
            actions: [
              logsProvider.loadStatus == 1 
                ? IconButton(
                    onPressed: openFilersModal, 
                    icon: const Icon(Icons.filter_list_rounded)
                  )
                : const SizedBox(),
              IconButton(
                onPressed: () => {
                  showModalBottomSheet(
                    context: context, 
                    builder: (context) => LogsConfigModal(
                      onConfirm: updateConfig,
                      onClear: clearQueries,
                    ),
                    backgroundColor: Colors.transparent,
                    isScrollControlled: true
                  )
                }, 
                icon: const Icon(Icons.settings)
              ),
              const SizedBox(width: 5),
            ],
            bottom: logsProvider.appliedFilters.searchText != null || logsProvider.appliedFilters.selectedResultStatus != 'all'
              ? PreferredSize(
                  preferredSize: const Size(double.maxFinite, 50),
                  child: Container(
                    height: 50,
                    width: double.maxFinite,
                    padding: const EdgeInsets.only(bottom: 10),
                    decoration: BoxDecoration(
                      border: Border(
                        bottom: BorderSide(
                          color: showDivider == true
                            ? Theme.of(context).dividerColor
                            : Colors.transparent,
                        )
                      )
                    ),
                    child: ListView(
                      scrollDirection: Axis.horizontal,
                      children: [
                        if (logsProvider.appliedFilters.searchText != null) ...[
                          const SizedBox(width: 15),
                          Chip(
                            avatar: Icon(
                              Icons.search,
                              size: 24,
                              color: Theme.of(context).primaryColor,
                            ),
                            label: Row(
                              children: [
                                Text(
                                  logsProvider.appliedFilters.searchText!,
                                  style: const TextStyle(
                                    fontSize: 14,
                                    fontWeight: FontWeight.w500
                                  ),
                                ),
                              ],
                            ),
                            deleteIcon: Icon(
                              Icons.cancel_rounded,
                              size: 18,
                              color: Theme.of(context).colorScheme.onSurfaceVariant
                            ),
                            onDeleted: () {
                              logsProvider.setAppliedFilters(
                                AppliedFiters(
                                  selectedResultStatus: logsProvider.appliedFilters.selectedResultStatus, 
                                  searchText: null
                                )
                              );
                              logsProvider.setSearchText(null);
                              fetchLogs(
                                inOffset: 0,
                                searchText: ''
                              );
                            },
                            shape: RoundedRectangleBorder(
                              borderRadius: BorderRadius.circular(8),
                              side: BorderSide(
                                color: Theme.of(context).colorScheme.onSurfaceVariant
                              )
                            ),
                            backgroundColor: Theme.of(context).dialogBackgroundColor,
                          ),
                        ],
                        if (logsProvider.appliedFilters.selectedResultStatus != 'all') ...[
                          const SizedBox(width: 15),
                          Chip(
                            avatar: Icon(
                              Icons.shield_rounded,
                              size: 24,
                              color: Theme.of(context).primaryColor,
                            ),
                            label: Row(
                              children: [
                                Text(
                                  translatedString[logsProvider.appliedFilters.selectedResultStatus]!,
                                  style: const TextStyle(
                                    fontSize: 14,
                                    fontWeight: FontWeight.w500
                                  ),
                                ),
                              ],
                            ),
                            deleteIcon: Icon(
                              Icons.cancel_rounded,
                              size: 18,
                              color: Theme.of(context).colorScheme.onSurfaceVariant
                            ),
                            onDeleted: () {
                              logsProvider.setAppliedFilters(
                                AppliedFiters(
                                  selectedResultStatus: 'all', 
                                  searchText: logsProvider.appliedFilters.searchText
                                )
                              );
                              logsProvider.setSelectedResultStatus('all');
                              fetchLogs(
                                inOffset: 0,
                                responseStatus: 'all'
                              );
                            },
                            shape: RoundedRectangleBorder(
                              borderRadius: BorderRadius.circular(8),
                              side: BorderSide(
                                color: Theme.of(context).colorScheme.onSurfaceVariant
                              )
                            ),
                            backgroundColor: Theme.of(context).dialogBackgroundColor,
                          ),
                        ],
                        const SizedBox(width: 15),
                      ],
                    ),
                  )
                )
            : null,
          ),
        ],
        body: // Body goes here
      ),
    );

Flutter analyze

Logs
   info • 'androidOverscrollIndicator' is deprecated and shouldn't be used. Use ThemeData.useMaterial3 or override
          ScrollBehavior.buildOverscrollIndicator. This feature was deprecated after v2.13.0-0.0.pre. • lib/config/theme.dart:76:3 •
          deprecated_member_use
   info • 'androidOverscrollIndicator' is deprecated and shouldn't be used. Use ThemeData.useMaterial3 or override
          ScrollBehavior.buildOverscrollIndicator. This feature was deprecated after v2.13.0-0.0.pre. • lib/config/theme.dart:157:3
          • deprecated_member_use
   info • 'androidOverscrollIndicator' is deprecated and shouldn't be used. Use ThemeData.useMaterial3 or override
          ScrollBehavior.buildOverscrollIndicator. This feature was deprecated after v2.13.0-0.0.pre. • lib/config/theme.dart:254:3
          • deprecated_member_use
   info • 'androidOverscrollIndicator' is deprecated and shouldn't be used. Use ThemeData.useMaterial3 or override
          ScrollBehavior.buildOverscrollIndicator. This feature was deprecated after v2.13.0-0.0.pre. • lib/config/theme.dart:358:3
          • deprecated_member_use
   info • Unused import: 'package:intl/intl.dart' • lib/functions/conversions.dart:1:8 • unused_import
   info • Unused import: 'package:bottom_sheet/bottom_sheet.dart' • lib/screens/filters/fab.dart:5:8 • unused_import
   info • Unused import: 'dart:io' • lib/screens/filters/update_interval_lists_modal.dart:1:8 • unused_import
   info • Unused import: 'package:adguard_home_manager/widgets/custom_list_tile.dart' • lib/screens/logs/log_details_screen.dart:3:8
          • unused_import
   info • Unused import: 'package:adguard_home_manager/functions/format_time.dart' • lib/screens/logs/logs_filters_modal.dart:14:8 •
          unused_import
   info • The declaration 'selectTime' isn't referenced • lib/screens/logs/logs_filters_modal.dart:68:10 • unused_element
   info • Unused import: 'package:adguard_home_manager/screens/settings/appbar.dart' • lib/screens/settings/settings.dart:15:8 •
          unused_import
   info • Unused import: 'package:adguard_home_manager/config/system_overlay_style.dart' • lib/widgets/add_server_modal.dart:15:8 •
          unused_import

Flutter doctor

Logs
[✓] Flutter (Channel stable, 3.3.7, on macOS 12.6.1 21G217 darwin-arm, locale es-ES)
    • Flutter version 3.3.7 on channel stable at /Users/juan/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision e99c9c7cd9 (9 days ago), 2022-11-01 16:59:00 -0700
    • Engine revision 857bd6b74c
    • Dart version 2.18.4
    • DevTools version 2.15.0

[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
    • Android SDK at /Users/juan/Library/Android/sdk
    • Platform android-33, build-tools 31.0.0
    • ANDROID_HOME = /Users/juan/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 14.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 14B47b
    • CocoaPods version 1.11.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)

[✓] VS Code (version 1.73.0)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.52.0

[✓] Connected device (3 available)
    • sdk gphone64 arm64 (mobile) • emulator-5554 • android-arm64  • Android 13 (API 33) (emulator)
    • macOS (desktop)             • macos         • darwin-arm64   • macOS 12.6.1 21G217 darwin-arm
    • Chrome (web)                • chrome        • web-javascript • Google Chrome 107.0.5304.87

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work lista: qualityA truly polished experiencef: material designflutter/packages/flutter/material repository.f: scrollingViewports, list views, slivers, etc.found in release: 3.3Found to occur in 3.3found in release: 3.6Found to occur in 3.6frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onr: fixedIssue is closed as already fixed in a newer version

Type

No type

Projects

Status

Done (PR merged)

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions