# 点击左边的各项功能模块，软键盘都会自动拉起又退出

#### 问题现象

应用内某tab页面，点击左边的各项功能模块tab，右边会跳转对应的页面，软键盘都会自动拉起又退出。

#### 背景知识

*   NavDestination：作为子页面的根容器，用于显示Navigation的内容区。
    *   onWillShow：当该Destination显示之前触发此回调。
    *   onWillHide：当该Destination隐藏之前触发此回调。
*   焦点控制：自定义组件的走焦效果，可设置组件是否走焦和具体的走焦顺序，tab键或者方向键切换焦点。
    *   focusable：设置当前组件是否可以获焦。
    *   defaultFocus：设置当前组件是否为当前层级页面上的默认焦点。

#### 问题定位

切换左边不同的模块，导致键盘拉起又自动退出，从现象来看推测可能是页面组件获取焦点然后又失去焦点导致的。

1.  分析日志，可以看到NavDestination页面跳转时，新页面展示，旧页面失去焦点，旧页面的键盘也随之关闭。
    
    ```
    AceFocus: [dict][(100000:100000:scope)] Focus view: NavDestination/2179 shown
    AceFocus: [dict][(100000:100000:scope)] Focus view: NavDestination/2117 lost focus
    AceNavigation: [dict][(100000:100000:scope)] GridEditor lifecycle change to onWillHide state.
    AceNavigation: [dict][(100000:100000:scope)] GridEditor lifecycle change to onWillShow state.
    AceKeyboard: [dict][(100000:100000:scope)] PageChange CloseKeyboard FrameNode notNeedSoftKeyboard.
    AceKeyboard: [dict][(100000:100000:scope)] PageChange CloseKeyboard SoftKeyboard Closes Successfully.
    ```
    
2.  接着根据"rich editor in focus"可知跳转新页面后，RichEditor组件获取焦点，并拉起键盘。
    
    ```
    AceFocus: [dict][(100000:100000:scope)] Request focus on focus view:NavDestination/2179.
    AceRichText: [dict][(100000:100000:scope)] rich editor in focus
    AceRichText: [dict][(100000:100000:scope)] HandleFocusEvent/2202
    AceKeyboard: [dict][(100000:100000:scope)] isScrollableChild_: 1
    AceRichText: [dict][(100000:100000:scope)] onFocus, requestKeyboard-1, windowMode=1
    AceRichText: [dict][(100000:100000:scope)] request keyboard, opts-0, 1, 1
    inputMethod/ImsaKit: [dict]line: 253, function: Attach,isShowKeyboard 1.
    ```
    
3.  然后从"OnFocusNodeChange"看出焦点发生变化，"NavDestination/2179"和"RichEditor/2202"在获取焦点时产生冲突，而"new isKeyboardEnableShow: false"说明键盘最后退出了。
    
    ```
    AceFocus: [dict][(100000:100000:scope)] FocusSwitch end, RichEditor/secure field onBlur, RichEditor/secure field onFocus, start: 2, end: 1, update: 2
    AceKeyboard: [dict][(100000:100000:scope)] current focus node info : (RichEditor/2202).
    AceRichText: [dict][(100000:100000:scope)] OnFocusNodeChange/2202, reason=0, blockKbInFloating-0
    AceFocus: [dict][(100000:100000:scope)] Focus view: NavDestination/2179 is first shown.
    AceFocus: [dict][(100000:100000:scope)] Request focus on default focus: RichEditor/2202 return: 1.
    CONCUR: [dict]report subFocus pid 4860 start
    WINDOW: SCBKeyboardSession --> old isKeyboardEnableShow: true, new isKeyboardEnableShow: false
    SCB: SCBKeyboardManager --> keyboard is not foreground, not need modify keyboard layer.
    inputMethod/ImsaKit: [dict]line: 645, function: operator(),OnInputStart task end!
    ```
    

#### 分析结论

NavDestination页面跳转时，不同页面和组件对获取焦点处理不当，导致的键盘反复拉起、退出。

#### 修改建议

建议在onWillShow、onWillHide等生命周期函数中控制焦点状态，优化不同页面和组件获取和失去焦点的逻辑，避免键盘反复拉起、退出，提升用户体验。示例代码如下：

```
@Entry
@Component
struct PageSwitchDemo {
  @Provide('pageInfos') pageInfos: NavPathStack = new NavPathStack();

  @Builder
  pageMap(name: string) {
    if (name === 'TestPage') {
      TestPage();
    }
  }

  build() {
    Column() {
      Navigation(this.pageInfos) {
        Column() {
          Button('TestPage1')
            .onClick(() => {
              this.pageInfos.pushPath({ name: 'TestPage', param: 'TestPage1' });
            })
            .margin({ bottom: 16 });
          Button('TestPage2')
            .onClick(() => {
              this.pageInfos.pushPath({ name: 'TestPage', param: 'TestPage2' });
            });
        }
        .padding(10)
      }
      .navDestination(this.pageMap)
      .mode(NavigationMode.Split);
    }
    .height('100%')
    .width('100%');
  }
}

@Component
struct TestPage {
  @State name: string = 'NA';
  @Consume('pageInfos') pageInfos: NavPathStack;
  @State isEnableFocus: boolean = false;
  controller: RichEditorController = new RichEditorController();
  options: RichEditorOptions = { controller: this.controller };

  build() {
    NavDestination() {
      Column() {
        Column() {
          RichEditor(this.options)
            .onReady(() => {
              this.controller.addTextSpan('test text string.', {
                style: {
                  fontColor: Color.Black,
                  fontSize: 15
                }
              });
            })
            .defaultFocus(true)
            .focusable(this.isEnableFocus)
        }.width('100%');
      }.height('100%');
    }
    .onReady((context: NavDestinationContext) => {
      this.name = context.pathInfo.param as string;
    })
    .title(this.name)
    .onWillShow(() => {
      this.isEnableFocus = true;
    })
    .onWillHide(() => {
      this.isEnableFocus = false;
    });
  }
}
```

更多关于焦点的内容可以参考官网的焦点事件、焦点控制。