1 unit Unit1;
2
3 interface
4
5 uses
6 System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
7 FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.ComboEdit,
8 FMX.Edit, FMX.EditBox, FMX.NumberBox, FMX.DateTimeCtrls, FMX.ScrollBox,
9 FMX.Memo, FMX.Controls.Presentation, FMX.StdCtrls,
10 System.Math,//需要引入
11 FMX.VirtualKeyboard,//需要引入
12 FMX.Layouts;
13
14 type
15 TForm1 = class(TForm)
16 VertScrollBox1: TVertScrollBox;
17 Layout1: TLayout;
18 Memo1: TMemo;
19 Label1: TLabel;
20 Button1: TButton;
21 Edit1: TEdit;
22 Edit2: TEdit;
23 procedure FormCreate(Sender: TObject);
24 procedure FormFocusChanged(Sender: TObject);
25 procedure FormVirtualKeyboardHidden(Sender: TObject;
26 KeyboardVisible: Boolean; const Bounds: TRect);
27 procedure FormVirtualKeyboardShown(Sender: TObject;
28 KeyboardVisible: Boolean; const Bounds: TRect);
29 private
30 //定义移位标记
31 FKBBounds:TRectF;
32 FNeedOffset: Boolean;
33 procedure CalcContentBoundsProc(Sender: TObject; var ContentBounds: TRectF);
34 procedure RestorePosition;
35 procedure UpdateKBBounds;
36 { Private declarations }
37 public
38 { Public declarations }
39 end;
40
41 var
42 Form1: TForm1;
43
44 implementation
45
46 {$R *.fmx}
47 {$R *.NmXhdpiPh.fmx ANDROID}
48
49 //赋值事件
50 procedure TForm1.FormCreate(Sender: TObject);
51 begin
52 VertScrollBox1.OnCalcContentBounds := CalcContentBoundsProc;
53 end;
54
55 //每次焦点改变都要更新位置
56 procedure TForm1.FormFocusChanged(Sender: TObject);
57 begin
58 UpdateKBBounds;
59 end;
60
61 //输入法隐藏时的处理
62 procedure TForm1.FormVirtualKeyboardHidden(Sender: TObject;
63 KeyboardVisible: Boolean; const Bounds: TRect);
64 begin
65 FKBBounds.Create(0, 0, 0, 0);
66 FNeedOffset := False;
67 RestorePosition;
68 end;
69
70 //输入法显示时的处理
71 procedure TForm1.FormVirtualKeyboardShown(Sender: TObject;
72 KeyboardVisible: Boolean; const Bounds: TRect);
73 begin
74 FKBBounds := TRectF.Create(Bounds);
75 FKBBounds.TopLeft := ScreenToClient(FKBBounds.TopLeft);
76 FKBBounds.BottomRight := ScreenToClient(FKBBounds.BottomRight);
77 UpdateKBBounds;
78 end;
79
80 //计算内容边界
81 procedure TForm1.CalcContentBoundsProc(Sender: TObject;
82 var ContentBounds: TRectF);
83 begin
84 if FNeedOffset and (FKBBounds.Top > 0) then
85 begin
86 ContentBounds.Bottom := Max(ContentBounds.Bottom, 2 * ClientHeight - FKBBounds.Top);
87 end;
88 end;
89
90 //还原位置
91 procedure TForm1.RestorePosition;
92 begin
93 VertScrollBox1.ViewportPosition := PointF(VertScrollBox1.ViewportPosition.X, 0);
94 Layout1.Align := TAlignLayout.Client;
95 VertScrollBox1.RealignContent;
96 end;
97
98 //更新边界
99 procedure TForm1.UpdateKBBounds;
100 var
101 LFocused : TControl;
102 LFocusRect: TRectF;
103 begin
104 FNeedOffset := False;
105 if Assigned(Focused) then
106 begin
107 LFocused := TControl(Focused.GetObject);
108 LFocusRect := LFocused.AbsoluteRect;
109 LFocusRect.Offset(VertScrollBox1.ViewportPosition);
110 if (LFocusRect.IntersectsWith(TRectF.Create(FKBBounds))) and
111 (LFocusRect.Bottom > FKBBounds.Top) then
112 begin
113 FNeedOffset := True;
114 Layout1.Align := TAlignLayout.Horizontal;
115 VertScrollBox1.RealignContent;
116 Application.ProcessMessages;
117 VertScrollBox1.ViewportPosition := PointF(VertScrollBox1.ViewportPosition.X, LFocusRect.Bottom - FKBBounds.Top);
118 end;
119 end;
120 if not FNeedOffset then
121 RestorePosition;
122 end;
123
124 end.