[FMX]太糊弄了,请不要使用 FMX.Platform.Win 中 GetDisplayMatrics 来获取物理信息

上官方的实现源码:

function TPlatformWin.GetDisplayMetrics: TDeviceDisplayMetrics;
var
  R: TRect;
begin
  Winapi.Windows.GetWindowRect(GetDesktopWindow, R);
  Result.PhysicalScreenSize := TSize.Create(R.Width, R.Height);
  Result.RawScreenSize := Result.PhysicalScreenSize;
  Result.LogicalScreenSize := Result.PhysicalScreenSize;
  if Result.PhysicalScreenSize.cx > 0 then
    Result.AspectRatio := Result.PhysicalScreenSize.cy / Result.PhysicalScreenSize.cx
  else
    Result.AspectRatio := 1;
  Result.PixelsPerInch := 96; // Windows Default
  Result.ScreenScale := 1;
  Result.FontScale := 1;
end;

对比 Android 版本:

function TAndroidScreenServices.GetDisplayMetrics: TDeviceDisplayMetrics;
var
  Metrics: JDisplayMetrics;
  RawScreenSize: JPoint;
  DensityDPI: Single;
begin
  Metrics := TAndroidHelper.DisplayMetrics;
  if Metrics <> nil then
  begin
    Result.PhysicalScreenSize := TSize.Create(Metrics.widthPixels, Metrics.heightPixels);
    DensityDPI := Round((Metrics.xdpi + Metrics.ydpi) / 2);
    if DensityDPI <> 0 then
    begin
      Result.LogicalScreenSize.cx := Trunc(Metrics.widthPixels / DensityDPI);
      Result.LogicalScreenSize.cy := Trunc(Metrics.heightPixels / DensityDPI);
    end
    else
      Result.LogicalScreenSize := Result.PhysicalScreenSize;
    if Metrics.widthPixels <> 0 then
      Result.AspectRatio := Metrics.heightPixels / Metrics.widthPixels
    else
      Result.AspectRatio := 1;
    Result.PixelsPerInch := Round(DensityDPI);
    Result.ScreenScale := Metrics.density;
    Result.FontScale := Metrics.scaledDensity;
  end
  else
    Result := TDeviceDisplayMetrics.Default;
  RawScreenSize := MainActivity.getRawDisplaySize;
  if RawScreenSize <> nil then
    if (Result.PhysicalScreenSize.cx > Result.PhysicalScreenSize.cy) and (RawScreenSize.x > RawScreenSize.y) then
      Result.RawScreenSize := TSize.Create(RawScreenSize.x, RawScreenSize.y)
    else
      Result.RawScreenSize := TSize.Create(RawScreenSize.y, RawScreenSize.x)
  else
    Result.RawScreenSize := Result.PhysicalScreenSize;
end;

再对比 iOS 的:

function TCocoaTouchScreenServices.GetDisplayMetrics: TDeviceDisplayMetrics;
const
  IOSBasePPI = 163;
var
  ScreenSize: TPointF;
  ScreenScale: Single;
begin
  ScreenSize := GetScreenSize;
  ScreenScale := GetScreenScale;
  Result.PhysicalScreenSize := TSize.Create(Round(ScreenSize.X * ScreenScale), Round(ScreenSize.Y * ScreenScale));
  Result.RawScreenSize := Result.PhysicalScreenSize;
  Result.LogicalScreenSize := TSize.Create(Round(ScreenSize.X), Round(ScreenSize.Y));
  if Abs(ScreenSize.X) > 0 then
    Result.AspectRatio := ScreenSize.Y / ScreenSize.X
  else
    Result.AspectRatio := 1;
  Result.PixelsPerInch := Round(IOSBasePPI * ScreenScale);
  Result.ScreenScale := ScreenScale;
  Result.FontScale := ScreenScale;
end;

换句话说,Windows 版的物理屏幕尺寸、逻辑屏幕尺寸和原始屏幕尺寸是一个东西,并不会反馈实际的显示器信息。要在 Windows 下获取屏幕的物理尺寸,可以调用 GetDeviceCaps 获取,索引为 HORZSIZE 和VERTSIZE,对应水平和垂直长度,单位为毫米。

分享到: