【问题标题】:Flutter: How can I add dynamic number of columns depending on device width or orientation?Flutter:如何根据设备宽度或方向添加动态列数?
【发布时间】:2022-01-31 08:07:16
【问题描述】:

我有一个 Flutter 应用程序,它在其中一个页面中显示了一个包含 200 多个项目的列表。我怎样才能做到这一点,例如,当应用程序在桌面环境中运行时,它会动态显示多列,当它在手机上运行时,它会显示一列,或者当它在平板电脑上以垂直方向运行时,它会显示一列并且当设备处于水平方向时不止一列?

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 MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'something here',
            ),
            Text(
              'something here',
            ),
            Text(
              'something here',
            ),
            Text(
              'something here',
            ),
          ],
        ),
      ),
    );
  }
}

无论设备或方向如何,这都会生成一列。

【问题讨论】:

  • 你能分享你屏幕的完整代码吗?和平板电脑的屏幕截图?通常,无论方向如何,该列都必须保持为一列。
  • @ShadyMohamedSherif 有完整的代码。

标签: android flutter dart


【解决方案1】:

尝试使用GridView 而不是Column,这样您可以使用GridViewcrossAxisCount 属性调整列数。我过会儿再说。

让我们谈谈如何根据屏幕大小动态调整列数。例如,我想要移动设备中的单列、选项卡中的 2 列和桌面中的 4 列。

我将创建一个名为LayoutSizeenum,它代表不同的布局大小。还要创建一个扩展,根据LayoutSize 返回列数。

enum LayoutSize { small, medium, large }

extension LayoutSizeX on LayoutSize {
  int get noOfColumns {
    switch (this) {
      case LayoutSize.small:
        return 1;
      case LayoutSize.medium:
        return 2;
      case LayoutSize.large:
        return 4;
    }
  }
}

现在是时候考虑 Breakpoints 了,它代表不同 LayoutSize 的最大宽度。您可以根据需要更改数字。

abstract class Breakpoints {
  static const double small = 760;
  static const double medium = 1644;
  static const double large = 1920;
}

最后总结所有这些逻辑并创建 UI。这里LayoutBuilder 将用于在constraints 发生更改时更改列数。

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(builder: (context, constraints) {
      final screenWidth = MediaQuery.of(context).size.width;

      if (screenWidth <= Breakpoints.small) {
        return _buildMyWidget(LayoutSize.small);
      }

      if (screenWidth <= Breakpoints.medium) {
        return _buildMyWidget(LayoutSize.medium);
      }

      if (screenWidth <= Breakpoints.large) {
        return _buildMyWidget(LayoutSize.large);
      }

      return _buildMyWidget(LayoutSize.small);
    });
  }

  Widget _buildMyWidget(LayoutSize size) {
    return GridView.builder(
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: size.noOfColumns,
      ),
      itemBuilder: (context, index) {
        return Container();
      },
    );
  }
}

我知道这个解决方案需要一些额外的编码,但相信我,从长远来看,这将非常有效,即使是在构建整个应用响应式时,而不仅仅是特定的小部件。

这是您在这种特殊情况下需要编写的最少代码。但是,如果您对更通用的方式感兴趣,这里有一个指向 gist 的链接。

【讨论】:

    【解决方案2】:

    您可以通过两种方式有条件地添加列表项:

    使用if() 声明:

      Column(
        children: [
          ListTile(
            ...
          ),
          if (_condition)
            Container(
              ...
            ),
        ],
      ),
    

    使用条件如下:

    Column (
      children: [
        x == 1 ? Widget1() : Widget2(),
      ],
    )
    

    这里你需要弄清楚操作系统和屏幕类型,Platform Class 会给你一些关于操作系统的信息:

    import 'dart:io' show Platform;
    
    if (Platform.isWindows) ...
    

    MediaQuery 类将为您提供有关屏幕和尺寸的有用信息:

    final isLandscape = (MediaQuery.of(context).orientation == Orientation.landscape);
    

    没有直接的方法可以确定设备是平板电脑还是手机,但是有一些技巧可以获取设备类型,here are some examples

    你需要结合这些方法来实现你想要的

    【讨论】:

    • 请停止使用 MediaQuery。首选的解决方案是 LayoutBuilder。
    • @RandalSchwartz 这取决于你如何使用它
    猜你喜欢
    • 1970-01-01
    • 2023-03-12
    • 2013-06-29
    • 2012-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-28
    • 1970-01-01
    相关资源
    最近更新 更多