Flutter屏幕显示模式管理插件flutter_displaymode的使用

发布于 1周前 作者 htzhanglong 来自 Flutter

Flutter屏幕显示模式管理插件flutter_displaymode的使用

Flutter Display Mode

pub package

flutter_displaymode 是一个Flutter插件,用于在Android设备上设置显示模式。它有助于在具有离散帧速率(如60Hz、90Hz等)的设备上启用高刷新率。对于具有LTPO面板的设备和iOS设备上的ProMotion,此库无效。

该库应作为临时修复措施,直到相关API被添加到Flutter引擎中。

Getting Started

添加依赖

要使用此插件,请先将其添加到您的 pubspec.yaml 文件中,并重建您的应用程序:

flutter pub add flutter_displaymode

设置最高/最低帧速率

您可以使用辅助函数 FlutterDisplayMode.setHighRefreshRateFlutterDisplayMode.setLowRefreshRate 切换到最高或最低刷新率,同时保持当前分辨率。

// current: #1 1440x3120 @ 60Hz
// new: #2 1440x3120 @ 90Hz
await FlutterDisplayMode.setHighRefreshRate();

// current: #2 1440x3120 @ 90Hz
// new: #1 1440x3120 @ 60Hz
await FlutterDisplayMode.setLowRefreshRate();

获取支持的模式

FlutterDisplayMode.supported 返回所有可以设置为首选模式的模式。这始终返回 DisplayMode.auto 作为其中一个模式。

import 'package:flutter_displaymode/flutter_displaymode.dart';

try {
  modes = await FlutterDisplayMode.supported;
  modes.forEach(print);

  /// On OnePlus 7 Pro:
  /// #0 0x0 @0Hz // Automatic
  /// #1 1080x2340 @ 60Hz
  /// #2 1080x2340 @ 90Hz
  /// #3 1440x3120 @ 90Hz
  /// #4 1440x3120 @ 60Hz

  /// On OnePlus 8 Pro:
  /// #0 0x0 @0Hz // Automatic
  /// #1 1080x2376 @ 60Hz
  /// #2 1440x3168 @ 120Hz
  /// #3 1440x3168 @ 60Hz
  /// #4 1080x2376 @ 120Hz
} on PlatformException catch (e) {
  /// e.code =>
  /// noAPI - No API support. Only Marshmallow and above.
  /// noActivity - Activity is not available. Probably app is in background
}

获取当前活动模式

FlutterDisplayMode.active 获取当前活动的模式。请注意,这并不总是由 FlutterDisplayMode.setPreferredMode 设置的首选模式。它可以基于显示设置被系统更改。

final DisplayMode m = await FlutterDisplayMode.active;

设置首选模式

FlutterDisplayMode.setPreferredMode 更改首选模式。是否使用此模式取决于系统。有时系统可能会根据内部启发式算法选择不切换到此模式。请检查 FlutterDisplayMode.active 以查看它是否实际切换。

/// This setting is per session. 
/// Please ensure this was placed with `initState` of your root widget.
await FlutterDisplayMode.setPreferredMode(modes[1]);

获取首选模式

FlutterDisplayMode.preferred 返回当前首选模式。如果未手动使用 FlutterDisplayMode.setPreferredMode 设置,则它将是 DisplayMode.auto

final DisplayMode m = await FlutterDisplayMode.preferred;

完整示例

以下是一个完整的示例,展示了如何使用 flutter_displaymode 插件来管理屏幕显示模式。

import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:flutter_displaymode/flutter_displaymode.dart';

