Флаттер Как сделать слайд-карусель из 2 карт с индикатором?

#flutter #user-interface #flutter-layout #flutter-animation #user-experience

Вопрос:

Я изучаю возможность наличия 2 карт на перетаскивание/свайп в элементе карусели. [Пожалуйста, смотрите прилагаемое для справки.

На каждом слайде карусели будут показаны 2 карточки, связанные с отдельной функцией просмотра, и индикатор 3 круга внизу. Подумываю о том, чтобы иметь 3 карусельных слайда, чтобы они были сбалансированы.

До сих пор я вижу только ссылки, которые представляют собой только одну карусель изображений, подобную этой. Я не могу воссоздать, настроив пример кода так, чтобы в одном слайде карусели было 2 карточки. Надеюсь, вы сможете показать мне, как я могу сделать код?

Кроме того, поскольку я не могу найти ссылку или пример для этого, не рекомендуется ли делать этот сложный вид слайд-карт с каруселью? Я недавно изучаю Flutter, поэтому я не уверен, что это усложнит интерфейсные API или что-то в этом роде.

Ответ №1:

Вы можете реализовать это, установив PageController просмотр страницы и установив viewportFraction число меньше 1.

Затем положите по две карточки на каждую страницу.

Gif

Вот исходный код:

 import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: TwoCardPageView(),
    );
  }
}

class TwoCardPageView extends StatefulWidget {
  const TwoCardPageView({Key? key}) : super(key: key);

  @override
  _TwoCardPageViewState createState() => _TwoCardPageViewState();
}

class _TwoCardPageViewState extends State<TwoCardPageView> {
  final List<Item> _items = [
    Item('A', Colors.red),
    Item('B', Colors.yellow),
    Item('C', Colors.green),
    Item('D', Colors.purple),
    Item('E', Colors.blue),
    Item('F', Colors.pink),
    Item('G', Colors.orange)
  ];
  final PageController _pageController =
      PageController(viewportFraction: 0.8, initialPage: 0);
  double _page = 0;

  @override
  void initState() {
    super.initState();
    _pageController.addListener(() {
      if (_pageController.page != null) {
        _page = _pageController.page!;
        setState(() {});
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Two Card PageView'),
        centerTitle: true,
      ),
      body: Column(
        children: [
          SizedBox(
            width: MediaQuery.of(context).size.width,
            height: 200,
            child: PageView.builder(
                controller: _pageController,
                itemCount: _items.length ~/ 2   _items.length % 2,
                itemBuilder: (context, index) {
                  return SizedBox(
                    child: Row(
                      children: [
                        Expanded(
                            child:
                                ItemBuilder(items: _items, index: index * 2)),
                        Expanded(
                            child: index * 2   1 >= _items.length
                                ? const SizedBox()
                                : ItemBuilder(
                                    items: _items, index: index * 2   1)),
                      ],
                    ),
                  );
                }),
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              for (int i = 0; i < _items.length ~/ 2   _items.length % 2; i  )
                Container(
                  margin: const EdgeInsets.all(2),
                  width: 10,
                  height: 10,
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(10),
                      border: Border.all(color: Colors.grey, width: 1.5),
                      color: _page - i > 1 || _page - i < -1
                          ? Colors.transparent
                          : _page - i > 0
                              ? Colors.grey.withOpacity(1 - (_page - i))
                              : Colors.grey.withOpacity(1 - (i - _page))),
                )
            ],
          )
        ],
      ),
    );
  }
}

class ItemBuilder extends StatelessWidget {
  const ItemBuilder({
    Key? key,
    required List<Item> items,
    required this.index,
  })  : _items = items,
        super(key: key);

  final List<Item> _items;
  final int index;

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
      height: 200,
      color: _items[index].color,
      child: Center(
          child: Text(
        _items[index].title,
        style: const TextStyle(fontSize: 25),
      )),
    );
  }
}

class Item {
  final String title;
  final Color color;

  Item(this.title, this.color);
}
 

Комментарии:

1. привет @Mehrzad, спасибо, что ответили. Тем временем я просто использовал пакет carousel_slider от pub dev, чтобы выполнить карусель карт с индикатором. К сожалению, однако, я не смог заставить две карты появиться в середине сразу. Если вы можете помочь мне, как этого добиться с помощью пакета слайдов «карусель», это будет здорово ^_^