HarmonyOS鸿蒙Next中点击确定后要在点击一下才显示,这是为什么?

HarmonyOS鸿蒙Next中点击确定后要在点击一下才显示,这是为什么? 点击确定后要在点击一下才显示,这是为什么?

import {twoTheme} from "../Theme/ThemeManager"
import { AppStorageV2, promptAction } from "@kit.ArkUI"
import { FailureCode } from "@ohos.app.ability.CompletionHandlerForAtomicService"
import { preferences } from "@kit.ArkData"
import { common } from "@kit.AbilityKit"

@Builder
export function PassProQuestBuilder(){
 PassPro_Question()
}


@CustomDialog
@Component
struct CustomDialogInput {
  @Link Index :number
  @Link TextInputQuestion : string
  @Consume TextInputValue : string
  @StorageLink("currentStatus") twoTheme: twoTheme = twoTheme.Light
  controllerInput?: CustomDialogController;
  cancel:() => void = () => {}
  confirm:() => void = () => {}

  build() {
    Column() {
      Text("自定义密保问题").fontSize(20).margin({top:"5%",bottom:"5%"}).fontColor("#000000")
      TextInput({placeholder:"请输入......",text:this.TextInputQuestion})
        .height("25%")
        .width("95%")
        .onChange((value:string)=>{
          this.TextInputQuestion=value
        })
      Flex({justifyContent:FlexAlign.SpaceAround}){
        Button('取消')
          .width("50%")
          .onClick(() => {
            if (this.controllerInput != undefined) {
              this.Index = 0
              this.controllerInput.close();
              this.cancel();
            }
          })
          .backgroundColor(this.twoTheme == twoTheme.Light ? "#E8E8E8":"#FFFFFF")
          .fontColor("#000000")
          .margin(20)
        Button('确认')
          .width("50%")
          .onClick(() => {
            if (this.controllerInput != undefined) {
              this.TextInputValue = this.TextInputQuestion
              this.controllerInput.close();
              this.confirm();
            }
          })
          .backgroundColor("#CCC" )
          .fontColor("#000000")
          .margin(20)
      }
      .borderRadius(20)
    }
    .width("90%")
    .height("28%")
  }
}



@Component
struct PassPro_Question{
  @State Index:number = 0;
  //密保问题
  @State TextInputQuestion : string =""
  @Provide TextInputValue :string = "自定义密保问题"
  //问题答案
  @State TextAnswer : string = ""
  @State Confirm_ON : boolean = false
  //其余变量
  @State DisValue:string = "您父亲的名字是"
  pathStack: NavPathStack = AppStorageV2.connect(NavPathStack,"NavPathStack",() => new NavPathStack())!
  @StorageLink("currentStatus") twoTheme: twoTheme = twoTheme.Light
  @State Quest :Array<string> =["您父亲的名字是?","您伴侣的姓名是?","您的小学班主任是?","您就读的中学名称是?","您最喜欢的歌手是?","自定义密保问题"]


  private SetQuestAnswer(Quest:string,Answer: string): void {
    const context: common.Context = this.getUIContext().getHostContext() as common.Context
    const option: preferences.Options = { name: 'Quest_Answer' }
    const pref: preferences.Preferences = preferences.getPreferencesSync(context,option)
    pref.putSync('Quest', Quest)
    pref.putSync('Answer',Answer)
    pref.flush()
  }



  dialogController : CustomDialogController | null = new CustomDialogController({
    builder: CustomDialogInput({
      cancel: ()=>{ this.onCancel(); },
      confirm: ()=>{ this.onConfirm(); },
      TextInputQuestion: this.TextInputQuestion,
      Index:this.Index
    }),
    cancel:this.onBack,
    autoCancel :true,
    onWillDismiss:(dismissDialogAction: DismissDialogAction)=> {
      if (dismissDialogAction.reason == DismissReason.PRESS_BACK) {
        dismissDialogAction.dismiss();
      }
      if (dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
        dismissDialogAction.dismiss();
      }
    },
    alignment: DialogAlignment.Center,
    offset: { dx: 0, dy: -20 },
    gridCount: 4,
    customStyle: false,
    cornerRadius: 25 ,
    backgroundColor:this.twoTheme == twoTheme.Light ? "#FFFFFF":"#404040",
    borderColor:this.twoTheme == twoTheme.Light ? "#FFFFFF":"#404040"
  })





