for B in AButtons do begin if ButtonIndex < ButtonsCount then begin LCaptions.Items[ButtonIndex] := StringToJString(ButtonCaptions[B]); if ADefaultButton = B then begin DefaultButton := ModalResults[B]; end; case ButtonIndex of 0: PosButton := ModalResults[B]; 1: NegButton := ModalResults[B]; 2: NeutralButton := ModalResults[B]; end; end; Inc(ButtonIndex); end;
DialogFactory := TJFMXDialogFactory.JavaClass.getFactory; if DialogFactory <> nil then begin CallInUIThreadAndWaitFinishing( procedure begin AlertDialog := DialogFactory.createMessageDialog(MainActivity, GetNativeTheme, StringToJString(AMessage), Ord(ADialogType), LCaptions, PosButton, NegButton, NeutralButton);
if AlertDialog <> nil then begin if DefaultButton > 0 then begin AlertDialog.getRealDialog.setCancelable(MessageDialog_Canceleable); AlertDialog.getRealDialog.setCanceledOnTouchOutside( MessageDialog_CanceledOnTouchOutsid); end else begin AlertDialog.getRealDialog.setCancelable(False); AlertDialog.getRealDialog.setCanceledOnTouchOutside(False); end; if Assigned(ACloseDialogProc) then begin DialogListener := TFMXDialogListener.Create( procedure (const AResult: TModalResult; const AValues: array of string) begin ACloseDialogProc(AResult); end, DefaultButton); DialogListener.ParentList := FAlertListeners; AlertDialog.setListener(DialogListener); end; AlertDialog.show; end; end); end; end;
【第七步】 找到 function TPlatformAndroid.InputQuery(const ACaption: string; const APrompts: array of string; var AValues: array of string; const ACloseQueryFunc: TInputCloseQueryFunc): Boolean; 修改这个函数的代码,改成如下内容。 //Fix By Flying Wang function TPlatformAndroid.InputQuery(const ACaption: string; const APrompts: array of string; var AValues: array of string; const ACloseQueryFunc: TInputCloseQueryFunc): Boolean; var ARetVal: Integer; I, J: Integer; CValues: array of string; begin //raise ENotImplemented.CreateFmt(SNotImplementedOnPlatform, [SBlockingDialogs]); Result := False; ARetVal := -1; InputQuery(ACaption, APrompts, AValues, procedure(const AResult: TModalResult; const BValues: array of string) var I, J: Integer; AStr: string; begin ARetVal := AResult; if ARetVal = mrOK then begin if Assigned(ACloseQueryFunc) then ACloseQueryFunc(BValues); SetLength(CValues, Length(BValues)); for I := Low(BValues) to High(BValues) do begin J := Low(CValues) + I - Low(BValues); if J <= High(CValues) then CValues[J] := BValues[I]; end; end; end); while ARetVal < 0 do begin Sleep(BlockingMessageWaitMilliSeconds); Application.ProcessMessages; end; Result := ARetVal = mrOK; if Result then begin for I := Low(CValues) to High(CValues) do begin J := Low(AValues) + I - Low(AValues); if J <= High(AValues) then AValues[J] := CValues[I]; end; end; end;
【第八步】 找到 procedure TPlatformAndroid.InputQuery(const ACaption: string; const APrompts, ADefaultValues: array of string; const ACloseQueryProc: TInputCloseQueryProc); 修改这个函数的代码,改成如下内容。 //Fix By Flying Wang procedure TPlatformAndroid.InputQuery(const ACaption: string; const APrompts, ADefaultValues: array of string; const ACloseQueryProc: TInputCloseQueryProc); var DialogFactory: JFMXDialogFactory; QueryDialog: JFMXStandardDialog; JavaPrompts: TJavaObjectArray<JString>; JavaDefaultValues: TJavaObjectArray<JString>; DialogListener: TFMXDialogListener; LCaptions: TJavaObjectArray<JString>; I: Integer; begin if Length(ADefaultValues) < Length(APrompts) then raise EInvalidOperation.Create(SPromptArrayTooShort); if Length(APrompts) = 0 then raise EInvalidOperation.Create(SPromptArrayEmpty);
JavaPrompts := TJavaObjectArray<JString>.Create(Length(APrompts)); JavaDefaultValues := TJavaObjectArray<JString>.Create(Length(ADefaultValues)); for I := 0 to Length(APrompts) - 1 do JavaPrompts[I] := StringToJString(APrompts[I]); for I := 0 to Length(ADefaultValues) - 1 do JavaDefaultValues[I] := StringToJString(ADefaultValues[I]); LCaptions := TJavaObjectArray<JString>.Create(2); LCaptions.Items[0] := StringToJString(ButtonCaptions[TMsgDlgBtn.mbOK]); LCaptions.Items[1] := StringToJString(ButtonCaptions[TMsgDlgBtn.mbCancel]); DialogFactory := TJFMXDialogFactory.JavaClass.getFactory; if DialogFactory <> nil then begin CallInUIThreadAndWaitFinishing( procedure begin QueryDialog := DialogFactory.createInputQueryDialog(MainActivity, GetNativeTheme, StringToJString(ACaption), JavaPrompts, JavaDefaultValues, LCaptions); if QueryDialog <> nil then begin QueryDialog.getRealDialog.setCancelable(MessageDialog_Canceleable); QueryDialog.getRealDialog.setCanceledOnTouchOutside( MessageDialog_CanceledOnTouchOutsid); if Assigned(ACloseQueryProc) then begin DialogListener := TFMXDialogListener.Create(ACloseQueryProc, ModalResults[TMsgDlgBtn.mbCancel]); DialogListener.ParentList := FAlertListeners; QueryDialog.setListener(DialogListener); end; QueryDialog.show; end; end); end; end;
//Fix By Flying Wang. constructor TFMXDialogListener.Create(const AInputCloseQueryProc: TInputCloseQueryProc; ADefaultButtonIndex: Integer); begin inherited Create; FDefaultButtonIndex := ADefaultButtonIndex; FInputCloseQueryProc := AInputCloseQueryProc; end;
//Fix By Flying Wang. procedure TFMXDialogListener.DoDialogClosed; begin //非常幸运的是,正常的返回都大于 0 。 if FModalResult <= 0 then FModalResult := FDefaultButtonIndex; FInputCloseQueryProc(FModalResult, FValues); if FParentList <> nil then FParentList.Remove(Self); FParentList := nil; end;
----------------------------------------------
(C)(P)Flying Wang
【第一步】 打开 FMX.VirtualKeyboard.Android 找到 function TVirtualKeyboardAndroid.GetVirtualKeyboardState: TVirtualKeyboardStates; begin if FError then Result := [TVirtualKeyboardState.Error] else Result := []; if IsAutoShow then Result := Result + [TVirtualKeyboardState.AutoShow]; if FTransient then Result := Result + [TVirtualKeyboardState.Transient]; if not FError then begin if FState = TvkbState.Shown then Result := Result + [TVirtualKeyboardState.Visible]; end; end;
将上面的函数修改为 //Fix Error By 爱吃猪头肉 & Flying Wang function ObtainKeyboardRect: TRect; var ContentRect, TotalRect: JRect; begin ContentRect := TJRect.Create; TotalRect := TJRect.Create; MainActivity.getWindow.getDecorView.getWindowVisibleDisplayFrame(ContentRect); MainActivity.getWindow.getDecorView.getDrawingRect(TotalRect); Result := TRectF.Create(ConvertPixelToPoint(TPointF.Create(TotalRect.left, TotalRect.top + ContentRect.height)), ConvertPixelToPoint(TPointF.Create(TotalRect.right, TotalRect.bottom))).Truncate; end;
function GetVirtualKeyboardHeight: Single; var KeyboardRect: TRect; begin Result := 0; KeyboardRect := ObtainKeyboardRect; //目前设置为 低于 30 就算隐藏。 if (KeyboardRect.Width < 30) or (KeyboardRect.Height < 30) then begin exit; end; Result := KeyboardRect.Height; end;
procedure ProcessVirtualKeyboardEvent; var VirtualKeyboard: IFMXVirtualKeyboardService; VirtualKeyboardAndroid: TVirtualKeyboardAndroid; begin if TPlatformServices.Current.SupportsPlatformService(IFMXVirtualKeyboardService, IInterface(VirtualKeyboard)) then begin VirtualKeyboardAndroid := TVirtualKeyboardAndroid(VirtualKeyboard); VirtualKeyboardAndroid.GetVirtualKeyBoardState; end; end;
function HideInputForFixVirtualKeyboardEvent :Boolean; var TextView: JFMXTextEditorProxy; begin Result := False; try Screen.ActiveForm.Focused := nil; TextView := MainActivity.getTextEditorProxy; CallInUIThread( procedure begin TextView.setFocusable(false); TextView.setFocusableInTouchMode(false); end); Result := True; except Application.HandleException(Screen.ActiveForm); end; end;
function TVirtualKeyboardAndroid.GetVirtualKeyboardState: TVirtualKeyboardStates; var KeyboardRect: TRect; begin if FError then Result := [TVirtualKeyboardState.Error] else Result := []; if IsAutoShow then Result := Result + [TVirtualKeyboardState.AutoShow]; if FTransient then Result := Result + [TVirtualKeyboardState.Transient]; if not FError then begin if (FState = TvkbState.Shown) then begin if GetVirtualKeyboardHeight < 1 then begin KeyboardRect := ObtainKeyboardRect; TThread.Synchronize(nil, procedure begin SetState(TVirtualKeyboardAndroid.TvkbState.Hidden); TMessageManager.DefaultManager.SendMessage(Self, TVKStateChangeMessage.Create(false, ObtainKeyboardRect), True); end); end; end; if FState = TvkbState.Shown then Result := Result + [TVirtualKeyboardState.Visible]; end; end;
4 或者对每个输入框的按下事件处理。 uses FMX.Platform, FMX.VirtualKeyboard; //使用这个事件 procedure TForm1.Edit1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); var VirtualKeyboard: IFMXVirtualKeyboardService; begin {$IFDEF ANDROID} if GetVirtualKeyboardHeight < 1 then begin if TPlatformServices.Current.SupportsPlatformService(IFMXVirtualKeyboardService, IInterface(VirtualKeyboard)) then begin if not (TVirtualKeyboardState.Visible in VirtualKeyboard.VirtualKeyBoardState) then begin if (TVirtualKeyboardState.AutoShow in VirtualKeyboard.VirtualKeyBoardState) then VirtualKeyboard.ShowVirtualKeyboard(Edit1); end; end; end; {$ENDIF} end;
----------------------------------------------
(C)(P)Flying Wang
//Add By Flying Wang. procedure ShowMessageWait(const AMessage: string); var RetVal: Integer; begin {$IFDEF ANDROID} FMX.Platform.Android.ShowMessageWait(AMessage); {$ELSE} ShowMessage(AMessage); {$ENDIF ANDROID} end;
procedure TMessageAlertsForm.btnStandardAlertClick(Sender: TObject); begin //Fix By Flying wang {$IFDEF ANDROID} MessageDialog_CanceledOnTouchOutsid := CheckBox1.IsChecked; MessageDialog_Canceleable := CheckBox2.IsChecked; {$ENDIF ANDROID} ShowMessageWait('还有一个对话框'); ShowMessageWait('Hello World!' + sLineBreak + 'Test Other Button.'); end;
procedure TMessageAlertsForm.btnMultiButtonAlertClick(Sender: TObject); var BResult: TModalResult; begin //Fix By Flying wang {$IFDEF ANDROID} MessageDialog_CanceledOnTouchOutsid := CheckBox1.IsChecked; MessageDialog_Canceleable := CheckBox2.IsChecked; {$ENDIF ANDROID} // MessageDlg('Choose a button:', System.UITypes.TMsgDlgType.mtInformation, // [ // System.UITypes.TMsgDlgBtn.mbYes, // System.UITypes.TMsgDlgBtn.mbNo, // System.UITypes.TMsgDlgBtn.mbCancel // ], 0, System.UITypes.TMsgDlgBtn.mbCancel, // procedure(const AResult: TModalResult) // begin // if AResult = mrYES then // ShowMessage('You chose Yes') else // if AResult = mrNo then // ShowMessage('You chose No') else // if AResult = mrCancel then // ShowMessage('You chose Cancel'); // end); //上面是非模式化的,下面是模式化的。 BResult := MessageDlg('Choose a button:', System.UITypes.TMsgDlgType.mtInformation, [ System.UITypes.TMsgDlgBtn.mbYes, System.UITypes.TMsgDlgBtn.mbNo, System.UITypes.TMsgDlgBtn.mbCancel ], 0, System.UITypes.TMsgDlgBtn.mbCancel);
if BResult = mrYES then ShowMessage('You chose Yes') else if BResult = mrNo then ShowMessage('You chose No') else if BResult = mrCancel then ShowMessage('You chose Cancel'); end;
//Add By Flying Wang. procedure TMessageAlertsForm.ButtonInputQueryClick(Sender: TObject); var AString: string; BResult: TModalResult; begin AString := 'Old string'; //Fix By Flying wang {$IFDEF ANDROID} MessageDialog_CanceledOnTouchOutsid := CheckBox1.IsChecked; MessageDialog_Canceleable := CheckBox2.IsChecked; {$ENDIF ANDROID} // InputBox('输入对话框', // 'Input a text:', AString, // procedure(const AResult: TModalResult; const AValue: string) // begin // AString := AValue; // if AResult = mrOK then // ShowMessage('Youer input text is:' + AString) else // if AResult = mrCancel then // ShowMessage('You chose Cancel'); // end); //上面是非模式化的,下面是模式化的。 if InputQuery('输入对话框','Input a text:', AString) then ShowMessage('Youer input text is:' + AString) else ShowMessage('You chose Cancel');
end;
----------------------------------------------
(C)(P)Flying Wang