XE5 修复 安卓 输入法隐藏 后 无法退出的问题 3.1
(****************************************************)
(* *)
(* 编写:爱吃猪头肉 & Flying Wang *)
(* 上面的版权声明请不要移除。 *)
(* 2014-03-15 *)
(* *)
(****************************************************)
找到 XE5 安装的
FMX.VirtualKeyboard.Android.pas
将他们另存到(复制到)其他目录,例如您的工程目录。
将新复制出的文件加入到您的工程中。
【第一步】
打开 FMX.VirtualKeyboard.Android.pas 找到
function TVirtualKeyboardAndroid.GetVirtualKeyBoardState: TVirtualKeyBoardState;
begin
if FError then
Result := [vksError]
else
Result := [];
if IsAutoShow then
Result := Result + [vksAutoShow];
if not FError then
begin
if FState = vkbsVisible then
Result := Result + [vksVisible];
end;
end;
将上面的函数修改为
//Fix Error By 爱吃猪头肉 & Flying Wang
var
LastVirtualKeyboardHeight: Single = 0;
IsProcess_VisibleEvent: Boolean = False;
IsTimerRunning: Boolean = False;
LastTimerRunning: TDateTime = 0;
function GetIsTimerRunning: Boolean;
begin
if IsTimerRunning then
begin
//需要 uses System.DateUtils;
if MilliSecondsBetween(Now, LastTimerRunning) > 1000 then
begin
IsTimerRunning := False;
end;
end;
Result := IsTimerRunning;
end;
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(Process_VisibleEvent: Boolean = False);
var
VirtualKeyboard: IFMXVirtualKeyboardService;
VirtualKeyboardAndroid: TVirtualKeyboardAndroid;
KeyboardRect: TRect;
VirtualKeyboardHeight: Single;
begin
IsProcess_VisibleEvent := Process_VisibleEvent;
IsTimerRunning := True;
LastTimerRunning := Now;
VirtualKeyboardHeight := GetVirtualKeyboardHeight;
KeyboardRect := ObtainKeyboardRect;
if TPlatformServices.Current.SupportsPlatformService(IFMXVirtualKeyboardService,
IInterface(VirtualKeyboard)) then
begin
VirtualKeyboardAndroid := TVirtualKeyboardAndroid(VirtualKeyboard);
end
else
begin
exit;
end;
//由于需要本代码完全接管消息发送。所以不能用 FState。
//if VirtualKeyboardAndroid.FState = vkbsVisible then
//当上次是显示,当本次不显示的时候。
if (LastVirtualKeyboardHeight >=1) and (VirtualKeyboardHeight < 1) then
begin
TThread.Synchronize(nil,
procedure
begin
VirtualKeyboardAndroid.SetState(TVirtualKeyboardAndroid.TvkbState.vkbsHidden);
TMessageManager.DefaultManager.SendMessage(VirtualKeyboardAndroid, TVKStateChangeMessage.Create(False, KeyboardRect), True);
end);
end
//当上次是不显示,本次是显示的时候
else if (LastVirtualKeyboardHeight < 1) and (VirtualKeyboardHeight >= 1) then
begin
TThread.Synchronize(nil,
procedure
begin
VirtualKeyboardAndroid.SetState(TVirtualKeyboardAndroid.TvkbState.vkbsVisible);
if IsProcess_VisibleEvent then
begin
TMessageManager.DefaultManager.SendMessage(VirtualKeyboardAndroid, TVKStateChangeMessage.Create(True, KeyboardRect), True);
end;
end);
//目前不建议支持高度变化。
//只有横竖切换才发生。
//各位可以在 Form 的 Resize 事件中处理。
// end
// //显示中,高度变了。
// else if
// (VirtualKeyboardAndroid >= 1) and (LastVirtualKeyboardHeight >=1) and
// (LastVirtualKeyboardHeight <> VirtualKeyboardAndroid)
// then
// begin
// TThread.Synchronize(nil,
// procedure
// begin
// VirtualKeyboardAndroid.SetState(TVirtualKeyboardAndroid.TvkbState.vkbsVisible);
// if IsProcess_VisibleEvent then
// begin
// TMessageManager.DefaultManager.SendMessage(VirtualKeyboardAndroid, TVKStateChangeMessage.Create(True, KeyboardRect), True);
// end;
// end);
end;
LastVirtualKeyboardHeight := VirtualKeyboardHeight;
end;
function HideInputForFixVirtualKeyboradEvent :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: TVirtualKeyboardState;
var
KeyboardRect: TRect;
begin
if FError then
Result := [vksError]
else
Result := [];
if IsAutoShow then
Result := Result + [vksAutoShow];
if not FError then
begin
if (FState = vkbsVisible) then
begin
if GetVirtualKeyboardHeight < 1 then
begin
KeyboardRect := ObtainKeyboardRect;
TThread.Synchronize(nil,
procedure
begin
SetState(TVirtualKeyboardAndroid.TvkbState.vkbsHidden);
//当使用 Timer 之后,就不需要这边的处理了。
if not GetIsTimerRunning then
TMessageManager.DefaultManager.SendMessage(Self, TVKStateChangeMessage.Create(False, KeyboardRect), True);
end);
end;
end;
if FState = vkbsVisible then
Result := Result + [vksVisible];
end;
end;
缺点:我的山寨机上 26 的高度就没有输入法了。但是不知道其他的机器是多少。
事实上,只检查高度就可以,为了安全起见,才 高度 宽度 都检查的。
【第二步】
找到
procedure TVKListener.onVirtualKeyboardShown; 和
procedure TVKListener.onVirtualKeyboardHidden; 这两个函数
分别修改为下面的代码。
procedure TVKListener.onVirtualKeyboardShown;
begin
TThread.Synchronize(nil,
procedure
begin
FKeyboardService.SetState(TVirtualKeyboardAndroid.TvkbState.vkbsVisible);
//当使用 Timer 之后,就不需要这边的处理了。
if (not IsProcess_VisibleEvent) or (not GetIsTimerRunning) then
TMessageManager.DefaultManager.SendMessage(Self, TVKStateChangeMessage.Create(true, ObtainKeyboardRect), True);
end);
FEvent.SetEvent;
end;
procedure TVKListener.onVirtualKeyboardHidden;
begin
TThread.Synchronize(nil,
procedure
begin
FKeyboardService.SetState(TVirtualKeyboardAndroid.TvkbState.vkbsHidden);
//当使用 Timer 之后,就不需要这边的处理了。
if not GetIsTimerRunning then
TMessageManager.DefaultManager.SendMessage(Self, TVKStateChangeMessage.Create(false, ObtainKeyboardRect), True);
end);
FEvent.SetEvent;
end;
注意:这样改完之后,输入框之间切换,将不会有消息。
【第三步】
然后到 文件的前面(implementation 之前),定义
/// <summary>
/// When < 1, it means VirtualKeyBoard Hided.
/// </summary>
function GetVirtualKeyBoardHeight: Single;
/// <summary>
/// <para>
/// Use a timer to call me. it will fix VirtualKeyboard Hide Message.
/// </para>
/// <para>
/// 用一个 TIMER 调用本函数,可以修复虚拟键盘的隐藏消息。
/// </para>
/// </summary>
/// <param name="Process_VisibleEvent">
/// 是否处理虚拟键盘的显示事件
/// </param>
procedure ProcessVirtualKeyboardEvent(Process_VisibleEvent: Boolean = False);
/// <summary>
/// 强制输入控件隐藏输入。
/// </summary>
function HideInputForFixVisualKeyboradEvent :Boolean;
下面是【使用方法】。
1. 放一个 Timer 例如叫 TimerForVKeyborad。300ms 一次。
procedure TForm1.TimerForVKeyboradTimer(Sender: TObject);
begin
{$IFDEF ANDROID}
ProcessVisualKeyboradEvent;
{$ENDIF}
end;
2. 完成如下事件。其实完全可以对每个输入框的按下事件处理。参考 4 。
procedure TForm1.FormVirtualKeyboardHidden(Sender: TObject; KeyboardVisible: Boolean; const Bounds: TRect);
begin
Memo1.Lines.Add('键盘隐藏了');
Memo1.GoToTextEnd;
if Focused <> Edit1.AsIControl then //这是为了配合 Edit1 的按下事件做的判断。
Focused := nil; //这个代码其实也可以。
//{$IFDEF ANDROID}
// HideInputForFixVisualKeyboradEvent;
//{$ENDIF}
end;
3. 完成如下事件。
procedure TForm1.FormVirtualKeyboardShown(Sender: TObject; KeyboardVisible: Boolean; const Bounds: TRect);
begin
Memo1.Lines.Add('键盘显示了');
Memo1.GoToLineEnd;
end;
4 或者对每个输入框的按下事件处理。
uses
FMX.Platform,
FMX.VirtualKeyboard;
procedure TForm1.Edit1Click(Sender: TObject);
var
VirtualKeyboard: IFMXVirtualKeyboardService;
begin
{$IFDEF ANDROID}
//当没有选中自己的时候不自动弹出。
if Focused <> Edit1.AsIControl then exit;
if GetVirtualKeyboardHeight < 1 then
begin
if TPlatformServices.Current.SupportsPlatformService(IFMXVirtualKeyboardService,
IInterface(VirtualKeyboard)) then
begin
if not (vksVisible in VirtualKeyboard.VirtualKeyBoardState) then
begin
if (vksAutoShow in VirtualKeyboard.VirtualKeyBoardState) then
VirtualKeyboard.ShowVirtualKeyboard(Edit1);
end;
end;
end;
{$ENDIF}
end;
XE5 修复 安卓 输入法隐藏 后 无法退出的问题 3.1的更多相关文章
- XE5 修复 安卓 输入法隐藏 后 无法退出的问题 3.2
欢迎到 ① FireMonkey[DELPHI XE5] 165232328 交流开发技术. (************************************************** ...
- delphi XE5下安卓开发技巧
delphi XE5下安卓开发技巧 一.手机快捷方式显示中文名称 project->options->Version Info-label(改成需要显示的中文名即可),但是需要安装到安卓手 ...
- dex方法隐藏后的反编译和运行时 效果
隐藏smali方法后 java源码: int b = fun2(); baksmali解释为: invoke-virtual {v1}, <int MainAc ...
- linux vi 中按了ctrl+s后没法退出
linux vi 中按了ctrl+s后无法退出 Linux 中使用vi编辑文件 不小心按了Ctrl + S (习惯了) 结果终端就跟死了一样, 解决办法: Ctrl+Q
- 关于easyui隐藏后数据不能刷新??
原因是div用display属性隐藏后不能重新加载table数据 解决方法:使用hide()方法在初始化时隐藏 $("#two").hide(); //点击按钮隐藏与显示表单域 $ ...
- 【问题解决方案】从 Anaconda Prompt 或 Jupyter Notebook 终端进入Python后重新退出到命令状态
从 Anaconda Prompt 或 Jupyter Notebook 终端进入Python后重新退出到命令状态 退出Python:exit() 或者 Ctrl+z 例子一枚 默认打开的是3.7,需 ...
- display none隐藏后如果表单有数值,那么他的数值还存在!
以前以为display:none后他的值就不存在了, display:none隐藏后如果表单有数值,那么他的数值还存在.(项目出了问题!!) <!DOCTYPE html PUBLIC &quo ...
- Html 使用技巧 -- 设置display属性可以使div隐藏后释放占用的页面空间
div的visibility可以控制div的显示和隐藏,但是隐藏后页面显示空白: style="visibility: none;" document.getElemen ...
- ecmall用户登录后自动退出解决方法
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...
随机推荐
- VS 2013 中如何自定义快捷键(图解)
随着软件的升级其功能也越来越多,所以相应的快捷键也多了起来.VS2013中的快捷方式已经发展为了两个快捷键的组合.例如VS2013中默认的多行注释的快捷功能键为(ctrl+k,ctrl+u).像这样类 ...
- Android BLE设备蓝牙通信框架BluetoothKit
BluetoothKit是一款功能强大的Android蓝牙通信框架,支持低功耗蓝牙设备的连接通信.蓝牙广播扫描及Beacon解析. 关于该项目的详细文档请关注:https://github.com/d ...
- Linux系统产生随机数/dev/random 和 /dev/urandom
1. 基本介绍 /dev/random和/dev/urandom是Linux系统中提供的随机伪设备,这两个设备的任务,是提供永不为空的随机字节数据流.很多解密程序与安全应用程序(如SSH Keys, ...
- snmp安装
只为成功找方法,不为失败找借口! Snmp学习总结(六)——linux下安装和配置SNMP 一.安装SNMP 1.1.下载Net-SNMP的源代码 选择一个SNMP版本,比如5.7.1,下载地址如下: ...
- Redis持久化存储(RDB和AOF)
参考了: https://blog.csdn.net/canot/article/details/52886923 和 https://www.cnblogs.com/zhangchao-letv/ ...
- linux操作系统语言更改
有时候我们的服务器在安装时安装的默认语言不支持中文,导致程序.文档中的汉子显示乱码,从而使系统报一些莫名其妙的错误,这是可以更改操作系统的默认语言 1.echo $LANG 查看当前操作系统的语 ...
- 【LOJ】#2181. 「SDOI2015」排序
题解 还以为是啥毒瘤题 然后是个搜索题 复杂度算起来挺大 然后跑起来就连0.1ms不到= = 就是从大到小进行每种操作,搜出来一种操作就乘上一个操作数的阶乘就行 如果现在进行的操作操作\(2^i\)那 ...
- Codeforces 291 E Tree-String Problem AC自动机
Tree-String Problem 网上的dfs + kmp 复杂度就是错的, 除非算出根据下一个字符直接转移Next数组直接转移, 而求出Next[ i ][ 26 ]数组和丢进AC自动机里面没 ...
- 【Java】 大话数据结构(4) 线性表之循环链表
本文稍微介绍了一下循环链表. 将单链表终端结点的指针域由空指针改为指向头结点,形成一个环,这种头尾相接的单链表称为循环列表. 循环列表的结构如下图所示: 循环链表的优点:可以从任意一个结点出发,遍历所 ...
- Db2与Oracle的区别
这个部分是自己随便整理下. 在工作上需要,公司需要DB2兼容Oracle. 不懂DB2与Oracle的细节,这里努力整理,以后精通了再回来重新修改. https://www.2cto.com/data ...