Search code examples
flutterfirebasedartflutter-pageview

Flutter how to put Pageview.builder inside GridView.count properly?


I tried using expanded widget and other ways to solve this but I really don't know how to solve this error.. Thank you very much for the help everyone 👍

This is the error i get :

Exception has occurred. FlutterError (Horizontal viewport was given unbounded width. Viewports expand in the scrolling direction to fill their container. In this case, a horizontal viewport was given an unlimited amount of horizontal space in which to expand. This situation typically happens when a scrollable widget is nested inside another scrollable widget. If this widget is always nested in a scrollable widget there is no need to use a viewport because there will always be enough horizontal space for the children. In this case, consider using a Row or Wrap instead. Otherwise, consider using a CustomScrollView to concatenate arbitrary slivers into a single scrollable.)

grid code:

GridView.count(
            shrinkWrap: true,
            physics: const NeverScrollableScrollPhysics(),
            crossAxisCount: 2,
            padding: EdgeInsets.fromLTRB(0, 13, 0, 30),
            // crossAxisSpacing: 10,
            childAspectRatio: size.width / (size.height * 0.59),
            children: List.generate(allProducts.length, (index) {
              return ChangeNotifierProvider.value(
                  value: allProducts[index],
                  child: Container(child: const FeedsWidget()));
            }),
          ),

Pageview.builder code:

PageView.builder(
                          scrollDirection: Axis.horizontal,
                          itemCount: productModel.imageUrl!.length,
                          itemBuilder: (context, index) {
                            return ClipRRect(
                              borderRadius: BorderRadius.circular(10),
                              child: FancyShimmerImage(
                                height: size.width * 0.28,
                                width: size.width * 0.38,
                                imageUrl: productModel.imageUrl![index],
                                boxFit: BoxFit.fill,
                              ),
                            );
                          }),

This is my full code:

class FeedsScreen extends StatefulWidget {
  static const routeName = "/FeedsScreenState";
  const FeedsScreen({Key? key}) : super(key: key);

  @override
  State<FeedsScreen> createState() => _FeedsScreenState();
}

class _FeedsScreenState extends State<FeedsScreen> {
  final TextEditingController? _searchTextController = TextEditingController();
  final FocusNode _searchTextFocusNode = FocusNode();
  @override
  void dispose() {
    _searchTextController!.dispose();
    _searchTextFocusNode.dispose();
    super.dispose();
  }

  @override
  void initState() {
    final productsProvider =
        Provider.of<ProductsProvider>(context, listen: false);
    productsProvider.fetchProducts();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    final productsProvider = Provider.of<ProductsProvider>(context);
    List<ProductModel> allProducts = productsProvider.getProducts;
    final Color color = Utils(context).color;
    Size size = Utils(context).getScreenSize;
    return Scaffold(
      appBar: AppBar(
        leading: const BackWidget(),
        elevation: 0,
        backgroundColor: Theme.of(context).scaffoldBackgroundColor,
        centerTitle: true,
        title: vTextWidget(
          text: 'All Products',
          color: color,
          textSize: 20.0,
          isTitle: true,
          fontWeight: FontWeight.bold,
        ),
      ),
      body: SingleChildScrollView(
        child: Column(children: [
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: SizedBox(
              height: kBottomNavigationBarHeight,
              child: TextField(
                focusNode: _searchTextFocusNode,
                controller: _searchTextController,
                onChanged: (valuee) {
                  setState(() {});
                },
                decoration: InputDecoration(
                  focusedBorder: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(12),
                    borderSide:
                        const BorderSide(color: Colors.greenAccent, width: 1),
                  ),
                  enabledBorder: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(12),
                    borderSide:
                        const BorderSide(color: Colors.greenAccent, width: 1),
                  ),
                  hintText: "What's in your mind",
                  prefixIcon: const Icon(Icons.search),
                  suffix: IconButton(
                    onPressed: () {
                      _searchTextController!.clear();
                      _searchTextFocusNode.unfocus();
                    },
                    icon: Icon(
                      Icons.close,
                      color: _searchTextFocusNode.hasFocus ? Colors.red : color,
                    ),
                  ),
                ),
              ),
            ),
          ),
          GridView.count(
            shrinkWrap: true,
            physics: const NeverScrollableScrollPhysics(),
            crossAxisCount: 2,
            padding: EdgeInsets.fromLTRB(0, 13, 0, 30),
            // crossAxisSpacing: 10,
            childAspectRatio: size.width / (size.height * 0.59),
            children: List.generate(allProducts.length, (index) {
              return ChangeNotifierProvider.value(
                  value: allProducts[index],
                  child: Container(child: const FeedsWidget()));
            }),
          ),
        ]),
      ),
    );
  }
}

