[Learn HarmonyOS Next Knowledge Every Day] Push and UI Layout
1. How to avoid displaying intermediate transition tab pages when switching Tab component pages?
Currently, when clicking on a tab page across multiple pages, intermediate transition pages are displayed.
If animations are required, the specification mandates transitioning through pages 1, 2, 3, 4 sequentially. To hide intermediate transition pages, set .animationDuration(0)
.
Reference Code:
// xxx.ets
@Entry
@Component
struct TabsExample {
@State fontColor: string = '#182431'
@State selectedFontColor: string = '#007DFF'
@State currentIndex: number = 0
private controller: TabsController = new TabsController()
@Builder
tabBuilder(index: number, name: string) {
Column() {
Text(name)
.fontColor(this.currentIndex === index ? this.selectedFontColor : this.fontColor)
.fontSize(16)
.fontWeight(this.currentIndex === index ? 500 : 400)
.lineHeight(22)
.margin({ top: 17, bottom: 7 })
Divider()
.strokeWidth(2)
.color('#007DFF')
.opacity(this.currentIndex === index ? 1 : 0)
}.width('100%')
}
build() {
Column() {
Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) {
TabContent() {
Column().width('100%').height('100%').backgroundColor('#00CB87')
}.tabBar(this.tabBuilder(0, 'green'))
TabContent() {
Column().width('100%').height('100%').backgroundColor('#007DFF')
}.tabBar(this.tabBuilder(1, 'blue'))
TabContent() {
Column().width('100%').height('100%').backgroundColor('#FFBF00')
}.tabBar(this.tabBuilder(2, 'yellow'))
TabContent() {
Column().width('100%').height('100%').backgroundColor('#E67C92')
}.tabBar(this.tabBuilder(3, 'pink'))
}
.vertical(false)
.barMode(BarMode.Fixed)
.barWidth(360)
.barHeight(56)
// Set animation duration to 0 to avoid displaying intermediate transition pages
.animationDuration(0)
.onChange((index: number) => {
this.currentIndex = index
})
.width(360)
.height(296)
.margin({ top: 52 })
.backgroundColor('#F1F3F5')
}.width('100%')
}
}
2. How to obtain application information and completely exit an app?
Problem Scenarios:
- How to obtain the app's version name (e.g., the version specified in
oh-package.json5
)? - How to completely exit an app? Methods like
router.clear()
androuter.back()
do not fully terminate the app, as some background tasks may persist.
Solutions:
-
Retrieve application information using
bundleManager
, which provides access to Ability information, ApplicationInfo, BundleInfo, etc. -
Completely exit the app by following the normal lifecycle of UIAbility. Use
killAllProcesses
underApplicationContext
only as a last resort (force-kills all app processes). For scenarios requiring app exit due to privacy policy rejection, useterminateSelf
underUIAbilityContext
.
Sample Code:
import { bundleManager } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { DateUtil } from '../../utils/DateUtil';
import { common } from '@kit.AbilityKit';
@Entry
@Component
struct CloseApp {
@State message: string = 'App Info: '
@State bundleInfo: bundleManager.BundleInfo | null = null
private context = getContext(this) as common.UIAbilityContext;
aboutToAppear(): void {
this.getAppPackageInfo()
}
/* Get app package information */
getAppPackageInfo() {
let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION;
try {
this.bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleFlags);
console.log('bundle-info', 'getBundleInfoForSelfSync successfully: %{public}s', JSON.stringify(this.bundleInfo))
} catch (err) {
let message = (err as BusinessError).message;
console.log('bundle-info', 'getBundleInfoForSelfSync failed: %{public}s', message);
}
}
closeApp() {
this.context.terminateSelf()
}
build() {
Scroll() {
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Start }) {
Text(this.message)
.id('System')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.margin({
bottom: 5
})
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
if (this.bundleInfo) {
Column() {
Row() {
Text('App Package Name: ')
Text(this.bundleInfo.name)
}.width('100%')
Row() {
Text('App Package Vendor: ')
Text(this.bundleInfo.vendor)
}.width('100%')
Row() {
Text('App Package Version Code: ')
Text(this.bundleInfo.versionCode.toString())
}.width('100%')
Row() {
Text('App Package Version Name: ')
Text(this.bundleInfo.versionName)
}.width('100%')
Row() {
Text('App Target Version: ')
Text(this.bundleInfo.targetVersion.toString())
}.width('100%')
Row() {
Text('App Target Version: ')
Text(this.bundleInfo.targetVersion.toString())
}.width('100%')
Row() {
Text('App Installation Time: ')
Text(`${this.bundleInfo.installTime.toString()} -- ${DateUtil.getFormatTimeStr(this.bundleInfo.installTime)}`)
.fontSize(14)
}.width('100%')
Row() {
Text('App Update Time: ')
Text(`${this.bundleInfo.updateTime.toString()} -- ${DateUtil.getFormatTimeStr(this.bundleInfo.updateTime)}`)
.fontSize(14)
}.width('100%')
}
}
Button('Exit App').width('100%').margin({ top: 10 }).onClick(() => {
this.closeApp()
})
}
.height('100%')
.width('100%')
}
.padding(10)
.width('100%')
.height('100%')
}
}
3. [Push] How to resolve the issue where the push image API reports success but the phone does not receive the image?
The push API has limitations on image size. See Notification Large Icon - Description. Use images that meet the requirements.
Even if the cloud successfully sends the message, the device may not receive it due to:
- Expired tokens: Regenerate the token and resend the message.
- Disabled notifications: Ensure the device's notification settings are enabled.
- App uninstalled: Verify the app is installed.
- Message frequency control: See Message Frequency Control.
4. How to implement click event passthrough in a Stack layout?
Problem Scenario:
After overlaying Stack layouts, how can a transparent page pass touch events to underlying views so that sibling components can also respond to events?
Solution:
Use the hitTestBehavior
property to control event passthrough. Refer to the documentation: Multi-level Gesture Handling.
Reference Code:
@Entry
@Component
struct PageHitTestBehavior {
@State message: string = 'Hello World';
build() {
Stack() {
Column() {
Text('Lower Column')
}
.onTouch(() => {
console.log('Lower onTouch')
})
.width('50%')
.height('50%')
.backgroundColor(Color.Blue)
Column() {
Text('Upper Column')
}
.onTouch(() => {
console.log('Upper onTouch')
})
// Set HitTestMode.Transparent to allow touch events to pass through to sibling components
.hitTestBehavior(HitTestMode.Transparent)
.width('50%')
.height('50%')
}
.width('100%')
.height('100%')
}
}
5. How does the client receive push "Alert Messages (Notification Messages)" and background messages?
-
Notification Messages (
push-type
0): Data is accessible only after the user clicks the notification to enter the app. See Sending Notification Messages. -
Background Messages: These messages are received only when the app is running. If the app is not running, messages are cached and delivered when the app starts. They do not appear in the notification bar. Verify configuration in the
module.json5
file'sskills
property. See Sending Background Messages.
Top comments (0)