flutter在windows平台如何自定义dpi设置
系统层级的支持(windows平台对高dpi的支持)
主要有两点:
- 设置系统的缩放比例 (系统及系统自带的app会根据这个设置来进行缩放;自己的app需要结合自己设置的dpi awareness来实现对应的dpi支持)
- 设置进程的dpi awareness(这个会影响某些系统api的返回值)
以DPI_AWARENESS_CONTEXT_UNAWARE举个例子,如果设置了这个值,会有一下几个影响:
- 系统api,GetDpiForWindow的返回值是96,也就是1:1缩放时的值
- 系统会根据用户设置的缩放比例,等比例的对程序界面进行缩放,这样会造成模糊。
这个也就是说,在程序不支持高dpi,没有2x,3x等对应缩放的切图时,可以设置这个。
如果有对应的高dpi的切图,却设置了这个,会造成程序拿不到系统的真实的dpi(只能拿到96这个dpi值),无法准确的使用对应的高倍图片。
一、设置缩放比例
二、设置进程的 DPI Awareness
相关链接
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setprocessdpiawarenesscontext
https://learn.microsoft.com/en-us/windows/win32/hidpi/dpi-awareness-context?redirectedfrom=MSDN
框架层级的支持
QT
https://doc.qt.io/qt-5/highdpi.html
By default, Qt applications are set to Per-Monitor DPI Aware on Windows 8.1 or System-DPI Aware on older Windows versions. As of Qt 5.4, this level can be specified via a parameter to the platform plugin:
当然,可以通过系统api修改这个设置。系统api只能调一次,谁先调用谁生效。
QT还可以设置
QT_SCALE_FACTOR [numeric] defines a global scale factor for the whole application, including point-sized fonts.
来覆盖系统级别设置的缩放值,从而做到dpi的自定义设置。设置方式为:
qputenv("QT_SCALE_FACTOR", "3.0");
Flutter
不像QT,flutter没有可以覆盖系统定义的缩放值的方法。
修改flutter引擎源码,让flutter支持自定义设置dpi的缩放比例
看flutter的导出接口头文件flutter_windows.h可以发现两个api跟dpi相关,只能获取,无法设置。
// Gets the DPI for a given |hwnd|, depending on the supported APIs per
// windows version and DPI awareness mode. If nullptr is passed, returns the DPI
// of the primary monitor.
//
// This uses the same logic and fallback for older Windows versions that is used
// internally by Flutter to determine the DPI to use for displaying Flutter
// content, so should be used by any code (e.g., in plugins) that translates
// between Windows and Dart sizes/offsets.
FLUTTER_EXPORT UINT FlutterDesktopGetDpiForHWND(HWND hwnd);
// Gets the DPI for a given |monitor|. If the API is not available, a default
// DPI of 96 is returned.
//
// See FlutterDesktopGetDpiForHWND for more information.
FLUTTER_EXPORT UINT FlutterDesktopGetDpiForMonitor(HMONITOR monitor);
代码中的使用
bool Win32Window::Create(const std::wstring& title,
const Point& origin,
const Size& size) {
Destroy();
const wchar_t* window_class =
WindowClassRegistrar::GetInstance()->GetWindowClass();
const POINT target_point = {static_cast<LONG>(origin.x),
static_cast<LONG>(origin.y)};
HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST);
UINT dpi = FlutterDesktopGetDpiForMonitor(monitor);
double scale_factor = dpi / 96.0;
通过查看上面接口的源码,可以发现,flutter的所有dpi相关的代码,可以归结到源文件:
// engine/shell/platform/windows/dpi_utils.cc
UINT GetDpiForHWND(HWND hwnd) {
return GetHelper()->GetDpiForWindow(hwnd);
}
UINT GetDpiForMonitor(HMONITOR monitor) {
return GetHelper()->GetDpiForMonitor(monitor);
}
因为这两个值都是从系统拿到的缩放值,可以修改这两个接口,来覆盖系统的缩放值。
) {
return GetHelper()->GetDpiForMonitor(monitor);
}
因为这两个值都是从系统拿到的缩放值,可以修改这两个接口,来覆盖系统的缩放值。
知道了这个,就可以给flutter加个导出设置缩放值的接口,来达到QT下QT_SCALE_FACTOR的类似效果。