Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SliverAutoScrollTag #108

Open
AlaaEldeenYsr opened this issue Jan 16, 2024 · 4 comments
Open

SliverAutoScrollTag #108

AlaaEldeenYsr opened this issue Jan 16, 2024 · 4 comments

Comments

@AlaaEldeenYsr
Copy link

I need another instance of the AutoScrollTag be SliverAutoScrollTag so i can use it inside CustomScrollView.
Please note that my itemBuilder is a SliverGrid and i want to wrap it with a SliverAutoScrollTag.
Note that SliverToBoxAdapter won't work here.

@jerrywell
Copy link
Member

Hi @AlaaEldeenYsr
Any simple reproducible code example is helpful : ) Can you provide the it?

@AlaaEldeenYsr
Copy link
Author

AlaaEldeenYsr commented Feb 3, 2024

My layout is kind of complicated nested scroll physics which make every item of my list is a SliverGrid and to wrap it with AutoScrollTag it throws an exception as it's a RenderBox and not a sliver, So we need the SliverAutoScrollTag copy of the widget.
The every item of my list annotated in below with // TODO: Scroll To Index @jerrywell

  @override
  Widget build(BuildContext context) {
    final controller = context.read<CategoryCubit>();

    return Scaffold(
      appBar: AppBar(
        forceMaterialTransparency: true,
        title: ReactiveValueListenableBuilder(
          formControl: controller.selectedCategoryId,
          builder: (context, control, child) {
            final selectedCategory = controller.categories.data?.firstWhere(
              (element) => element.id == control.value,
              orElse: () => controller.categories.data!.first,
            );

            return Text(selectedCategory?.title ?? '');
          },
        ),
        actions: [
          IconButton(
            onPressed: () {
              context.replace('/search');
            },
            icon: AppIcon(
              icon: Assets.icons.search.path,
              size: 20.sp,
            ),
          ),
        ],
      ),
      body: EntityBuilder(
        entity: controller.categories,
        pendingBuilder: (context) => const AppInPageLoader(),
        rejectedBuilder: (context, error) => ErrorModelWidget(error: error, onRefresh: controller.refresh),
        fulfilledBuilder: (context, data) => CustomScrollView(
          slivers: [
            SliverFloatingHeader(
              child: Container(
                color: Theme.of(context).scaffoldBackgroundColor,
                child: Observer(
                  builder: (context) => Column(children: [
                    ReactiveFormField<String, int>(
                      formControl: controller.selectedCategoryId,
                      valueAccessor: CategoryValueAccessor(list: data),
                      builder: (field) => DefaultTabController(
                        length: data?.length ?? 0,
                        initialIndex: field.value ?? 0,
                        child: TabBar(
                          tabAlignment: TabAlignment.start,
                          labelPadding: EdgeInsets.symmetric(
                            horizontal: AppSpaces.horizontalPadding8,
                          ),
                          onTap: (value) => field.didChange(value),
                          // dividerHeight: 2.h,
                          dividerColor: AppColors.grey7,
                          labelStyle: Theme.of(context).tabBarTheme.labelStyle?.copyWith(
                                fontSize: AppFontSizes.s12,
                                fontWeight: FontWeight.w700,
                              ),
                          unselectedLabelStyle: Theme.of(context).tabBarTheme.unselectedLabelStyle?.copyWith(
                                color: AppColors.grey6,
                                fontSize: AppFontSizes.s12,
                                fontWeight: FontWeight.w700,
                              ),
                          isScrollable: true,
                          tabs: [
                            ...?data?.map((e) => Tab(text: e.title)),
                          ],
                        ),
                      ),
                    ),
                    if (controller.category.fulfilled)
                      Column(children: [
                        DefaultTabController(
                          length: controller.category.data?.children?.length ?? 0,
                          child: Container(
                            color: Theme.of(context).scaffoldBackgroundColor,
                            alignment: AlignmentDirectional.topStart,
                            child: ButtonsTabBar(
                              buttonMargin: EdgeInsets.all(AppSpaces.borderRadius8),
                              unselectedBackgroundColor: AppColors.grey5,
                              contentPadding: EdgeInsets.symmetric(
                                horizontal: AppSpaces.horizontalPadding20,
                                vertical: 5.5.h,
                              ),
                              radius: 100,
                              labelStyle: Theme.of(context).tabBarTheme.labelStyle?.copyWith(
                                    color: Theme.of(context).scaffoldBackgroundColor,
                                    fontWeight: FontWeight.w500,
                                    fontSize: AppFontSizes.s14,
                                  ),
                              unselectedLabelStyle: Theme.of(context).tabBarTheme.unselectedLabelStyle?.copyWith(
                                    color: AppColors.secondary,
                                    fontWeight: FontWeight.w300,
                                  ),
                              tabs: [
                                ...?controller.category.data?.children?.map((e) => Tab(text: e.title)),
                              ],
                            ),
                          ),
                        ),
                        Divider(
                          color: AppColors.grey7,
                          height: 0,
                          thickness: 2.h,
                        )
                      ]),
                  ]),
                ),
              ),
            ),
            CupertinoSliverRefreshControl(
              onRefresh: () async => controller.refresh(),
            ),
            EntityBuilder(
              entity: controller.category,
              rejectedBuilder: (context, error) => SliverFillRemaining(
                hasScrollBody: false,
                child: ErrorModelWidget(error: error, onRefresh: controller.refresh),
              ),
              pendingBuilder: (context) => const SliverFillRemaining(
                hasScrollBody: false,
                child: AppInPageLoader(),
              ),
              pristineBuilder: (context) => const SliverToBoxAdapter(),
              fulfilledBuilder: (context, data) => MultiSliver(pushPinnedChildren: true, children: [
                ...?data.children?.mapIndexed(
                // TODO: Scroll To Index
                  (i, e) => SliverPadding(
                    padding: EdgeInsets.only(bottom: AppSpaces.verticalPadding16).add(
                      EdgeInsets.symmetric(
                        horizontal: AppSpaces.horizontalPadding16,
                        vertical: AppSpaces.verticalPadding12,
                      ),
                    ),
                    sliver: MultiSliver(children: [
                      SliverToBoxAdapter(
                        child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
                          Text(
                            e.title ?? '',
                            style: TextStyle(
                              fontSize: AppFontSizes.s16,
                              fontWeight: FontWeight.w600,
                            ),
                          ),
                          SizedBox(
                            height: AppSpaces.verticalPadding16,
                          )
                        ]),
                      ),
                      SliverGrid.builder(
                        itemCount: data.children?[i].products?.length ?? 0,
                        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                          mainAxisExtent: 238.h,
                          crossAxisCount: 3,
                          mainAxisSpacing: AppSpaces.horizontalPadding8,
                          crossAxisSpacing: AppSpaces.verticalPadding8,
                        ),
                        itemBuilder: (context, j) {
                          final item = e.products![j];

                          return ModelProductCard(
                            item: item,
                            onCartChange: (value) {
                              final controller = context.read<ProductCardActionsCubit>();

                              controller.handleCartChange(
                                hasVariants: item.hasVariants,
                                cartItemId: item.cartItem?.id,
                                body: PutCartItemRequestModel(
                                  productId: item.id,
                                  price: item.inventory?.price,
                                  quantity: value,
                                  offerId: item.offer?.id,
                                ),
                              );
                            },
                            onHeartClick: () {
                              final controller = context.read<ProductCardActionsCubit>();

                              controller.toggleProductFavourites(
                                productId: item.id,
                              );
                            },
                          );
                        },
                      )
                    ]),
                  ),
                ),
              ]),
            ),
          ],
        ),
      ),
      bottomNavigationBar: FreeDeliveryBottomBar(
        hasProductsCount: true,
        elevatedButton: ElevatedButton(
          onPressed: () => context.go("/cart"),
          child: const Text("فتح السلة"),
        ),
      ),
    );
  }

