鴻蒙輸入框被軟鍵盤遮擋的解決辦法
處理前后對比

問題現狀
安卓上面,輸入框被軟鍵盤遮擋,很簡單
- xml 配置
- android:windowSoftInputMode="adjustPan"
- 或者,java 配置
- getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
這樣,軟鍵盤彈出后,輸入框就會自動上移。
鴻蒙上也有類似的設置,但是貌似沒效果:
- getWindow().setInputPanelDisplayType(WindowManager.LayoutConfig.INPUT_ADJUST_PAN);
解決過程
原理:
布局文件用ScrollView包起來
監(jiān)聽根布局大小變化,變小了,證明輸入法彈出了。
滾動ScrollView,使當前焦點控件顯示在軟鍵盤上方。
核心代碼:
- 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> display = DisplayManager.getInstance().getDefaultDisplay(getContext());
- Point pt = new Point();
- display.get().getSize(pt);
- int screenHeight = pt.getPointYToInt();//不包括狀態(tài)欄(手機時間、wifi顯示的那一部分,) 2211,狀態(tài)欄是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) {
- //包括標題欄,但不包括狀態(tài)欄。默認 大小 (0,129,1080,2340),top=129即狀態(tài)欄 , 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可視區(qū)域),下面的大黑框是輸入法顯示區(qū)域。其中,軟鍵盤彈出后,輸入框被軟鍵盤擋住,圖中的小紅框。
所以,要滾動的距離就是圖中的C=A-B。

可以優(yōu)化的點:
如果是Dialog中的輸入框,當前的計算方法是否正確?
如果不用ScrollView,還有別的解決辦法嗎?
抽取出工具類或工具方法,代碼復用。
文章相關附件可以點擊下面的原文鏈接前往下載
原文鏈接:https://harmonyos.51cto.com/posts/4776