制作自适应 Flutter 应用程序的最佳方法是什么?

What's the best way to make a adaptive flutter app?

我已经制作了很多 Flutter 应用程序,但我不太确定制作响应式应用程序的最佳方式是什么。我目前正在做的是根据屏幕大小制作所有小部件。

例如,渲染一个容器,而不是放一个固定大小的:

width: MediaQuery.of(context).size.width * 0.2;

因此,我所有的小部件都将与它们使用的 phone 相关,而不是使用不同的断点。这是正确的做法吗?

如果我应该使用断点,移动断点应该是什么?我知道对于一个网站,我会为 phone、Ipad、笔记本电脑、台式机等设置断点,但是对于小型 phone、中型 phone 和大phone?谢谢!

在 flutter 网页上,您可以找到一篇关于如何构建自适应 flutter 应用程序的好文章(参见 here)。

另一个选项,类似于基于屏幕的断点方法 是 abstract factory pattern.

为了实现抽象工厂模式,你首先需要一个抽象工厂和一个class,它决定了可用的屏幕尺寸(AdaptivityWidget):

abstract class IWidgetsFactory {

   // returns the factory regarding to the screen size
   static IWidgetsFactory getFactory(BuildContext context) {
    if (AdaptivityWidget.isTinyScreen(context)) {
      return TinyScreenFactory();
    } else if (AdaptivityWidget.isSmallScreen(context)) {
      return SmallScreenFactory();
    } else if (AdaptivityWidget.isMediumScreen(context)) {
      return MediumScreenFactory();
    } else {
      return LargeScreenFactory();
    }
  }

  // implement the abstract methods, which the concrete factories shall implement
  double getBurgerMenuIconSize();

  // and so on ...
}
/// [AdaptivityWidget] determines, which type of screen is available.
class AdaptivityWidget {

  /// Returns the current width depending on the current context.
  static double _getWidth(BuildContext context) {
    return MediaQuery.of(context).size.width;
  }

  /// Large screen is any screen whose width is more than 1200 pixels.
  static bool isLargeScreen(BuildContext context) {
    return _getWidth(context) >= 1200;
  }

  /// Medium screen is any screen whose width is less than 1200 pixels,
  /// and more than 799 pixels.
  static bool isMediumScreen(BuildContext context) {
    return _getWidth(context) >= 800 && _getWidth(context) < 1200;
  }

  /// Small screen is any screen whose width is less than 800 pixels,
  /// and more than 399.
  static bool isSmallScreen(BuildContext context) {
    return _getWidth(context) >= 400 && _getWidth(context) < 800;
  }

  /// Tiny Screen is any screen whose width is less than 400 pixels.
  static bool isTinyScreen(BuildContext context) {
    return _getWidth(context) < 400;
  }
}

之后你必须实现具体的工厂(我将在一个例子中展示):

/// Concrete factory for large screens.
class LargeScreenFactory extends IWidgetsFactory {
  /// Returns 48.0px.
  @override
  double getBurgerMenuIconSize() {
    return SizeT24S32M40L48().large;
  }
}

比起你的风格需要一个摘要class。这可能看起来像这样:

abstract class IStyle {
  /// Parameter for [TinyScreenFactory]
  dynamic get tiny;

  /// Parameter for [SmallScreenFactory]
  dynamic get small;

  /// Parameter for [MediumScreenFactory]
  dynamic get medium;

  /// Parameter for [LargeScreenFactory]
  dynamic get large;
}

具体实现如下所示:

class SizeT24S32M40L48 implements IStyle {

  @override
  double get large => 48.0;

  @override
  double get medium => 40.0;

  @override
  double get small => 32.0;

  @override
  double get tiny => 24.0;
}

在视图中使用它看起来像这样:

class View extends StatelessWidget implements IMyFactory, IMySize{
  @override
  Widget build(BuildContext context){
    return Icon(
      Icons.menu,
      size: getSize(getFactory(context)),
    );
  }
  
  /// Returns a widget factory.
  @override
  IWidgetsFactory getFactory(BuildContext context) {
    return IWidgetsFactory.getFactory(context);
  }

  /// Returns a single icon size.
  @override
  double getSize(IWidgetsFactory factory) {
    return factory.getBurgerMenuIconSize();
  }


}

IMySize 和 IMyFactory 可以如下所示:

abstract class IMySize {
  double getSize(IWidgetsFactory factory);
}

abstract class IMyFactory {
  IWidgetsFactory getFactory(BuildContext context);
}

您也可以使用抽象工厂模式来区分 Android 和 iOS 以生成特定于平台的行为。