Pinterest 风格的网格在 Flutter 中

huangapple go评论64阅读模式
英文:

Pinterest like grid in Flutter

问题

我有一个容器列表,它们都有相同的宽度但不同的高度。我想要用它们填充屏幕,从左上角开始,然后到右上角,然后到下方,依此类推。

类似的布局可以在Pinterest和Google Keep中看到。请注意,屏幕的尺寸可能会改变,因此我不知道列数。

我尝试过flutter_staggered_grid_view。最相似的东西我能找到是砌砖格(Masonry grid)。但它改变了容器的宽度。

英文:

I have a list of containers which all have the same width and different heights. I want to fill the screen with them. From top left, to top right, to below, etc.

Similar thing can be seen in Pinterest and also Google Keep. Notice that the screen might resize so I don't know the number of columns.

I have tried flutter_staggered_grid_view. The most similar thing I could find was the Masonry grid. But it changed the width of the containers.

答案1

得分: 1

这是一个在Flutter中创建类似Pinterest网格的示例。图像的宽度不会改变。希望这有所帮助。


class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    double w = MediaQuery.of(context).size.width;
    double itemwidth = 250;
    double crossAxisCount = w / (itemwidth);
    return Scaffold(
        appBar: newMethod(),
        body: Center(
            child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
              Expanded(
                  child: MasonryGridView.count(
                      itemCount: 50,
                      mainAxisSpacing: 10,
                      crossAxisCount: crossAxisCount.toInt(),
                      itemBuilder: (context, index) {
                        int randomHeight = Random().nextInt(6);
                        return UnconstrainedBox(
                            child: Container(
                                width: itemwidth,
                                height: (randomHeight % 5 + 2) * 100,
                                decoration: BoxDecoration(
                                    borderRadius: BorderRadius.circular(10),
                                    image: DecorationImage(
                                        fit: BoxFit.cover,
                                        image: NetworkImage(
                                            "https://picsum.photos/100/${(randomHeight % 5 + 2) * 100}")))));
                      }))
            ])));
  }
}

Pinterest 风格的网格在 Flutter 中

英文:

This is an example for pinterest like grid in Flutter. Width of images doesn't change. I hope that helps.


class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State&lt;MyHomePage&gt; createState() =&gt; _MyHomePageState();
}

