该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
BambooCaep原创,转载请注明。
目前许多手机的屏幕分辨率大小不一,可以相差两三倍,但是屏幕尺寸并不会同比增加。为了使得显示出的界面能够适应不同的分辨率,英巴在FMX平台使用了
TWindowManager.Scale这个属性来进行屏幕缩放调整。
在FMX.Platform.Android.pas文件里,是使用SetScreenScaleOverrideHook来更改屏幕缩放比例的。
type
TScreenScaleOverrideHook = procedure(const UserContext: Pointer; const DensityScale, DensityDPI: Single;
var ScreenScale: Single);
procedure SetScreenScaleOverrideHook(const UserContext: Pointer; const Hook: TScreenScaleOverrideHook);
begin
ScreenScaleOverrideHook := Hook;
ScreenScaleOverrideHookContext := UserContext;
end;
function TPlatformAndroid.GetScreenScale: Single;
const
// Default values taken from Android SDK reference:
// http://developer.android.com/reference/android/util/DisplayMetrics.html#density
DefaultDensityScale = 1;
DefaultDensityDPI = 160;
var
Metrics: JDisplayMetrics;
DensityScale, DensityDPI: Single;
begin
if SameValue(FScreenScale, 0, TEpsilon.Scale) then
begin
Metrics := GetJDisplayMetrics;
if Assigned(Metrics) then
begin
DensityScale := Metrics.density; // API level 1
DensityDPI := Metrics.densityDpi; // API level 4
end
else
begin
DensityScale := DefaultDensityScale;
DensityDPI := DefaultDensityDPI;
end;
FScreenScale := DensityScale;
if Assigned(ScreenScaleOverrideHook) then
begin
ScreenScaleOverrideHook(ScreenScaleOverrideHookContext, DensityScale, DensityDPI, FScreenScale);
if FScreenScale < 1 then
FScreenScale := 1
else if FScreenScale > 3 then
FScreenScale := 3;
end;
end;
Result := FScreenScale;
end;
constructor TWindowManager.Create;
begin
......
FScale := PlatformAndroid.GetScreenScale;
......
end;
看起来相当美好。然而下述代码并不能生效,引用该单元后屏幕缩放比例并未改变。
unit TestScreenScale;
uses
FMX.Platform.Android;
implementation
procedure MyHook(const UserContext: Pointer; const DensityScale, DensityDPI: Single;
var ScreenScale: Single);
begin
ScreenScale := ScreenScale / 2;
end;
initialization
SetScreenScaleOverrideHook(nil, MyHook);
end.
原因就在于,调用SetScreenScaleOverrideHook必须引用FMX.Platform.Android。而FMX.Platform.Android引用了FMX.Platform,但是FMX.Platform在初始化时调用了
RegisterCorePlatformServices方法,在Android系统下就是调用FMX.Platform.Android里面的RegisterCorePlatformServices方法。
于是,在我们SetScreenScaleOverrideHook之前,PlatformAndroid实例已经被创建了。
constructor TPlatformAndroid.Create;
begin
......
PlatformAndroid := Self;
TWindowManager.Current;
......
end;
于是,TWindowManager也有了实例,不会再创建。
结果就是:在我们SetScreenScaleOverrideHook之前,就已经注定不会再使用到这个Hook了!
解决方法倒是简单:
procedure SetScreenScaleOverrideHook(const UserContext: Pointer; const Hook: TScreenScaleOverrideHook);
begin
ScreenScaleOverrideHook := Hook;
ScreenScaleOverrideHookContext := UserContext;
PlatformAndroid.FScreenScale := 0; //保证GetScreenScale时会重新计算
TWindowManager.Current.FScale := PlatformAndroid.GetScreenScale; //重新获取Hook后的Scale。
end;