skip to Main Content

Here is my code want to impliment custom header which is gose up when user scroll.
and stick tabbar to top and bottom view widget will show.. for that i user Sliver Widgets..

here is code Snaipts.

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

  @override
  State<ProfileMyGroupDetailsScreen> createState() => _ProfileMyGroupDetailsScreenState();
}

class _ProfileMyGroupDetailsScreenState extends State<ProfileMyGroupDetailsScreen> with SingleTickerProviderStateMixin {
  TabController? _tabController;

  @override
  void initState() {
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      _tabController = TabController(initialIndex: 0, length: 4, vsync: this);
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: CustomChatAppBar(
        title: AppLabels.myGroupDetails,
        systemOverlayStyle: Global.whiteOverLay,
        actions: [],
      ),
      body: buildDataTabWidget(),
    );
  }

  DefaultTabController buildDataTabWidget() {
    return DefaultTabController(
      length: 4,
      child: CustomScrollView(
        slivers: [
          SliverToBoxAdapter(
            child: Column(
              children: [
                ListTileType1(
                  padding: padXY(24, 8.5),
                  imageUrl: AppImages.dummyProfileImage1,
                  imageWidth: 44,
                  imageHeight: 44,
                  title1: 'Meme team',
                  title2: 'Jack & Chris',
                ),
                Padding(
                  padding: padXY(24, 16),
                  child: CustomImage(
                    imageUrl: AppImages.dummyProfileImage1,
                    height: MediaQuery.of(context).size.width - (24 * 2),
                    width: MediaQuery.of(context).size.width,
                    fit: BoxFit.cover,
                    borderRadius: 12,
                  ),
                ),
              ],
            ),
          ),
          SliverPersistentHeader(
            pinned: true,
            delegate: _SliverAppBarDelegate(
              TabBar(
                controller: _tabController,
                dividerColor: AppColors.kBorderColor,
                dividerHeight: 2,
                isScrollable: true,
                padding: EdgeInsets.zero,
                tabAlignment: TabAlignment.center,
                indicatorSize: TabBarIndicatorSize.tab,
                indicatorWeight: 1,
                labelColor: AppColors.kSecondaryColor,
                unselectedLabelColor: AppColors.kAppGrey,
                labelStyle: context.bodyLarge.w500,
                unselectedLabelStyle: context.bodyLarge,
                onTap: (index) {
                  // moduleDetailController.selectedIndex.value = index;
                  // moduleDetailController.selectedIndex.refresh();
                },
                tabs: [
                  Tab(text: AppLabels.basicInformation),
                  Tab(text: AppLabels.myLikes),
                  Tab(text: AppLabels.matches),
                  Tab(text: AppLabels.sentRequests),
                ],
              ),
            ),
          ),
          SliverFillRemaining(
            child: TabBarView(
              controller: _tabController,
              children: [
                BuildBasicInfoTab(),
                MyLikeTab(),
                MatchesTab(),
                SentRequestTab(),
              ],
            ),
          )
        ],
      ),
    );
  }
}

and i make custom delegate methods to stick tab bar

class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
  _SliverAppBarDelegate(this._tabBar);

  final TabBar _tabBar;

  @override
  double get minExtent => _tabBar.preferredSize.height;

  @override
  double get maxExtent => _tabBar.preferredSize.height;

  @override
  Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
    return Container(color: AppColors.kWhiteColor, child: _tabBar);
  }

  @override
  bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
    return false;
  }
}

but main issue is that when tab bar pin to tap after that it scroll under to it.

and then not able to scolle down the content.

please assist me how we can acheive these type of ui ?

enter image description here

2

Answers


  1. You should use a NestedScrollView instead of a CustomScrollView within the DefaultTabController. Inside the headerSliverBuilder, place your CustomChatAppBar widget inside a SliverAppBar, followed by the SliverPersistentHeader widget. Finally, in the body, include the TabBarView widget.

    Login or Signup to reply.
  2. as Salman said you have to use NestedScrollView,
    please refer for more details NestedScroll Widget

    import 'package:flutter/material.dart';
    
    class ProfileMyGroupDetailsScreen extends StatefulWidget {
    const ProfileMyGroupDetailsScreen({Key? key}) : super(key: key);
    
    @override
    State<ProfileMyGroupDetailsScreen> createState() => 
    _ProfileMyGroupDetailsScreenState();
    }
    
    class _ProfileMyGroupDetailsScreenState extends 
    State<ProfileMyGroupDetailsScreen> with SingleTickerProviderStateMixin {
    late TabController _tabController;
    
    @override
    void initState() {
    super.initState();
    _tabController = TabController(length: 4, vsync: this);
    }
    
    @override
    Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: CustomChatAppBar(
        title: AppLabels.myGroupDetails,
        systemOverlayStyle: Global.whiteOverLay,
        actions: [],
      ),
      body: buildDataTabWidget(),
    );
    }
    
    Widget buildDataTabWidget() {
    return NestedScrollView(
      headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
        return [
          SliverToBoxAdapter(
            child: Column(
              children: [
                ListTileType1(
                  padding: padXY(24, 8.5),
                  imageUrl: AppImages.dummyProfileImage1,
                  imageWidth: 44,
                  imageHeight: 44,
                  title1: 'Meme team',
                  title2: 'Jack & Chris',
                ),
                Padding(
                  padding: padXY(24, 16),
                  child: CustomImage(
                    imageUrl: AppImages.dummyProfileImage1,
                    height: MediaQuery.of(context).size.width - (24 * 2),
                    width: MediaQuery.of(context).size.width,
                    fit: BoxFit.cover,
                    borderRadius: 12,
                  ),
                ),
              ],
            ),
          ),
          SliverPersistentHeader(
            pinned: true,
            delegate: _SliverAppBarDelegate(
              TabBar(
                controller: _tabController,
                dividerColor: AppColors.kBorderColor,
                dividerHeight: 2,
                isScrollable: true,
                padding: EdgeInsets.zero,
                tabAlignment: TabAlignment.center,
                indicatorSize: TabBarIndicatorSize.tab,
                indicatorWeight: 1,
                labelColor: AppColors.kSecondaryColor,
                unselectedLabelColor: AppColors.kAppGrey,
                labelStyle: context.bodyLarge.w500,
                unselectedLabelStyle: context.bodyLarge,
                tabs: [
                  Tab(text: AppLabels.basicInformation),
                  Tab(text: AppLabels.myLikes),
                  Tab(text: AppLabels.matches),
                  Tab(text: AppLabels.sentRequests),
                ],
              ),
            ),
          ),
        ];
      },
      body: TabBarView(
        controller: _tabController,
        children: [
          BuildBasicInfoTab(),
          MyLikeTab(),
          MatchesTab(),
          SentRequestTab(),
         ],
       ),
      );
     }
    }
    
    class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
    _SliverAppBarDelegate(this._tabBar);
    
    final TabBar _tabBar;
    
    @override
    double get minExtent => _tabBar.preferredSize.height;
    
    @override
    double get maxExtent => _tabBar.preferredSize.height;
    
    @override
    Widget build(BuildContext context, double shrinkOffset, bool 
    overlapsContent) {
    return Container(color: AppColors.kWhiteColor, child: _tabBar);
    }
    
    @override
    bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
    return false;
     }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search