# TestTextField **Repository Path**: andych008/test-text-field ## Basic Information - **Project Name**: TestTextField - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2021-07-08 - **Last Updated**: 2022-02-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README @[toc](目录) ### 处理前后对比 |处理前|处理前后| |-|-| |![tutieshi_320x694_4s.gif](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202107/a8752b36277c9f6952a7125d68964a9494a4b7.gif?x-oss-process=image/resize,w_320,h_694)|![tutieshi_320x694_6s.gif](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202107/d9308c41039a09e69d3342f5e303725c14873c.gif?x-oss-process=image/resize,w_320,h_694)| ### 问题现状 安卓上面,输入框被软键盘遮挡,很简单 ```java xml 配置 android:windowSoftInputMode="adjustPan" 或者,java 配置 getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); ``` 这样,软键盘弹出后,输入框就会自动上移。 **鸿蒙上也有类似的设置,但是貌似没效果**: ```java getWindow().setInputPanelDisplayType(WindowManager.LayoutConfig.INPUT_ADJUST_PAN); ``` ### 解决过程 #### 原理: 1. 布局文件用ScrollView包起来 2. 监听根布局大小变化,变小了,证明输入法弹出了。 3. 滚动ScrollView,使当前焦点控件显示在软键盘上方。 #### 核心代码: ```java public class MainAbilitySlice extends AbilitySlice { private EventHandler mainHandler = new EventHandler(EventRunner.getMainEventRunner()); private MyTask myTask = null; class MyTask implements Runnable { private final int softHeight; private final ScrollView root; private final Rect decorRect; public MyTask(int softHeight, ScrollView root, Rect decorRect) { this.softHeight = softHeight; this.root = root; this.decorRect = decorRect; } @Override public void run() { Timber.d("onRefreshed() called with: softHeight = [ %s ]", softHeight); Component focusView = root.findFocus(); int focusTop = focusView.getLocationOnScreen()[1];//焦点控件的左上角 root.fluentScrollByY(focusTop + focusView.getHeight() - decorRect.top - decorRect.getHeight() + 100); } } @Override public void onStart(Intent intent) { super.onStart(intent); getWindow().setInputPanelDisplayType(WindowManager.LayoutConfig.INPUT_ADJUST_PAN); super.setUIContent(ResourceTable.Layout_ability_main); Optional display = DisplayManager.getInstance().getDefaultDisplay(getContext()); Point pt = new Point(); display.get().getSize(pt); int screenHeight = pt.getPointYToInt();//不包括状态栏(手机时间、wifi显示的那一部分,) 2211,状态栏是129,加起来就是2340 Timber.d("onRefreshed() called with: screenHeight = [ %s ]", screenHeight); ScrollView root = (ScrollView) findComponentById(ResourceTable.Id_root); root.setLayoutRefreshedListener(new Component.LayoutRefreshedListener() { @Override public void onRefreshed(Component component) { //包括标题栏,但不包括状态栏。默认 大小 (0,129,1080,2340),top=129即状态栏 , height=2211。 同android的decorView Rect decorRect = new Rect(); component.getWindowVisibleRect(decorRect); Timber.d("onRefreshed() called with: rect = [ %s ]", decorRect); if (decorRect.getHeight() == 0) { //刚进入界面可能为0 return; } int softHeight = screenHeight - decorRect.getHeight(); Timber.d("onRefreshed() called with: softHeight = [ %s ]", softHeight); if (softHeight > 100) {//当输入法高度大于100判定为输入法打开了 if (myTask != null) { mainHandler.removeTask(myTask); myTask = null; } mainHandler.postTask(myTask = new MyTask(softHeight, root, decorRect), 100); } } }); } } ``` ----> **完整代码见文末** <---- **特别说明:** 滚动操作为什么要delay 100毫秒?因为点击一个输入框`Component.LayoutRefreshedListener`有时会反复调用多次,而且间隔时间小于10毫秒,所以会造成滚动距离不准确。用postTask之后,每次调用的时候会把之前的task remove掉,以最新的一次为准。 #### 计算滚动距离 其中上面的大红框是decorRect(即当前Ability可视区域),下面的大黑框是输入法显示区域。其中,软键盘弹出后,输入框被软键盘挡住,图中的小红框。 所以,要滚动的距离就是图中的`C=A-B`。 ![shiyitu.jpg](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202107/38ad0e78700528fdd1f170e836bd266d7c4285.jpg?x-oss-process=image/resize,w_1081,h_800) #### 可以优化的点:(有兴趣的朋友可以试一下,记得在评论区分享你的结果) 1. 如果是Dialog中的输入框,当前的计算方法是否正确? 2. 如果不用ScrollView,还有别的解决办法吗? 3. 抽取出工具类或工具方法,代码复用。 #### 2021-08-02优化 1. 封装了TextFieldHelper工具类 > 自动上移TextField。监听软键盘显示、隐藏。 2. 对于不同的布局处理TextField的移动有差异,所以定义了ITFHAdapter来适配。 > 我已经预定义了`ScrollViewTFHAdapter`、`DirectionTFHAdapter`处理根布局为`ScrollView`、`DirectionalLayout`的情况。 > 预定义了`DlgTFHAdapter`处理`CommonDialog`的情况(通过debug发现CommonDialog的根布局也是ScrollView,但是Dialog有一些特殊情,所以通过继承ScrollViewTFHAdapter来实现)