  // 在自定义组件即将析构销毁时将dialogController置空
  aboutToDisappear() {
    this.dialogController = null; // 将dialogController置空
  }
  //点击取消的回调函数
  onCancel() {
    console.info('当点击取消时进行回调');
  }
  //点击确认的回调函数
  onConfirm() {
    console.info('当点击确认时进行回调');
  }
  //退出时的回调函数
  onBack() {
    console.info('在空白区域点击返回按钮');
  }


  build() {
    NavDestination(){
      Column(){
        Row(){
          Text("请牢记密保问题答案。如忘记图案密码,可通过密保问题进行重置。")
            .height("15%")
            .fontSize(14)
            .fontColor(this.twoTheme == twoTheme.Light ? "#CCC":Color.Gray)
        }.justifyContent(FlexAlign.Center).width("90%")
        Select([
          { value : this.Quest[0], icon:$r("app.media.checkmark_white") },
          { value : this.Quest[1], icon:$r("app.media.checkmark_white") },
          { value : this.Quest[2], icon:$r("app.media.checkmark_white") },
          { value : this.Quest[3], icon:$r("app.media.checkmark_white") },
          { value : this.Quest[4], icon:$r("app.media.checkmark_white") },
          { value : this.Quest[5], icon:$r("app.media.checkmark_white") } ,
        ])
          .margin({bottom:"20%"})
          .optionWidth(OptionWidthMode.FIT_TRIGGER)
          .backgroundColor(this.twoTheme == twoTheme.Light ? "#E8E8E8":Color.Gray)
          .fontColor(this.twoTheme == twoTheme.Light ? "#000000":"#FFFFFF")
          .selected(this.Index)
          .value(this.DisValue)
          .onSelect((index: number, value?: string) => {
            this.Index = index;
            if (value) {
              this.DisValue = value
              if(this.Index == 5 && this.dialogController != null){
                this.dialogController.open();
                this.DisValue = this.TextInputQuestion
              }
            }
          })
        TextInput({text:this.TextAnswer,placeholder:"请输入2-18个字符"})
          .placeholderColor(this.twoTheme == twoTheme.Light ? Color.Gray:"CCC")
          .width("90%")
          .margin({top:"15%"})
          .defaultFocus(true) // 设置默认焦点为true,进入页面就会获取焦点,弹出键盘
          .focusable(true)
          .backgroundColor(this.twoTheme == twoTheme.Light ? "#E8E8E8":Color.Gray)
          .onChange((value:string)=>{
            this.TextAnswer =value
            if ((value).length >= 2) {
              this.Confirm_ON = true
            }
            else this.Confirm_ON =false
          })

      }
      .margin({left:"5%"})
      .width("95%")
      .height("80%")
      .alignItems(HorizontalAlign.Start)
      Row(){
        Button('取消')
          .width("40%")
          .onClick(() => {
            this.pathStack.pop()
          })
          .backgroundColor(this.twoTheme == twoTheme.Light ? "#E8E8E8":"#555555")
          .fontColor(this.twoTheme == twoTheme.Light ? "#000000":"#FFFFFF")
          .margin({left:"5%"})
        Button('确认')
          .width("40%")
          .enabled(this.Confirm_ON)
          .margin({right:"5%"})
          .onClick(() => {
            this.SetQuestAnswer(this.DisValue,this.TextAnswer)
            promptAction.showToast({message:"保存成功"})
            this.pathStack.pop()
          })
          .backgroundColor(this.twoTheme == twoTheme.Light ? "#949494":"#888")
          .fontColor(this.twoTheme == twoTheme.Light ? "#000000":"#FFFFFF")
      }
      .justifyContent(FlexAlign.SpaceBetween)
      .alignItems(VerticalAlign.Bottom)
      .height("18%")
      .width("100%")
    }
    .width("100%")
    .height("100%")
    .title("设置密保问题")
    .backgroundColor(this.twoTheme == twoTheme.Light ? "#FFFFFF":"#404040")
  }
}

更多关于HarmonyOS鸿蒙Next中点击确定后要在点击一下才显示,这是为什么?的实战教程也可以访问 https://www.itying.com/category-93-b0.html

