Карты с горизонтальной прокруткой и эффектом Snap при трепете

Я хочу создать список карточек, прокручивающихся по горизонтали с эффектом привязки по размеру при смахивании влево или вправо.

Каждая карта имеет некоторый интервал между ними и соответствует размеру экрана, как показано на изображении ниже.

введите описание изображения здесь

Кроме того, эти элементы списка с горизонтальной прокруткой должны содержаться внутри списка с вертикальной прокруткой.

Все, что я могу достичь, - это только отображение списка карт с горизонтальной прокруткой после следующего примера в документации по флаттеру.

class SnapCarousel extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final title = 'Horizontal List';

    return MaterialApp(
      title: title,
      home: Scaffold(
        appBar: AppBar(
          title: Text(title),
        ),
        body: Container(
          margin: EdgeInsets.symmetric(vertical: 20.0),
          height: 200.0,
          child: ListView(
            scrollDirection: Axis.horizontal,
            children: <Widget>[
              Container(
                width: 160.0,
                color: Colors.red,
              ),
              Container(
                width: 160.0,
                color: Colors.blue,
              ),
              Container(
                width: 160.0,
                color: Colors.green,
              ),
              Container(
                width: 160.0,
                color: Colors.yellow,
              ),
              Container(
                width: 160.0,
                color: Colors.orange,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

person WitVault    schedule 31.07.2018    source источник
comment
Возможный дубликат Создание карусели изображений во Flutter   -  person Rémi Rousselet    schedule 31.07.2018
comment
@ RémiRousselet Вышеупомянутая ссылка частично решает мою проблему, так как я также хотел поместить их в список с вертикальной прокруткой. Каждый компонент внутри вертикально прокручиваемого списка будет набором элементов, которые будут прокручиваться по горизонтали.   -  person WitVault    schedule 31.07.2018
comment
Ничего не мешает сделать по предыдущей ссылке   -  person Rémi Rousselet    schedule 31.07.2018
comment
@ RémiRousselet, пожалуйста, приведите простой пример. Я не знаю, как сделать его вертикально прокручиваемым.   -  person WitVault    schedule 31.07.2018
comment
Вы не делаете его вертикально прокручиваемым. Вместо этого заверните его внутрь ListView   -  person Rémi Rousselet    schedule 31.07.2018
comment
Вы можете найти аналогичный ответ здесь   -  person Pratik    schedule 14.05.2021


Ответы (3)


Используйте PageView и ListView:

import 'package:flutter/material.dart';

main() => runApp(MaterialApp(home: MyHomePage()));

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Carousel in vertical scrollable'),
      ),
      body: ListView.builder(
        padding: EdgeInsets.symmetric(vertical: 16.0),
        itemBuilder: (BuildContext context, int index) {
          if(index % 2 == 0) {
            return _buildCarousel(context, index ~/ 2);
          }
          else {
            return Divider();
          }
        },
      ),
    );
  }

  Widget _buildCarousel(BuildContext context, int carouselIndex) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[
        Text('Carousel $carouselIndex'),
        SizedBox(
          // you may want to use an aspect ratio here for tablet support
          height: 200.0,
          child: PageView.builder(
            // store this controller in a State to save the carousel scroll position
            controller: PageController(viewportFraction: 0.8),
            itemBuilder: (BuildContext context, int itemIndex) {
              return _buildCarouselItem(context, carouselIndex, itemIndex);
            },
          ),
        )
      ],
    );
  }

  Widget _buildCarouselItem(BuildContext context, int carouselIndex, int itemIndex) {
    return Padding(
      padding: EdgeInsets.symmetric(horizontal: 4.0),
      child: Container(
        decoration: BoxDecoration(
          color: Colors.grey,
          borderRadius: BorderRadius.all(Radius.circular(4.0)),
        ),
      ),
    );
  }
}
person boformer    schedule 31.07.2018
comment
на первой странице есть отступы .. как удалить это - person Rahul Devanavar; 07.02.2019
comment
страницы располагаются по центру виджета. вы можете увеличить viewportFraction до 1.0, чтобы страницы были во всю ширину. - person boformer; 08.02.2019
comment
Я хочу добиться чего-то вроде этого ibb.co/GcPp3bd. viewportFraction 1.0 сделать полный экран - person Rahul Devanavar; 11.02.2019
comment
Вы нашли способ @RahulDevanavar? - person Underfrog; 02.03.2019
comment
Я пробовал запустить этот код, он просто выглядит как горизонтальный список. Как мы добавляем эффект масштабирования на текущую карточку, как показано на изображении выше этого вопроса. - person Mahesh Jamdade; 02.07.2019
comment
Я не понимаю, зачем вам нужно было гнездиться в ListView.builder. - person Shababb Karim; 28.09.2020
comment
@ShababbKarim Помогает путем рендеринга / построения только при необходимости, что помогает с большими или бесконечными списками. - person aklingam; 08.10.2020

