Search code examples
flutterdartcarousel

Flutter carousel view overflowing, but when hot reloading, everything seems to fix itself


I am working on a page for an app I am building. On this page, I am using a CarouselView to display cards. These cards consist of a background image, on top of this is another smaller image, a linear gradient, a column of text in which one of the children is a row, of which one of the row's children is another row to make the "ratings" part of the tile. When I restart the app and navigate to this page, I get an error saying that the carousel has overflowed to the right, but an overflow for a carousel makes sense to me. However, when I hot reload, having made no changes, the issue is fixed and I get a display I expect to see. (If this explanation doesn't make sense, I have put the code and the images on this post) Just after restarting the app After hot reloading, with no changes made

I thought this was an issue with the lack of padding where I call this widget, but that wasn't the case. The code for the carousel:

import 'package:flutter/material.dart';

class MyPracticesCarousel extends StatelessWidget {
  const MyPracticesCarousel({super.key});

  @override
  Widget build(BuildContext context) {
    return CarouselView(
      itemExtent: 325,
      itemSnapping: true,
      children: List<Widget>.generate(10, (int index) {
        return MyPracticeCard();
      }),
    );
  }
}



class MyPracticeCard extends StatelessWidget {
  const MyPracticeCard({
    super.key,
  });

  void viewPractice(BuildContext context)
  {
    print("Card pressed");
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () => viewPractice(context),
      child: Card(
        color: Colors.white,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(20),
        ),
        child: ClipRRect(
          borderRadius: BorderRadius.circular(20),
          child: Stack(
            children: [
              Container(
                decoration: const BoxDecoration(
                  image: DecorationImage(
                    image: AssetImage("assets/GP_front_image.jpg"),
                    fit: BoxFit.cover,
                    alignment: Alignment.topCenter,
                  ),
                ),
              ),
              Container(
                decoration: const BoxDecoration(
                  gradient: LinearGradient(
                    colors: [
                      Colors.black,
                      Colors.transparent,
                    ],
                    begin: Alignment.bottomCenter,
                    end: Alignment.center,
                    stops: [0.0, 1],
                  ),
                ),
              ),
              const Positioned(
                bottom: 20,
                left: 15,
                right: 15,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      "London Bridge General Practice",
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 16,
                        fontWeight: FontWeight.w500,
                      ),
                      overflow: TextOverflow.ellipsis,
                      maxLines: 1,
                    ),
                    // SizedBox(height: 2), // Optionally, uncomment for spacing
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Expanded(
                          child: Text(
                            "0.2 miles",
                            style: TextStyle(
                              color: Colors.white,
                              fontSize: 16,
                              fontWeight: FontWeight.w400,
                            ),
                            overflow: TextOverflow.ellipsis,
                            maxLines: 1,
                          ),
                        ),
                        
                          Row(
                            mainAxisAlignment: MainAxisAlignment.end,
                            children: [
                              Text(
                                "4.5",
                                style: TextStyle(
                                  color: Colors.white,
                                  fontSize: 16,
                                  fontWeight: FontWeight.w400,
                                ),
                                overflow: TextOverflow.ellipsis,
                                maxLines: 1,
                              ),
                              SizedBox(width: 2,),
                              Icon(
                                Icons.star,
                                color: Colors.white, // Color of the star icon
                                size: 18, // Size of the star icon
                              ),
                              
                            ],
                          ),
                      
                      ],
                    ),
                  ],
                ),
              ),
              Positioned(
                top: 10,
                right: 10,
                child: ClipRRect(
                  borderRadius: BorderRadius.circular(10),
                  child: Image.asset(
                    "assets/HCA_logo.jpg",
                    width: 50,
                    height: 50,
                    fit: BoxFit.cover,
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}


The overflow issue comes from the embedded Rows, but I don't get why when I hot reload the ui is fixed? I want it to be fixed from the start.


Solution

  • It seems that when the carousel is rendered for the first time, it is still performing calculations, which causes the second widget to appear as if it's being wrapped. In your case, there are a few solutions. The first is to wrap the rating widget with Flexible, as shown in the code below:

                     Flexible( /// Flexible here
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.end,
                            children: [
                              Flexible( /// Flexible here
                                child: Text(
                                  "4.5",
                                  style: TextStyle(
                                    color: Colors.white,
                                    fontSize: 16,
                                    fontWeight: FontWeight.w400,
                                  ),
                                  overflow: TextOverflow.ellipsis,
                                  maxLines: 1,
                                ),
                              ),
                              SizedBox(width: 2),
                              Flexible( /// Flexible here
                                child: Icon(
                                  Icons.star,
                                  color: Colors.white,
                                  size: 18, 
                                ),
                              ),
    

    Or you can add shrinkExtent with the same value as itemExtent, which is 320, as shown in the code below:

    CarouselView(
      itemExtent: 320,
      shrinkExtent: 320, /// add shrinkExtent here
      itemSnapping: true,
      children: List<Widget>.generate(10, (int index) {
        return MyPracticeCard();
      }),
    )
    

    but if you add shrinkExtent the same width as itemExtent, there won't be any animation like wrapping or snapping.