在 Flutter 中,你可以根据给定的屏幕方向构建不同的布局。例如,如果应用处于纵向(竖屏)模式,你可以用两列显示数据;如果处于横向(横屏)模式,则用三列显示数据。此外,你还可以创建测试来检查每个屏幕方向是否显示了正确数量的列。

在本教程中,你将学习如何检查应用的屏幕方向是纵向还是横向,以及每个屏幕方向显示了多少列。

本示例将采取以下步骤

  1. 创建一个根据屏幕方向更新内容布局的应用。
  2. 创建屏幕方向测试组。
  3. 创建纵向(竖屏)屏幕方向测试。
  4. 创建横向(横屏)屏幕方向测试。
  5. 运行测试。

1. 创建一个随屏幕方向更新的应用

#

创建一个 Flutter 应用,使其在纵向或横向模式下改变显示列数

  1. 创建一个名为 orientation_tests 的新 Flutter 项目。

    flutter create orientation_tests
  2. 按照根据屏幕方向更新 UI 中的步骤设置项目。

2. 创建屏幕方向测试组

#

设置好 orientation_tests 项目后,完成以下步骤来组织你未来的屏幕方向测试:

  1. 在你的 Flutter 项目中,打开 test/widget_test.dart

  2. 将现有内容替换为以下代码:

    widget_test.dart
    dart
    import 'package:flutter/material.dart';
    import 'package:flutter_test/flutter_test.dart';
    import 'package:orientation_tests/main.dart';
    
    void main() {
      group('Orientation', () {
        // ···
      });
    }

3. 创建纵向(竖屏)屏幕方向测试

#

将纵向屏幕方向测试添加到 Orientation 组中。此测试确保屏幕方向为纵向,并且应用中只显示 2 列数据。

  1. test/widget_test.dart 中,将 Orientation 组内的 ... 替换为以下测试代码:

    widget_test.dart
    dart
    // Check if portrait mode displays correctly.
    testWidgets('Displays 2 columns in portrait mode', (tester) async {
      // Build the app.
      await tester.pumpWidget(const MyApp());
    
      // Change to portrait.
      tester.view.physicalSize = const Size(600, 800);
      tester.view.devicePixelRatio = 1.0;
      addTearDown(() {
        tester.view.resetPhysicalSize();
      });
      await tester.pump();
    
      // Verify initial orientation is portrait.
      final orientation = MediaQuery.of(
        tester.element(find.byType(OrientationList)),
      ).orientation;
      expect(orientation, Orientation.portrait);
    
      // Verify there are only 2 columns in portrait mode.
      final gridViewFinder = find.byType(GridView);
      final gridView = tester.widget<GridView>(gridViewFinder);
      final delegate =
          gridView.gridDelegate as SliverGridDelegateWithFixedCrossAxisCount;
      expect(delegate.crossAxisCount, 2);
    });

4. 创建横向(横屏)屏幕方向测试

#

将横向屏幕方向测试添加到 Orientation 组中。此测试确保屏幕方向为横向,并且应用中只显示 3 列数据。

  1. test/widget_test.dart 中,在 Orientation 组内,在横向测试之后添加以下测试代码:

    widget_test.dart
    dart
    // Check if landscape mode displays correctly.
    testWidgets('Displays 3 columns in landscape mode', (tester) async {
      // Build the app.
      await tester.pumpWidget(const MyApp());
    
      // Change to landscape.
      tester.view.physicalSize = const Size(800, 600);
      tester.view.devicePixelRatio = 1.0;
      addTearDown(() {
        tester.view.resetPhysicalSize();
      });
      await tester.pump();
    
      // Verify initial orientation is landscape.
      final orientation = MediaQuery.of(
        tester.element(find.byType(OrientationList)),
      ).orientation;
      expect(orientation, Orientation.landscape);
    
      // Verify there are only 3 columns in landscape mode.
      final gridViewFinder = find.byType(GridView);
      final gridView = tester.widget<GridView>(gridViewFinder);
      final delegate =
          gridView.gridDelegate as SliverGridDelegateWithFixedCrossAxisCount;
      expect(delegate.crossAxisCount, 3);
    });

5. 运行测试

#

从项目根目录运行以下命令来执行测试:

flutter test test/widget_test.dart

完整示例

#
widget_test.dart
dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:orientation_tests/main.dart';

void main() {
  group('Orientation', () {
    // Check if portrait mode displays correctly.
    testWidgets('Displays 2 columns in portrait mode', (tester) async {
      // Build the app.
      await tester.pumpWidget(const MyApp());

      // Change to portrait.
      tester.view.physicalSize = const Size(600, 800);
      tester.view.devicePixelRatio = 1.0;
      addTearDown(() {
        tester.view.resetPhysicalSize();
      });
      await tester.pump();

      // Verify initial orientation is portrait.
      final orientation = MediaQuery.of(
        tester.element(find.byType(OrientationList)),
      ).orientation;
      expect(orientation, Orientation.portrait);

      // Verify there are only 2 columns in portrait mode.
      final gridViewFinder = find.byType(GridView);
      final gridView = tester.widget<GridView>(gridViewFinder);
      final delegate =
          gridView.gridDelegate as SliverGridDelegateWithFixedCrossAxisCount;
      expect(delegate.crossAxisCount, 2);
    });

    // Check if landscape mode displays correctly.
    testWidgets('Displays 3 columns in landscape mode', (tester) async {
      // Build the app.
      await tester.pumpWidget(const MyApp());

      // Change to landscape.
      tester.view.physicalSize = const Size(800, 600);
      tester.view.devicePixelRatio = 1.0;
      addTearDown(() {
        tester.view.resetPhysicalSize();
      });
      await tester.pump();

      // Verify initial orientation is landscape.
      final orientation = MediaQuery.of(
        tester.element(find.byType(OrientationList)),
      ).orientation;
      expect(orientation, Orientation.landscape);

      // Verify there are only 3 columns in landscape mode.
      final gridViewFinder = find.byType(GridView);
      final gridView = tester.widget<GridView>(gridViewFinder);
      final delegate =
          gridView.gridDelegate as SliverGridDelegateWithFixedCrossAxisCount;
      expect(delegate.crossAxisCount, 3);
    });
  });
}
main.dart
dart
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    const appTitle = 'Orientation Demo';

    return const MaterialApp(
      title: appTitle,
      home: OrientationList(title: appTitle),
    );
  }
}

class OrientationList extends StatelessWidget {
  final String title;

  const OrientationList({super.key, required this.title});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(title)),
      body: OrientationBuilder(
        builder: (context, orientation) {
          return GridView.count(
            // Create a grid with 2 columns in portrait mode, or
            // 3 columns in landscape mode.
            crossAxisCount: orientation == Orientation.portrait ? 2 : 3,
            // Generate 100 widgets that display their index in the list.
            children: List.generate(100, (index) {
              return Center(
                child: Text(
                  'Item $index',
                  style: TextTheme.of(context).displayLarge,
                ),
              );
            }),
          );
        },
      ),
    );
  }
}