Снимок экрана:

введите описание изображения здесь


Если вы не хотите использовать какие-либо сторонние пакеты, вы можете просто попробовать следующее:

class _HomePageState extends State<HomePage> {
  int _index = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: SizedBox(
          height: 200, // card height
          child: PageView.builder(
            itemCount: 10,
            controller: PageController(viewportFraction: 0.7),
            onPageChanged: (int index) => setState(() => _index = index),
            itemBuilder: (_, i) {
              return Transform.scale(
                scale: i == _index ? 1 : 0.9,
                child: Card(
                  elevation: 6,
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
                  child: Center(
                    child: Text(
                      "Card ${i + 1}",
                      style: TextStyle(fontSize: 32),
                    ),
                  ),
                ),
              );
            },
          ),
        ),
      ),
    );
  }
}
person CopsOnRoad    schedule 28.02.2020
comment
Отлично! Но мне остается только задаваться вопросом, как установить расстояние между элементами? Хотел зазор поменьше? - person K-Dawg; 04.06.2020
comment
@PrimeByDesign Обновить значение scale с 0.9 до 0.95 - person CopsOnRoad; 05.06.2020
comment
при самой загрузке слева есть запас, как его убрать? - person Nifal Nizar; 11.10.2020
comment
@NifalNizar О какой марже вы говорите? - person CopsOnRoad; 11.10.2020
comment
comment
@NifalNizar Мне нужен доступ для просмотра файла. Вы можете сделать это достоянием общественности? - person CopsOnRoad; 11.10.2020
comment
@NifalNizar Хорошо, вы говорите о начальном интервале, ну, мне нужно немного поправить кое-что, в настоящее время не могу работать последние несколько дней, позвольте мне вернуться к машине через день или около того, я ' Я обновлю решение - person CopsOnRoad; 12.10.2020
comment
@CopsOnRoad, спасибо, как мы можем разместить несколько элементов вокруг центрального элемента? в вашей реализации у нас есть только один элемент, как мы можем, например, иметь 2 элемента? и изменение непрозрачности, например снимок экрана, который прикрепил владелец сообщения? - person DolDurma; 27.10.2020
comment
@DolDurma Вы можете установить viewportFraction на что-то вроде 0.5, а также уменьшить значение scale, но тогда это не будет служить цели для PageView. В вашем случае я предлагаю вам использовать горизонтальный ListView. А для непрозрачности просто оберните виджет Card внутри виджета Opacity и установите opacity: i == _index ? 1 : 0.5 - person CopsOnRoad; 28.10.2020
comment
Есть ли ответ на вопрос NifalNizar? @CopsOnRoad? - person Ufuk Zimmerman; 26.04.2021
comment
можно ли использовать PageView в этом контексте без фиксированной высоты, больше как будто он должен обертывать его содержимое. - person Paul Okeke; 03.05.2021

это старый вопрос, и я пришел сюда в поисках чего-то еще ;-), но то, что искал WitVault, легко сделать с помощью этого пакета: https://pub.dev/packages/flutter_swiper

Демо-изображение

Реализация:

Поместите зависимости в pubsec.yaml:

dependencies:
   flutter_swiper: ^1.1.6

Импортируйте его на нужную страницу:

import 'package:flutter_swiper/flutter_swiper.dart';

В макете:

new Swiper(
  itemBuilder: (BuildContext context, int index) {
    return new Image.network(
      "http://via.placeholder.com/288x188",
      fit: BoxFit.fill,
    );
  },
  itemCount: 10,
  viewportFraction: 0.8,
  scale: 0.9,
)
person Daniel    schedule 01.08.2019
comment
Мы попробовали этот пакет. Опыт оказался ниже наших ожиданий. Вероятно, из-за большого количества нерешенных проблем (158 проблем на момент написания - в основном требовалась помощь). github.com/best-flutter/flutter_swiper/issues - мы остановились на другом решении . - person Alex Jean; 07.08.2020
comment
@AlexJean, пожалуйста, поделитесь другим решением с сообществом - person Marcos Eznavil; 09.08.2020
comment
PageView, как указано в дубликате этого вопроса, - это то, на что мы остановились. Другие решения в этом посте и его дубликате тоже были удобными. Дубликат stackoverflow.com/questions/47349784/ - person Alex Jean; 11.08.2020
comment
Как представляется, интерес - мы также успешно использовали этот популярный пакет pub.dev/packages/carousel_slider, который пока не упоминается среди ответов. - person Alex Jean; 13.09.2020