and the widget page full code:

class FeedsWidget extends StatefulWidget {
  static const routeName = "/feedItemsSc";
  const FeedsWidget({Key? key}) : super(key: key);

  @override
  State<FeedsWidget> createState() => _FeedsWidgetState();
}

class _FeedsWidgetState extends State<FeedsWidget> {
  final _quantityTextController = TextEditingController();
  @override
  void initState() {
    _quantityTextController.text = '1';
    super.initState();
  }

  @override
  void dispose() {
    _quantityTextController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final themeState = Provider.of<DarkThemeProvider>(context);
    final productModel = Provider.of<ProductModel>(context);
    final cartProvider = Provider.of<CartProvider>(context);
    final wishlistProvider = Provider.of<WishlistProvider>(context);
    bool? _isInCart = cartProvider.getCartItems.containsKey(productModel.id);
    bool? _isInWishlist =
        wishlistProvider.getWishlistItems.containsKey(productModel.id);

    bool _isDark = themeState.getDarkTheme;
    final Color color = Utils(context).color;
    Size size = Utils(context).getScreenSize;
    return Padding(
      padding: const EdgeInsets.fromLTRB(5, 0, 8, 8),
      child: Material(
        borderRadius: BorderRadius.circular(12),
        color: Theme.of(context).cardColor,
        child: InkWell(
          onTap: () {
            Navigator.pushNamed(context, ProductDetails.routeName,
                arguments: productModel.id);
            //GlobalMethods.navigateTo(
            // ctx: context, routeName: ProductDetails.routeName);
          },
          borderRadius: BorderRadius.circular(12),
          child: Column(children: [
            Flexible(
                flex: 3,
                child: SizedBox(
                  height: 300,
                  width: 400,
                  child: productModel.imageUrl == null
                      ? Image(
                          height: size.width * 0.28,
                          width: size.width * 0.38,
                          fit: BoxFit.fill,
                          image:
                              AssetImage('lib/assets/images/error_image.png'),
                        )
                      : PageView.builder(
                          scrollDirection: Axis.horizontal,
                          itemCount: productModel.imageUrl!.length,
                          itemBuilder: (context, index) {
                            return ClipRRect(
                              borderRadius: BorderRadius.circular(10),
                              child: FancyShimmerImage(
                                height: size.width * 0.28,
                                width: size.width * 0.38,
                                imageUrl: productModel.imageUrl![index],
                                boxFit: BoxFit.fill,
                              ),
                            );
                          }),
                )),
            //SizedBox(
            // height: 8,
            // ),
            // FancyShimmerImage(
            //imageUrl: productModel.imageUrl,
            // height: size.width * 0.28,
            // width: size.width * 0.38,
            // boxFit: BoxFit.fill,
            //),
            SizedBox(
              height: 5,
            ),
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 3),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Flexible(
                    flex: 3,
                    child: fTextWidget(
                      text: productModel.title,
                      maxLines: 1,
                      color: color,
                      textSize: 22,
                      isTitle: true,
                    ),
                  ),
                  Flexible(
                      flex: 1,
                      child: HeartBTN(
                        productId: productModel.id,
                        isInWishlist: _isInWishlist,
                      )),
                ],
              ),
            ),
            Padding(
              padding: const EdgeInsets.fromLTRB(6, 8, 8, 2),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Flexible(
                    flex: 3,
                    child: priceWidget(
                      isDark: _isDark,
                      salePrice: productModel.discountPrice,
                      price: productModel.price,
                      textPrice: _quantityTextController.text,
                      isOneSale: productModel.isDiscounted ? true : false,
                    ),
                  ),
                  //  const SizedBox(
                  //    width: 10,
                  //  ),
                  /* Flexible(
                    child: Row(
                      children: [
                        FittedBox(
                          child: fTextWidget(
                            text: 'Qty',
                            color: color,
                            textSize: 18,
                            isTitle: true,
                          ),
                        ),
                        const SizedBox(
                          width: 4,
                        ),
                        Flexible(
                          flex: 2,
                          child: TextFormField(
                            controller: _quantityTextController,
                            key: const ValueKey('10'),
                            style: TextStyle(color: color, fontSize: 17),
                            keyboardType: TextInputType.number,
                            maxLines: 1,
                            decoration: InputDecoration(
                              focusedBorder: UnderlineInputBorder(
                                  borderSide: BorderSide()),
                            ),
                            textAlign: TextAlign.center,
                            cursorColor: Colors.green,
                            enabled: true,
                            inputFormatters: [
                              FilteringTextInputFormatter.allow(
                                RegExp('[0-9.,]'),
                              ),
                            ],
                            onChanged: (value) {
                              setState(() {
                                if (value.isEmpty) {
                                  _quantityTextController.text = '1';
                                } else {
                                  // total = usedPrice *
                                  //     int.parse(_quantityTextController.text);
                                }
                              });
                            },
                            onSaved: (value) {},
                          ),
                        ),
                      ],
                    ),
                  ),*/
                ],
              ),
            ),
            const Spacer(),
            SizedBox(
              width: double.infinity,
              child: TextButton(
                onPressed: _isInCart
                    ? null
                    : () {
                        final User? user = authInstance.currentUser;
                        if (user == null) {
                          GlobalMethods.errorDialog(
                              subtitle: 'Please Login',
                              vicon: Icon(Icons.error),
                              context: context);
                          return;
                        }
                        // if (_isInCart) {
                        //   return;
                        // }
                        cartProvider.addProductsToCart(
                          productId: productModel.id,
                          quantity: int.parse(_quantityTextController.text),
                        );
                      },
                child: fTextWidget(
                  text: _isInCart ? 'Added' : 'Add to cart',
                  maxLines: 1,
                  color: color,
                  textSize: 20,
                ),
                style: ButtonStyle(
                    backgroundColor:
                        MaterialStateProperty.all(Theme.of(context).cardColor),
                    tapTargetSize: MaterialTapTargetSize.shrinkWrap,
                    shape: MaterialStateProperty.all<RoundedRectangleBorder>(
                      const RoundedRectangleBorder(
                        borderRadius: BorderRadius.only(
                          bottomLeft: Radius.circular(12.0),
                          bottomRight: Radius.circular(12.0),
                        ),
                      ),
                    )),
              ),
            ),
          ]),
        ),
      ),
    );
  }
}

Solution

  • I have fixed the problem by adding a sized box and giving it height and width. Thus, the problem was fixed thanks for your help everyone.

    Here is my updated Pageview.builder code:

    child: SizedBox(
                    height: 120,
                    width: 400,
                    child: productModel.imageUrl == null
                        ? Image(
                            height: size.width * 0.28,
                            width: size.width * 0.38,
                            fit: BoxFit.fill,
                            image: AssetImage('lib/assets/images/error_image.png'),
                          )
                        : PageView.builder(
                            scrollDirection: Axis.horizontal,
                            itemCount: productModel.imageUrl!.length,
                            itemBuilder: (context, index) {
                              return ClipRRect(
                                borderRadius: BorderRadius.circular(10),
                                child: FancyShimmerImage(
                                  height: size.width * 0.28,
                                  width: size.width * 0.38,
                                  imageUrl: productModel.imageUrl![index],
                                  boxFit: BoxFit.fill,
                                ),
                              );
                            }),
                  ),