class _MyHomePageState extends State&lt;MyHomePage&gt; {
  @override
  Widget build(BuildContext context) {
    double w = MediaQuery.of(context).size.width;
    double itemwidth = 250;
    double crossAxisCount = w / (itemwidth);
    return Scaffold(
        appBar: newMethod(),
        body: Center(
            child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: &lt;Widget&gt;[
              Expanded(
                  child: MasonryGridView.count(
                      itemCount: 50,
                      mainAxisSpacing: 10,
                      crossAxisCount: crossAxisCount.toInt(),
                      itemBuilder: (context, index) {
                        int randomHeight = Random().nextInt(6);
                        return UnconstrainedBox(
                            child: Container(
                                width: itemwidth,
                                height: (randomHeight % 5 + 2) * 100,
                                decoration: BoxDecoration(
                                    borderRadius: BorderRadius.circular(10),
                                    image: DecorationImage(
                                        fit: BoxFit.cover,
                                        image: NetworkImage(
                                            &quot;https://picsum.photos/100/${(randomHeight % 5 + 2) * 100}&quot;)))));
                      }))
            ])));
}
}

Pinterest 风格的网格在 Flutter 中

答案2

得分: 0

尝试将此扩展添加到您的项目中:

extension Responsive on BuildContext {
  T responsive<T>(
    T defaultVal, {
    T? sm,
    T? md,
    T? lg,
    T? xl,
  }) {
    final wd = MediaQuery.of(this).size.width;
    return wd >= 1280
        ? (xl ?? lg ?? md ?? sm ?? defaultVal)
        : wd >= 1024
            ? (lg ?? md ?? sm ?? defaultVal)
            : wd >= 768
                ? (md ?? sm ?? defaultVal)
                : wd >= 640
                    ? (sm ?? defaultVal)
                    : defaultVal;
  }
}

此扩展将侦听屏幕宽度的更改,并返回匹配的值,因此您的 gridView 将类似于以下方式:

GridView.count(
  crossAxisCount: context.responsive(2, sm: 2, md: 3, lg: 4, xl: 6),
  children: items
      .map(
        (final e) => Container(
          padding: const EdgeInsets.all(10),
          child: Text(e),
        ),
      )
      .toList(),
),

因此,随着屏幕宽度的增加,gridView 的 crossAxisCount 也会增加。

英文:

try adding this extension in your project:

extension Responsive on BuildContext {
  T responsive&lt;T&gt;(
    T defaultVal, {
    T? sm,
    T? md,
    T? lg,
    T? xl,
  }) {
    final wd = MediaQuery.of(this).size.width;
    return wd &gt;= 1280
        ? (xl ?? lg ?? md ?? sm ?? defaultVal)
        : wd &gt;= 1024
            ? (lg ?? md ?? sm ?? defaultVal)
            : wd &gt;= 768
                ? (md ?? sm ?? defaultVal)
                : wd &gt;= 640
                    ? (sm ?? defaultVal)
                    : defaultVal;
  }
}

this extension will listen to changes of screen width and return a matched value, so your gridView would be something like this:

GridView.count(
            crossAxisCount: context.responsive(2, sm: 2, md: 3, lg: 4, xl: 6),
            children: items
                .map(
                  (final e) =&gt; Container(
                    padding: const EdgeInsets.all(10),
                    child: Text(e),
                  ),
                )
                .toList(),
          ),

so gridView crossAxisCount will increase as long as the screen width goes larger.

答案3

得分: 0

为什么不使用SliverGrid?

它会类似于这样:

class MySliverGrid extends StatelessWidget {
  final double width;
  final List<Widget> widgets;
  const MySliverGrid({Key? key, required this.width, required this.widgets})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: [
        SliverGrid(
            delegate: SliverChildListDelegate(widgets),
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: MediaQuery.of(context).size.width ~/ width)),
      ],
    );
  }
}
英文:

why don't you use sliverGrid ?

it will be something like this :

class MySliverGrid extends StatelessWidget {
  final double width;
  final List&lt;Widget&gt; widgets;
  const MySliverGrid({Key? key, required this.width, required this.widgets})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: [
        SliverGrid(
            delegate: SliverChildListDelegate(widgets),
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: MediaQuery.of(context).size.width ~/ width)),
      ],
    );
  }
}

答案4

得分: 0

要实现类似Pinterest的瀑布流布局,容器宽度相同但高度不同,您可以使用flutter_staggered_grid_view包以及SliverGridDelegateWithFixedCrossAxisCount。这个组合允许您创建一个响应式的错列网格,根据可用的屏幕宽度来调整列数。

class PinterestGrid extends StatelessWidget {
  PinterestGrid({Key? key});

  // 创建容器高度的列表(您可以用实际数据替换它):
  final List<double> containerHeights = [150, 250, 200, 180, 220, 190];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Pinterest Like Grid'),
      ),
      body: StaggeredGridView.countBuilder(
        crossAxisCount: MediaQuery.of(context).size.width > 600 ? 3 : 2,
        itemCount: containerHeights.length,
        itemBuilder: (BuildContext context, int index) {
          return Container(
            color: Colors.blue,
            height: containerHeights[index],
            child: Center(
              child: Text('$index'),
            ),
          );
        },
        staggeredTileBuilder: (int index) => const StaggeredTile.fit(1),
        mainAxisSpacing: 8.0,
        crossAxisSpacing: 8.0,
      ),
    );
  }
}

不要忘记添加以下两行导入语句:

import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:flutter_staggered_grid_view/staggered_tile.dart';
英文:

To achieve a Pinterest-like grid layout with containers of the same width but different heights, you can use the flutter_staggered_grid_view package along with SliverGridDelegateWithFixedCrossAxisCount. This combination allows you to create a responsive staggered grid that adjusts the number of columns based on the available screen width.

class PinterestGrid extends StatelessWidget {
  PinterestGrid({super.key});