5 回复

问题在于数据更新时机不当。在选择自定义密保问题后会打开弹窗,在弹窗内输入自定义密保问题,但同步数据的步骤直接放在了打开弹窗的方法之后,使得第一次同步数据时,自定义密保问题还未输入,导致同步到的数据为空,第二次点击时数据已存在,则可以显示自定义密保问题。

cke_210.png

将数据同步的操作改到弹窗点击确定的回调即可。

cke_507.png

更多关于HarmonyOS鸿蒙Next中点击确定后要在点击一下才显示,这是为什么?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


【解决方案】

看了下是因为Select组件的value属性设置的值为DisValue,而这边在弹窗中修改的是TextInputQuestion的值,TextInputQuestion在主页面上没有属性使用到,只是做了赋值不会触发页面的刷新,可以在弹窗confirm中给DisValue重新赋值触发页面的刷新。

confirm: () => {
  this.onConfirm();
  this.DisValue = this.TextInputQuestion
}

好的,谢谢老师,

在HarmonyOS Next中,点击确定后需再次点击才显示,通常是由于界面渲染机制或事件处理逻辑导致。可能原因包括:UI组件状态更新延迟、事件冒泡处理不当,或异步操作未及时触发界面刷新。建议检查相关组件的状态绑定及事件回调函数,确保UI更新与用户操作同步。

根据你提供的代码,问题很可能出在自定义对话框 CustomDialogInputTextInput 组件的数据绑定和状态更新机制上。

具体分析如下:

  1. 数据流问题:在 PassPro_Question 组件中,你通过 @Provide 提供了 TextInputValue,并在 CustomDialogInput 中通过 @Consume 进行消费。然而,在对话框的“确认”按钮点击事件中,你执行了:

    this.TextInputValue = this.TextInputQuestion
    this.controllerInput.close();
    

    这里将对话框内输入框的值 (TextInputQuestion) 赋给了消费的变量 (TextInputValue)。但是,TextInputQuestionCustomDialogInput 组件中是通过 @Link 从父组件 (PassPro_Question) 传入的 State 变量。这个赋值操作直接修改了父组件的状态。

  2. 渲染时机与状态同步:在 PassPro_Question 组件的 Select 组件 onSelect 回调中,当你选择“自定义密保问题”(Index == 5)时,有以下逻辑:

    if(this.Index == 5 && this.dialogController != null){
        this.dialogController.open();
        this.DisValue = this.TextInputQuestion // 问题点
    }
    

    在打开对话框之后,你立即将 DisValue(即 Select 组件显示的值)设置为 this.TextInputQuestion。然而,此时 TextInputQuestion 可能尚未更新为你在对话框中输入并确认的最新值。因为对话框的关闭和状态的回传是异步发生的。

核心原因Select 组件显示的 DisValue 没有与最终确认的 TextInputValue(或更新后的 TextInputQuestion)正确同步。对话框关闭后,DisValue 可能仍指向旧的 TextInputQuestion 值。你需要再次点击(例如触发一次界面重绘或焦点变化)才能使 DisValue 更新为最新值。

解决方案: 确保在对话框确认关闭后,DisValue 能自动更新为最新的自定义问题文本。修改 PassPro_QuestionSelect 组件的 value 绑定:

.value(this.DisValue)

改为直接绑定到最终存储自定义问题文本的变量。根据你的代码逻辑,这个变量应该是 TextInputValue(由 @Provide 提供,并在对话框确认时更新)。因此,可以尝试修改为:

.value(this.Index === 5 ? this.TextInputValue : this.DisValue)

同时,需要调整 onSelect 回调中设置 DisValue 的逻辑,确保它只在选择非自定义选项时更新,而在选择自定义选项时,DisValue 应能自动关联到 TextInputValue

更简洁的做法是:Selectvalue 绑定可以根据 Index 动态决定:

.value(this.Index === 5 ? this.TextInputValue : this.Quest[this.Index])

这样,当选择自定义选项(Index === 5)时,显示的是 TextInputValue(它会在对话框确认时更新);选择其他预设选项时,显示对应数组中的字符串。这能确保显示的值总是与当前选择的状态同步,无需二次点击刷新。

回到顶部