skip to Main Content

I would like to create a kind of animation in a layout, but I have no idea how to do it. Imagine a list with 7 (just for example) elements. However, the sixth and seventh elements are initially positioned below the fifth. When this list is scrolled, the fifth element moves out of the way, revealing the sixth, and so on. In this link, there is a Figma layout that illustrates what I am trying to achieve: https://www.figma.com/file/RBJUpcskBS3uImeyHDkstW/Untitled?type=design&node-id=0%3A1&mode=design&t=YwR33X6YBswv1o8a-1.

If anyone can help me, I would greatly appreciate it. I don’t have any code to show because everything I’ve tried doesn’t make sense, haha."

2

Answers


  1. Chosen as BEST ANSWER

    consegui fazer o que estava querendo, usei por base a biblioteca StackedCardCarousel, no código ate o momento eu preciso importar a biblioteca, creio que ainda da pra melhorar o código mas por enquanto vai continuar desse jeito, essa é a classe que cria o efeito

        `class HorizontalStackedCardCarousel extends StatefulWidget {
        HorizontalStackedCardCarousel({
        required List<Widget> items,
        StackedCardCarouselType type = StackedCardCarouselType.cardsStack,
        double initialOffset = 00.0,
        required spaceBetweenItems,
        bool applyTextScaleFactor = true,
        PageController? pageController,
        OnPageChanged? onPageChanged,
      })  : assert(items.isNotEmpty),
            _items = items,
            _type = type,
            _initialOffset = initialOffset,
            _spaceBetweenItems = spaceBetweenItems,
            _applyTextScaleFactor = applyTextScaleFactor,
            _pageController = pageController ?? PageController(),
            _onPageChanged = onPageChanged;
    
      final List<Widget> _items;
      final StackedCardCarouselType _type;
      final double _initialOffset;
      final double _spaceBetweenItems;
      final bool _applyTextScaleFactor;
      final PageController _pageController;
      final OnPageChanged? _onPageChanged;
    
      @override
      HorizontalStackedCardCarouselState createState() =>
          HorizontalStackedCardCarouselState();
    }
    
    class HorizontalStackedCardCarouselState
        extends State<HorizontalStackedCardCarousel> {
      double _pageValue = 0.0;
    
      @override
      void initState() {
        super.initState();
        // Adicione o deslocamento inicial desejado
        Future.delayed(Duration.zero, () {
          _pageValue = 4.0; // ou o valor desejado
          widget._pageController.jumpToPage(_pageValue.toInt());
        });
    
        widget._pageController.addListener(() {
          if (mounted) {
            setState(() {
              _pageValue = widget._pageController.page!;
            });
          }
        });
      }
    
      void onPageChanged(int index) {
        // Prevent the user from scrolling to pages with index less than 3
        if (index < 4) {
          widget._pageController.jumpToPage(4);
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return ClickThroughStack(
          children: <Widget>[
            _stackedCards(context),
            PageView.builder(
              scrollDirection: Axis.horizontal,
              controller: widget._pageController,
              itemCount: widget._items.length,
              onPageChanged: onPageChanged,
              itemBuilder: (BuildContext context, int index) {
                return Container();
              },
            ),
          ],
        );
      }
    
      Widget _stackedCards(BuildContext context) {
        double textScaleFactor = 1.0;
        if (widget._applyTextScaleFactor) {
          final double mediaQueryFactor = MediaQuery.of(context).textScaleFactor;
          if (mediaQueryFactor > 1.0) {
            textScaleFactor = mediaQueryFactor;
          }
        }
    
        final List<Widget> _positionedCards =
            widget._items.asMap().entries.map((MapEntry<int, Widget> item) {
          double position = widget._initialOffset;
    
          if (_pageValue > item.key) {
            position += (_pageValue - item.key) *
                widget._spaceBetweenItems *
                textScaleFactor;
          }
          switch (widget._type) {
            case StackedCardCarouselType.fadeOutStack:
              double opacity = 1.0;
              double scale = 1.0;
              if (_pageValue - item.key < 0) {
                final double factor = 1 + (_pageValue - item.key);
                opacity = factor < 0.0 ? 0.0 : pow(factor, 1.5).toDouble();
                scale = factor < 0.0 ? 0.0 : pow(factor, 0.1).toDouble();
              }
              return Positioned(
                right: position,
                child: Transform.scale(
                  scale: scale,
                  child: Opacity(
                    opacity: opacity,
                    child: item.value,
                  ),
                ),
              );
            case StackedCardCarouselType.cardsStack:
            default:
              double scale = 1.0;
              if (_pageValue - item.key < 0) {
                final double factor = 1 + (_pageValue - item.key);
                scale = 0.95 + (factor * 0.1 / 2);
              }
              return Positioned(
                right: position,
                child: Transform.scale(
                  scale: scale,
                  child: Stack(
                    children: [
                      item.value, // O container da imagem
                      if (item.key >= 4 && item.key != widget._items.length - 1) // Exibir o container apartir do index 4 ate o penultimo index
                        Positioned.fill(
                          child: AnimatedOpacity(
                            opacity: _isContainerVisible(item.key) ? 1.0 : 0.0,
                            duration: Duration(milliseconds: 100), // Ajuste conforme necessário
                            child: Container(
                              decoration: BoxDecoration(
                                color: Colors.black38,
                                borderRadius: BorderRadius.circular(10),
                              ),
                              child: Center(
                                child: Text(
                                  '${widget._items.length - item.key - 1}+', // Exibir o índice ajustado
                                  style: GoogleFonts.acme(
                                    color: Colors.white,
                                    fontSize: 30,
                                  ),
                                ),
                              ),
                            ),
                          ),
                        ),
                    ],
                  ),
                ),
              );
          }
        }).toList();
    
        return Stack(
          alignment: Alignment.centerRight,
          fit: StackFit.passthrough,
          children: _positionedCards.reversed.toList(),
        );
      }
    
      bool _isContainerVisible(int index) {
        // Ajuste conforme necessário, dependendo da lógica exata para determinar a visibilidade
        return index >= 4 && _pageValue <= index;
      }
    }
    

    `

    para usar eu preciso de uma classe auxiliar por que a view estava se recriando, esta é a classe auxiliar: `

    class MyWidget extends StatefulWidget {
      final double itemWidth;
      final double screenHeight;
    
      const MyWidget({required this.itemWidth, required this.screenHeight});
    
      @override
      _MyWidgetState createState() => _MyWidgetState();
    }
    
    class _MyWidgetState extends State<MyWidget> {
      late HorizontalStackedCardCarousel _carousel;
    
      @override
      void initState() {
        super.initState();
        _carousel = HorizontalStackedCardCarousel(
          spaceBetweenItems: widget.itemWidth + 5,
          items: List.generate(
            10,
            (index) => Container(
              width: widget.itemWidth,
              // Desired width for each container
              height: widget.screenHeight,
              clipBehavior: Clip.antiAlias,
              decoration: BoxDecoration(
                color: Colors.blueGrey,
                borderRadius: BorderRadius.circular(10),
              ),
              child: Image.network(
                'https://thypix.com/wp-content/uploads/2018/05/Sommerlandschaft-Bilder-30.jpg',
                fit: BoxFit.cover,
              ),
            ),
          ),
        );
      }
    
      @override
      Widget build(BuildContext context) {
        return Center(
          child: _carousel,
        );
      }
    }
    

    `

    chamo essa classe dentro da minha view principal e dessa maneira consigo mostrar o carrossel de imagens em miniatura, na horizontal como demonstrado na imagem :imagem demonstrativa de carrossel de imagens na horizontal


  2. I think you want to make a slider. you can achieve this using pageview widget. to change its index automatically you can set a Timer.periodic in initstate.

    or you can use this package carousel_slider

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search