【问题标题】:Horizontally scrollable cards with Snap effect in flutterFlutter 中具有 Snap 效果的水平滚动卡片
【发布时间】:2019-01-07 11:59:12
【问题描述】:

我想创建一个水平滚动的卡片列表,并在从左或右滑动时使用对齐效果。

每张卡片之间都有一些间距,适合屏幕,如下图所示

除此之外,这些可水平滚动的列表元素应包含在可垂直滚动的列表中。

在flutter docs中的示例之后,我所能实现的只是显示水平滚动卡的列表。

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,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

【问题讨论】:

  • @RémiRousselet 上面的链接部分解决了我的问题,因为我还想将它们放在垂直滚动列表中。垂直滚动列表中的每个组件都是水平滚动的元素集合。
  • 没有什么能阻止您使用上一个链接进行操作
  • @RémiRousselet 你能提供一个基本的例子吗?我不知道如何让它垂直滚动。
  • 你不能让它垂直滚动。将其包裹在 ListView

标签: dart flutter flutter-layout flutter-animation flutter-sliver


【解决方案1】:

使用PageViewListView

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)),
        ),
      ),
    );
  }
}

【讨论】:

  • 首页有一些填充..如何删除它
  • 页面在小部件中居中。您可以将viewportFraction 增加到 1.0 以使页面全宽。
  • 我想实现这样的目标ibb.co/GcPp3bd。 viewportFraction 1.0 使全屏
  • 你找到@RahulDevanavar 的方法了吗?
  • 我尝试运行此代码,它看起来就像一个水平列表视图我们如何在当前卡片上添加缩放效果,如本问题的上图所示
【解决方案2】:

截图:


如果你不想使用任何 3rd 方包,你可以简单地试试这个:

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),
                    ),
                  ),
                ),
              );
            },
          ),
        ),
      ),
    );
  }
}

【讨论】:

  • 这太棒了!但我想知道,你如何设置项目之间的距离?我想要一个更小的差距?
  • @PrimeByDesign 将scale 值从0.9 更新为0.95
  • 加载时左边有边距,如何去掉?
  • @NifalNizar 你说的是哪个边距?
  • 我在第一项drive.google.com/file/d/1m3SC7mpLd6tx2iPoMMoMnLCSoUURqCSx/…之前得到一个小空白@
【解决方案3】:

这是一个老问题,我来这里是为了寻找其他东西 ;-),但是 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,
)

【讨论】:

  • 我们试过这个包。经验低于我们的预期。可能是因为大量未解决的问题(在撰写本文时有 158 个问题 - 主要是“需要帮助”)。 github.com/best-flutter/flutter_swiper/issues -- 我们选择了另一种解决方案。
  • @AlexJean 请与社区分享其他解决方案
  • PageView 如该问题的副本所示,是我们解决的问题。这篇文章中的其他解决方案及其副本也很舒服。重复stackoverflow.com/questions/47349784/…
  • 似乎有兴趣 - 我们也成功地使用了这个流行的包pub.dev/packages/carousel_slider,到目前为止还没有在答案中提及。
【解决方案4】:

要通过ListView实现snap效果,只需将physics设置为PageScrollPhysics

const List<Widget> children = [
  ContainerCard(),
  ContainerCard(),
  ContainerCard(),
];
ListView.builder(
    scrollDirection: Axis.horizontal,
    physics: const PageScrollPhysics(), // this for snapping
    itemCount: children.length,
    itemBuilder: (_, index) => children[index],
  )

【讨论】:

    猜你喜欢
    • 2016-10-02
    • 1970-01-01
    • 2019-02-25
    • 1970-01-01
    • 1970-01-01
    • 2013-10-27
    • 2016-06-29
    • 2023-02-05
    相关资源
    最近更新 更多