void main() => runApp(MaterialApp(home: MyApp()));

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  List<DisplayMode> modes = <DisplayMode>[];
  DisplayMode? active;
  DisplayMode? preferred;

  final ValueNotifier<int> page = ValueNotifier<int>(0);
  late final PageController controller = PageController()
    ..addListener(() {
      page.value = controller.page!.round();
    });

  @override
  void initState() {
    super.initState();
    SchedulerBinding.instance.addPostFrameCallback((_) {
      fetchAll();
    });
  }

  Future<void> fetchAll() async {
    try {
      modes = await FlutterDisplayMode.supported;
      modes.forEach(print);

      /// On OnePlus 7 Pro:
      /// #1 1080x2340 @ 60Hz
      /// #2 1080x2340 @ 90Hz
      /// #3 1440x3120 @ 90Hz
      /// #4 1440x3120 @ 60Hz

      /// On OnePlus 8 Pro:
      /// #1 1080x2376 @ 60Hz
      /// #2 1440x3168 @ 120Hz
      /// #3 1440x3168 @ 60Hz
      /// #4 1080x2376 @ 120Hz
    } on PlatformException catch (e) {
      print(e);

      /// e.code =>
      /// noAPI - No API support. Only Marshmallow and above.
      /// noActivity - Activity is not available. Probably app is in background
    }

    preferred = await FlutterDisplayMode.preferred;

    active = await FlutterDisplayMode.active;

    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Plugin example app')),
        body: Padding(
          padding: const EdgeInsets.only(top: 16, left: 16, right: 16),
          child: PageView(
            controller: controller,
            children: <Widget>[
              Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Row(
                    children: <Widget>[
                      Text(
                        'Available modes',
                        style: Theme.of(context).textTheme.headlineSmall,
                      ),
                      TextButton.icon(
                        icon: const Icon(Icons.refresh),
                        onPressed: () {
                          fetchAll();
                        },
                        label: const Text('Fetch'),
                      ),
                    ],
                  ),
                  if (modes.isEmpty) const Text('Nothing here'),
                  Expanded(
                    child: ListView.builder(
                      itemCount: modes.length,
                      itemBuilder: (_, int i) {
                        final DisplayMode mode = modes[i];
                        return Row(
                          children: <Widget>[
                            Radio<DisplayMode>(
                              value: mode,
                              groupValue: preferred,
                              onChanged: (DisplayMode? newMode) async {
                                await FlutterDisplayMode.setPreferredMode(newMode!);
                                await Future.delayed(const Duration(milliseconds: 100));
                                await fetchAll();
                                setState(() {});
                              },
                            ),
                            if (mode == DisplayMode.auto)
                              const Text('Automatic')
                            else
                              Text(mode.toString()),
                            if (mode == active) const Text(' [ACTIVE]'),
                          ],
                        );
                      },
                    ),
                  ),
                  if (modes.isNotEmpty) const Divider(),
                  if (modes.isNotEmpty)
                    Row(
                      children: <Widget>[
                        ElevatedButton(
                          onPressed: () async {
                            await FlutterDisplayMode.setHighRefreshRate();
                            await Future.delayed(const Duration(milliseconds: 100));
                            await fetchAll();
                            setState(() {});
                          },
                          child: const Text('Highest Hz'),
                        ),
                        const SizedBox(width: 8),
                        ElevatedButton(
                          onPressed: () async {
                            await FlutterDisplayMode.setLowRefreshRate();
                            await Future.delayed(const Duration(milliseconds: 100));
                            await fetchAll();
                            setState(() {});
                          },
                          child: const Text('Lowest Hz'),
                        ),
                      ],
                    ),
                  const Divider(),
                ],
              ),
              ListView.builder(
                itemBuilder: (BuildContext _, int i) {
                  return Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Text('Index: $i'),
                  );
                },
              ),
            ],
          ),
        ),
        bottomNavigationBar: ValueListenableBuilder<int>(
          valueListenable: page,
          builder: (_, int page, __) => BottomNavigationBar(
            currentIndex: page,
            items: const <BottomNavigationBarItem>[
              BottomNavigationBarItem(
                icon: Icon(Icons.android),
                label: 'Modes',
              ),
              BottomNavigationBarItem(
                icon: Icon(Icons.list),
                label: 'Lists',
              ),
            ],
            onTap: (int i) => controller.animateToPage(
              i,
              duration: kTabScrollDuration,
              curve: Curves.easeOutQuart,
            ),
          ),
        ),
      ),
    );
  }
}

通过以上代码,您可以在Flutter应用程序中轻松管理屏幕显示模式。希望这对您有所帮助!