@lockieRichter
Copy link

Any updates on this? I am in the same boat and really want this feature.

@jerrywell
Copy link
Member

jerrywell commented Mar 21, 2024

Hi @AlaaEldeenYsr, The attached example is unable to build and debug, so i can't check it.

However, I have write the code snippet for CustomScrollView with both SliverList and SliverGrid as following.
You can replace the body of example with follow code snippets:

body: CustomScrollView(
  scrollDirection: scrollDirection,
  controller: controller,
  slivers: [
    SliverGrid(
      delegate: SliverChildListDelegate(
        randomList.sublist(0, 10).map<Widget>((data) {
          return Padding(
            padding: EdgeInsets.all(8),
            child: _getRow(data[0], math.max(data[1].toDouble(), 50.0)),
          );
        }).toList(),
      ),
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        mainAxisExtent: 100,
        crossAxisCount: 3,
        mainAxisSpacing: 10,
        crossAxisSpacing: 10,
      ),
    ),
    SliverList(
      delegate: SliverChildListDelegate(
        randomList.sublist(10, 100).map<Widget>((data) {
          return Padding(
            padding: EdgeInsets.all(8),
            child: _getRow(data[0], math.max(data[1].toDouble(), 50.0)),
          );
        }).toList(),
      ),
    )
  ],
),

@lockieRichter the code snippet should be helpful enough to demo how it works with Slivers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants