我正在为一个客户从较旧的AppMethod版本移植到旧版项目(适用于iOS和Android的应用程序)到最新的RAD Studio版本(10.0 Berlin)。 MessageDlg
和类似项目在项目中经常使用,但这不再适用。应用程序显示一条消息,Android上不支持模态对话框。我知道并理解为什么Android平台会出现这种情况(所以请不要通过引用解释将此问题标记为公开 - 我要求其他东西!)。
Firemonkey允许设置一个匿名函数,在用户点击对话框中的按钮或关闭按钮后异步执行。但是,通常的代码取决于用户决策或在对话框之后必须执行的代码,无论用户点击哪个按钮。例如,对话框必须在正在进行的操作过程中询问用户他的决定。然后,进一步的操作取决于用户的决定(这可能还包括在当前应用程序中停止进一步的代码执行!)。由于RAD Studio不支持在Android上阻止对话框,我似乎被迫分解我的代码 - 从一个功能到多个功能(可读性更差......)。当存在嵌套函数调用以及可能需要用户交互的模式对话框时,这会变得更加复杂。
还有办法以某种方式模拟阻止对话框吗?它不一定是完美的。我只是不想重写很多代码,甚至将小代码片段外包到许多单独的函数中,无论在哪里需要用户交互。
好的,我认为以下“脏”的解决方案对我来说可能就足够了:
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.DialogService,
FMX.Controls.Presentation, FMX.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
blockDlg: array[0..99] of Boolean;
blockDlgIdx: Integer = 0;
implementation
{$R *.fmx}
procedure NShowMessageAsync(AMessage: String);
begin
TDialogService.ShowMessage(AMessage);
end;
procedure NShowMessageSync(AMessage: String);
var
locBlockIdx: Integer;
begin
if blockDlgIdx = Length(blockDlg)-1 then blockDlgIdx := 0 else Inc(blockDlgIdx);
locBlockIdx := blockDlgIdx;
blockDlg[locBlockIdx] := true;
TDialogService.ShowMessage(AMessage,
procedure(const AResult: TModalResult)
begin
blockDlg[locBlockIdx] := false;
end);
while blockDlg[locBlockIdx] do begin
Sleep(40);
Application.ProcessMessages();
end;
end;
procedure NMessageDialogAsync(const AMessage: string; const ADialogType: TMsgDlgType;
const AButtons: TMsgDlgButtons; const ADefaultButton: TMsgDlgBtn;
const AHelpCtx: LongInt);
begin
TDialogService.MessageDialog(AMessage, ADialogType, AButtons, ADefaultButton,
AHelpCtx, procedure(const AResult: TModalResult) begin end);
end;
function NMessageDialogSync(const AMessage: string; const ADialogType: TMsgDlgType;
const AButtons: TMsgDlgButtons; const ADefaultButton: TMsgDlgBtn;
const AHelpCtx: LongInt): TModalResult;
var
locBlockIdx: Integer;
LModalResult: TModalResult;
begin
Result := -1;
if blockDlgIdx = Length(blockDlg)-1 then blockDlgIdx := 0 else Inc(blockDlgIdx);
locBlockIdx := blockDlgIdx;
blockDlg[locBlockIdx] := true;
TDialogService.MessageDialog(AMessage, ADialogType, AButtons, ADefaultButton, AHelpCtx,
procedure(const AResult: TModalResult)
begin
LModalResult := AResult;
blockDlg[locBlockIdx] := false;
end);
while blockDlg[locBlockIdx] do begin
Sleep(40);
Application.ProcessMessages();
end;
Result := LModalResult;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
mr: TModalResult;
begin
mr := NMessageDialogSync('1',
System.UITypes.TMsgDlgType.mtInformation,
[System.UITypes.TMsgDlgBtn.mbYes, System.UITypes.TMsgDlgBtn.mbNo, System.UITypes.TMsgDlgBtn.mbCancel],
System.UITypes.TMsgDlgBtn.mbYes,
0);
NShowMessageSync(IntToStr(mr));
mr := NMessageDialogSync('2',
System.UITypes.TMsgDlgType.mtWarning,
[System.UITypes.TMsgDlgBtn.mbYesToAll, System.UITypes.TMsgDlgBtn.mbAbort],
System.UITypes.TMsgDlgBtn.mbAbort,
0);
NShowMessageSync(IntToStr(mr));
mr := NMessageDialogSync('3',
System.UITypes.TMsgDlgType.mtInformation,
[System.UITypes.TMsgDlgBtn.mbIgnore, System.UITypes.TMsgDlgBtn.mbAll, System.UITypes.TMsgDlgBtn.mbHelp, System.UITypes.TMsgDlgBtn.mbClose],
System.UITypes.TMsgDlgBtn.mbClose,
0);
NShowMessageSync(IntToStr(mr));
Form1.Fill.Kind := TBrushKind.Solid;
if Form1.Fill.Color = TAlphaColors.Red then
Form1.Fill.Color := TAlphaColors.Blue
else
Form1.Fill.Color := TAlphaColors.Red;
end;
end.
不是很干净,但至少我可以使用它一段时间。