Read the original article:How to reuse the same subwindow in different locations on multiple pages
Requirement Description
To improve subwindow reusability, both the Index page and PageA page need to reuse the same subwindow.
- On the Index page, the subwindow should appear above the TabBar.
- On the PageA page, the subwindow should appear at the bottom of the page. The goal is to implement this behavior using a single reusable subwindow component.
Background Knowledge
In HarmonyOS, you can create a subwindow using the createSubWindow method.
When creating a subwindow, you can set its initial position using moveWindowTo, which defines the subwindow’s top-left corner coordinates.
After creation, you can find the subwindow by name using the window.findWindow method.
These APIs together allow dynamic control over subwindow positioning and visibility across multiple pages.
Implementation Steps
Step 1: Encapsulate the Subwindow in a Class
- Create a utility class (e.g.,
Until.ets) to encapsulate subwindow logic. - This class provides methods to open, move, and close the subwindow.
- Any page can import and call this class to reuse the same subwindow instance.
Step 2: Set Subwindow Properties
- In the class, use
createSubWindowto initialize the subwindow. - Set its UI content, background color, position, and size using
setUIContent,setWindowBackgroundColor,moveWindowTo, andresize. - Finally, call
showWindow()to display it.
Step 3: Control Subwindow Position from Different Pages
- On the Index page, call
OpenSubWindows()during theaboutToAppear()lifecycle to display the subwindow above the TabBar. - On the PageA page, use
window.findWindow()to retrieve the existing subwindow and reposition it withmoveWindowTo()so that it appears at the bottom.
Step 4: Handle Navigation and Cleanup
- When navigating from the main page to the subpage, reposition the subwindow using
moveWindowTo. - When navigating back, destroy and recreate the subwindow to reset its position.
Step 5: Customize Subwindow Content
- The subwindow page (e.g.,
FloatPage.ets) defines the visible content of the floating window. - It can contain buttons for navigation and closing the subwindow.
Code Snippet / Configuration
1. Encapsulated Subwindow Class (Until.ets)
import { common } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { hilog } from '@kit.PerformanceAnalysisKit';
export class Loading {
win: window.Window | undefined = undefined;
OpenSubWindows(UIContext: UIContext) {
(UIContext?.getHostContext() as common.UIAbilityContext).windowStage.createSubWindow('FloatPage', (err, windowClass) => {
if (err.code > 0) {
hilog.error(0x0000, 'testTag', '%{public}s', `failed to create subWindow Cause: ${err.message}`);
return;
}
this.win = windowClass;
try {
windowClass.setUIContent('pages/FloatPage', () => {
windowClass.setWindowBackgroundColor('#00000000');
});
windowClass.moveWindowTo(0, 2285);
windowClass.resize(1260, 200);
windowClass.showWindow();
} catch (err) {
hilog.error(0x0000, 'testTag', '%{public}s', `failed to create subWindow Cause:${err}`);
}
})
}
CloseSubWindows() {
this.win?.destroyWindow();
}
}
export default new Loading()
2. Subpage Logic (PageA.ets)
import { router, window } from '@kit.ArkUI';
import Loading from './Until';
@Entry
@Component
struct PageA {
floatWindow: window.Window = window.findWindow('FloatPage')
aboutToAppear(): void {
this.floatWindow.moveWindowTo(0, 2500);
}
build() {
Column()
.width('100%')
.height('100%')
.backgroundColor('#5291FF')
.onClick(() => {
router.back()
Loading.CloseSubWindows()
})
}
}
3. Main Page Logic (Index.ets)
import Loading from './Until';
@Entry
@Component
struct Index {
@State fontColor: string = '#182431';
@State selectedFontColor: string = '#007DFF';
@State currentIndex: number = 0;
@State selectedIndex: number = 0;
private controller: TabsController = new TabsController();
aboutToAppear(): void {
Loading.OpenSubWindows(this.getUIContext())
}
build() {
Column() {
Tabs({ barPosition: BarPosition.End, index: this.currentIndex, controller: this.controller }) {
TabContent() {
Column()
.width('100%')
.height('100%')
.backgroundColor('#00CB87')
.onClick(() => {
Loading.OpenSubWindows(this.getUIContext())
})
.onVisibleAreaChange([0.0, 1.0], (isVisible: boolean, currentRatio: number) => {
if (isVisible && currentRatio >= 1.0) {
Loading.OpenSubWindows(this.getUIContext())
}
})
}.tabBar('Tab 0')
TabContent() { Column().width('100%').height('100%').backgroundColor('#007DFF') }.tabBar('Tab 1')
TabContent() { Column().width('100%').height('100%').backgroundColor('#FFBF00') }.tabBar('Tab 2')
TabContent() { Column().width('100%').height('100%').backgroundColor('#E67C92') }.tabBar('Tab 3')
}
.vertical(false)
.barMode(BarMode.Fixed)
.barHeight(56)
.animationDuration(400)
.onChange((index: number) => { this.currentIndex = index; this.selectedIndex = index; })
.onAnimationStart((index: number, targetIndex: number) => {
if (index !== targetIndex) this.selectedIndex = targetIndex;
})
.height('100%')
.backgroundColor('#F1F3F5')
}.width('100%')
}
}
4. Subwindow Page (FloatPage.ets)
import { common } from '@kit.AbilityKit';
import Loading from './Until';
@Entry
@Component
struct FloatPage {
@State message: string = 'Floating Window'
private context = this.getUIContext().getHostContext() as common.UIAbilityContext;
onBackPress() {
Loading.CloseSubWindows()
return true
}
build() {
Row() {
Text(this.message)
.fontSize(15)
.fontWeight(FontWeight.Bold)
.margin({ left: '16vp' })
Button('Go to New Page')
.onClick(() => {
const mainR = this.context.windowStage.getMainWindowSync()
.getUIContext()
.getRouter()
mainR.pushUrl({ url: 'pages/PageA' })
})
Blank()
Button('Close Subwindow')
.onClick(() => { Loading.CloseSubWindows() })
.margin({ right: '16vp' })
}
.width('100%')
.height(50)
.backgroundColor('#FFFFFF')
}
}
Test Results
- When on the Index page, the subwindow appears above the TabBar.
- When navigating to PageA, the subwindow automatically repositions to the bottom.
- When returning to the Index page, the subwindow is destroyed and recreated at the default position.
Limitations or Considerations
- Requires API Version 19 Release or later.
- Requires HarmonyOS 5.1.1 Release SDK or later.
- Must be built and run using DevEco Studio 5.1.1 Release or later.
Top comments (0)