  //Create a list of container heights (you can replace this with your actual data):
  final List&lt;double&gt; containerHeights = [150, 250, 200, 180, 220, 190];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(&#39;Pinterest Like Grid&#39;),
      ),
      body: StaggeredGridView.countBuilder(
        crossAxisCount: MediaQuery.of(context).size.width &gt; 600 ? 3 : 2,
        itemCount: containerHeights.length,
        itemBuilder: (BuildContext context, int index) {
          return Container(
            color: Colors.blue,
            height: containerHeights[index],
            child: Center(
              child: Text(&#39;$index&#39;),
            ),
          );
        },
        staggeredTileBuilder: (int index) =&gt; const StaggeredTile.fit(1),
        mainAxisSpacing: 8.0,
        crossAxisSpacing: 8.0,
      ),
    );
  }
}

Don't forget to add this two

import &#39;package:staggered_grid_view_flutter/widgets/staggered_grid_view.dart&#39;;
import &#39;package:staggered_grid_view_flutter/widgets/staggered_tile.dart&#39;;

答案5

得分: 0

你可以尝试类似这样的代码(为了简单起见,它只包含在一个文件中,但如果适用于你,你可以使用你需要的代码块):

import 'package:flutter/material.dart';

// 假设这是你的数据模型类,具有 `title` 和 `height` 属性
class Item {
  final String title;
  final double height;

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

class MyApp extends StatelessWidget {
  // 这个小部件是你应用程序的根部件。
  @override
  Widget build(BuildContext context) {
    // 示例项目列表
    final List<Item> items = [
      Item('项目 1', 100.0),
      Item('项目 2', 200.0),
      Item('项目 3', 150.0),
      // 在此添加更多项目
    ];

    return MaterialApp(
      title: 'Flutter 示例',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter 示例主页'),
        ),
        body: GridView.builder(
          padding: EdgeInsets.all(10),
          // 根据屏幕宽度计算列数
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: calculateColumns(MediaQuery.of(context).size.width),
            mainAxisSpacing: 10,  // 根据需要调整
            crossAxisSpacing: 10,  // 根据需要调整
          ),
          itemCount: items.length,
          itemBuilder: (BuildContext context, int index) {
            return Container(
              height: items[index].height,
              child: Card(
                child: Center(
                  child: Text('项目 ${items[index].title}'),
                ),
              ),
            );
          },
        ),
      ),
    );
  }

  int calculateColumns(double screenWidth) {
    int columns = (screenWidth ~/ 150);  // 根据需要调整列宽
    return columns > 0 ? columns : 1;
  }
}

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

希望这对你有帮助。

英文:

You may try something like this: (its in just one file due simplicity, but if it works fine for ya you may use the block of code you may need)

import &#39;package:flutter/material.dart&#39;;

// Assuming this is your data model class with `title` and `height` properties
class Item {
  final String title;
  final double height;

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    // Sample list of Items
    final List&lt;Item&gt; items = [
      Item(&#39;Item 1&#39;, 100.0),
      Item(&#39;Item 2&#39;, 200.0),
      Item(&#39;Item 3&#39;, 150.0),
      // Add more items here
    ];

    return MaterialApp(
      title: &#39;Flutter Demo&#39;,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text(&#39;Flutter Demo Home Page&#39;),
        ),
        body: GridView.builder(
          padding: EdgeInsets.all(10),
          // Calculates the number of columns based on the screen width
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: calculateColumns(MediaQuery.of(context).size.width),
            mainAxisSpacing: 10,  // Adjust as needed
            crossAxisSpacing: 10,  // Adjust as needed
          ),
          itemCount: items.length,
          itemBuilder: (BuildContext context, int index) {
            return Container(
              height: items[index].height,
              child: Card(
                child: Center(
                  child: Text(&#39;Item ${items[index].title}&#39;),
                ),
              ),
            );
          },
        ),
      ),
    );
  }

  int calculateColumns(double screenWidth) {
    int columns = (screenWidth ~/ 150);  // Adjust the column width as needed
    return columns &gt; 0 ? columns : 1;
  }
}

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

huangapple
  • 本文由 发表于 2023年7月23日 19:10:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76747922.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定