更多关于Flutter屏幕显示模式管理插件flutter_displaymode的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter屏幕显示模式管理插件flutter_displaymode的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用flutter_displaymode插件来管理屏幕显示模式的代码示例。flutter_displaymode插件允许你查询和设置设备的显示模式,比如分辨率和刷新率。

首先,确保你已经将flutter_displaymode添加到你的pubspec.yaml文件中:

dependencies:
  flutter:
    sdk: flutter
  flutter_displaymode: ^0.4.0  # 请检查最新版本号

然后运行flutter pub get来安装依赖。

接下来,你可以在Flutter应用中使用该插件。以下是一个完整的示例,展示如何查询和设置屏幕显示模式:

import 'package:flutter/material.dart';
import 'package:flutter_displaymode/flutter_displaymode.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Display Mode Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: DisplayModeScreen(),
    );
  }
}

class DisplayModeScreen extends StatefulWidget {
  @override
  _DisplayModeScreenState createState() => _DisplayModeScreenState();
}

class _DisplayModeScreenState extends State<DisplayModeScreen> {
  DisplayMode? currentDisplayMode;
  List<DisplayMode> availableModes = [];

  @override
  void initState() {
    super.initState();
    _queryDisplayMode();
  }

  Future<void> _queryDisplayMode() async {
    try {
      DisplayMode? mode = await FlutterDisplayMode.getDisplayMode();
      List<DisplayMode> modes = await FlutterDisplayMode.getAvailableDisplayModes();
      
      setState(() {
        currentDisplayMode = mode;
        availableModes = modes;
      });
    } catch (e) {
      print("Error querying display mode: $e");
    }
  }

  Future<void> _setDisplayMode(DisplayMode mode) async {
    try {
      bool success = await FlutterDisplayMode.setDisplayMode(mode);
      if (success) {
        setState(() {
          currentDisplayMode = mode;
        });
        print("Successfully set display mode to: ${mode.refreshRate}Hz, ${mode.width}x${mode.height}");
      } else {
        print("Failed to set display mode.");
      }
    } catch (e) {
      print("Error setting display mode: $e");
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Display Mode Management'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text('Current Display Mode:', style: TextStyle(fontWeight: FontWeight.bold)),
            if (currentDisplayMode != null) {
              Text(
                "${currentDisplayMode!.refreshRate}Hz, ${currentDisplayMode!.width}x${currentDisplayMode!.height}",
                style: TextStyle(fontSize: 18),
              ),
            } else {
              Text('Unknown', style: TextStyle(fontSize: 18, color: Colors.grey)),
            },
            SizedBox(height: 16),
            Text('Available Display Modes:', style: TextStyle(fontWeight: FontWeight.bold)),
            DropdownButton<DisplayMode>(
              value: currentDisplayMode,
              hint: Text('Select a mode'),
              onChanged: (DisplayMode? newValue) {
                if (newValue != null) {
                  _setDisplayMode(newValue);
                }
              },
              items: availableModes.map((DisplayMode mode) {
                return DropdownMenuItem<DisplayMode>(
                  value: mode,
                  child: Text("${mode.refreshRate}Hz, ${mode.width}x${mode.height}"),
                );
              }).toList(),
            ),
          ],
        ),
      ),
    );
  }
}

代码说明:

  1. 依赖添加:确保在pubspec.yaml中添加了flutter_displaymode依赖。
  2. 查询当前显示模式:在_queryDisplayMode函数中,使用FlutterDisplayMode.getDisplayMode()获取当前显示模式,并使用FlutterDisplayMode.getAvailableDisplayModes()获取所有可用的显示模式。
  3. 设置显示模式:在_setDisplayMode函数中,使用FlutterDisplayMode.setDisplayMode(mode)设置新的显示模式。
  4. UI展示:使用DropdownButton显示当前显示模式和所有可用的显示模式,用户可以选择新的显示模式并应用。

注意:不是所有设备都支持更改显示模式,某些操作可能需要设备管理员权限或特定硬件支持。运行此代码前,请确保你的设备支持这些操作,并处理可能出现的错误。

回到顶部