[Daily HarmonyOS Next Knowledge] Automatic Focus Acquisition, Global Popups, Data Change Monitoring, Size Display Anomalies, One-Click Closure of All Pages
1. HarmonyOS TextInput automatic focus issue?
A TextInput and a button are arranged vertically on the page. Clicking the button triggers a popup using CustomDialogController. After closing the popup, the TextInput automatically gains focus. How to prevent automatic focus acquisition? Setting .defaultFocus(false).groupDefaultFocus(false)
is ineffective.
Use requestFocus
as shown in the demo:
import prompt from '@ohos.prompt';
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
@State isboole: boolean = true;
build() {
Row() {
Column() {
Text(this.message)
.id('1sa')
.fontSize(50)
.fontWeight(FontWeight.Bold)
Button('I will get focus')
.key('BBB')
TextInput({ placeholder: 'AAAAA' })
.id('AAAA1')
.type(InputType.Normal)
Button('Click to transfer focus')
.onClick(() => {
let res = focusControl.requestFocus('BBB')
if (res) {
prompt.showToast({ message: 'Request success' })
} else {
prompt.showToast({ message: 'Request failed' })
}
})
Button('Click to get focus')
.onClick(() => {
this.isboole = true
sendEventByKey("AAAA1", 10, "") // Send click event to component with id "longClick"
})
}
.width('100%')
}
.height('100%')
}
}
2. How to encapsulate global popups in HarmonyOS? What is the best practice?
- What is the optimal way to encapsulate public popups?
- How to use popups in non-UI components?
To encapsulate a globally usable popup, use promptAction
to wrap a custom dialog:
Reference documentation: See the example code for promptAction.openCustomDialog
(https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-promptaction-V5#promptactionopencustomdialog11)
Sample code:
let customDialogId: number = 0
export function showCustomDialog() {
let result: CustomDialogController = new CustomDialogController({
builder: SimpleDialog({}),
alignment: DialogAlignment.Bottom,
customStyle: true,
offset: {
dx: 0,
dy: CommonConstants.DY_OFFSET
}
})
result.open()
}
...
onClick: () => {
promptAction.openCustomDialog({
builder: showCustomDialog.bind(this)
}).then((dialogId: number) => {
customDialogId = dialogId;
})
}
// Confirm/cancel popup
promptAction.closeCustomDialog(customDialogId)
3. How to monitor data changes of isNormalMode
within a @builder decorator in HarmonyOS?
Need to update the Image component's source when isNormalMode
changes. Currently, if written directly in build
without @builder, the Image updates normally. When written in @builder, data changes are not detected. How to monitor data changes within @builder?
@State isNormalMode: boolean = true;
@Builder
showImage(source: string | Resource, onImageClick: () => void = () => {}) {
Image(source)
.fitOriginalSize(true)
.objectFit(ImageFit.Auto)
.width(Constants.FULL_PARENT)
.onClick(() => {
console.log("obclick")
onImageClick();
})
.padding({ /// Inner area padding
top: $r('app.float.screen_margin_left_right')
})
}
build() {
Stack({ alignContent: Alignment.TopStart }) {
Flex({ direction: FlexDirection.Column }) {
TitleBar({ model: $model })
Column() {
this.showImage(this.isNormalMode ? $r('app.media.normal_mode_selected') : $r('app.media.normal_mode_unselect'), () => {
console.log("setImageobclick")
this.isNormalMode = true;
});
this.showImage(this.isNormalMode ? $r('app.media.easy_mode_unselect') : $r('app.media.easy_mode_selected'), () => {
console.log("setImageobclick")
this.isNormalMode = false;
});
}
.padding({ /// Inner area padding
left: $r('app.float.screen_margin_left_right'),
right: $r('app.float.screen_margin_left_right'),
})
.width(Constants.FULL_PARENT)
.height(Constants.FULL_PARENT)
}
}
.width(Constants.FULL_PARENT)
.height(Constants.FULL_PARENT)
}
When calling a @Builder-decorated function, parameters are passed by value. Changes to state variables (passed by value) do not trigger UI refresh within @builder. For state variables, use reference passing.
Reference: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-builder-V5
Sample code:
class ImageParams {
imageUrl: string | Resource = ''
onImageClick: () => void = () => {
}
}
@Entry
@Component
struct Index {
@State isNormalMode: boolean = true;
@State imgUrl: string | Resource = $r('app.media.img1')
@Builder
showImageNew(params: ImageParams) {
Image(params.imageUrl)
.fitOriginalSize(true)
.objectFit(ImageFit.Auto)
.width(200)
.onClick(() => {
console.log("obclick")
params.onImageClick();
})
}
@Builder
showImage(source: string | Resource, onImageClick: () => void = () => {
}) {
Image(source)
.fitOriginalSize(true)
.objectFit(ImageFit.Auto)
.width(200)
.onClick(() => {
console.log("obclick")
onImageClick();
})
}
build() {
Stack({ alignContent: Alignment.TopStart }) {
Flex({ direction: FlexDirection.Column }) {
Column() {
Text("Status: " + this.isNormalMode)
Text(" imgUrl: " + JSON.stringify(this.imgUrl))
this.showImage(this.imgUrl, () => {
console.log("setImageobclick")
this.isNormalMode = !this.isNormalMode;
this.imgUrl = this.isNormalMode ? $r('app.media.img1') : $r('app.media.img2')
})
Button("Change type (only status, image unchanged)").onClick(() => {
this.isNormalMode = !this.isNormalMode
})
//=================Use the following approach==========================
this.showImageNew(
{
imageUrl: this.imgUrl,
onImageClick: () => {
this.isNormalMode = !this.isNormalMode;
this.imgUrl = this.isNormalMode ? $r('app.media.img1') : $r('app.media.img2')
}
}
)
if (this.isNormalMode) {
this.showImageNew(
{
imageUrl: $r("app.media.img1"),
onImageClick: () => {
this.isNormalMode = !this.isNormalMode;
this.imgUrl = this.isNormalMode ? $r('app.media.img1') : $r('app.media.img2')
}
}
)
} else {
this.showImageNew(
{
imageUrl: $r("app.media.img2"),
onImageClick: () => {
this.isNormalMode = !this.isNormalMode;
this.imgUrl = this.isNormalMode ? $r('app.media.img1') : $r('app.media.img2')
}
}
)
}
}
.width("100%")
.height("100%")
}
}
.width("100%")
.height("100%")
}
}
4. HarmonyOS component size display anomaly?
In the following code, the width is set to 100%, but the actual width does not fill the screen as shown in the screenshot.
@Entry
@Component
struct AlignRuleTestPage {
@State message: string = 'Hello World';
build() {
RelativeContainer() {
Text(this.message)
.id('AlignRuleTestPageHelloWorld')
.fontSize(30)
.width("100%")
.aspectRatio(6)
.margin({
top: "14%"
})
.backgroundColor(Color.Red)
.fontWeight(FontWeight.Bold)
.alignRules({
top: { anchor: '__container__', align: VerticalAlign.Top },
left: { anchor: '__container__', align: HorizontalAlign.Start },
right: { anchor: '__container__', align: HorizontalAlign.End },
})
}
.height('100%')
.width('100%')
}
}
Refer to the demo:
@Component
struct Index {
@State message: string = 'Hello World';
build() {
RelativeContainer() {
Text(this.message)
.id('AlignRuleTestPageHelloWorld')
.fontSize(30)//.aspectRatio(0) Remove this line
.margin({
top: "14%"
})
.backgroundColor(Color.Red)
.fontWeight(FontWeight.Bold)
.width("100%")
.height('100%')
}
.height('100%')
.width('100%')
}
}
Reference for aspectRatio
: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-universal-attributes-layout-constraints-V5
5. How to close all previous pages with one click in HarmonyOS?
After navigating through multiple pages (e.g., A-B-C-D), how to close A, B, and C with one click?
To close pages A and B, use router.clear()
to clear all historical pages from the stack, leaving only the current page as the top.
Reference: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-router-V5
Top comments (0)