diff --git a/en/application-dev/reference/apis-arkui/Readme-EN.md b/en/application-dev/reference/apis-arkui/Readme-EN.md index 46df4161689a8c633895e23482c8963c684ae77c..38e4b78bc34eb71bc92a806d63fe9d63aa5f97e7 100644 --- a/en/application-dev/reference/apis-arkui/Readme-EN.md +++ b/en/application-dev/reference/apis-arkui/Readme-EN.md @@ -1,7 +1,7 @@ # ArkUI -- ArkTS APIs - - UI +- ArkTS API + - UI - [@ohos.animator (Animator)](js-apis-animator.md) - [@ohos.arkui.componentSnapshot (Component Snapshot)](js-apis-arkui-componentSnapshot.md) - [@ohos.arkui.componentUtils (componentUtils)](js-apis-arkui-componentUtils.md) @@ -12,7 +12,7 @@ - [@ohos.arkui.observer (Observer)](js-apis-arkui-observer.md) - [@ohos.arkui.prefetcher (Prefetching)](js-apis-arkui-Prefetcher.md) - [@ohos.arkui.shape(Shape)](js-apis-arkui-shape.md) - - [@ohos.arkui.Theme (Theme)](js-apis-arkui-theme.md) + - [@ohos.arkui.theme (Theme)](js-apis-arkui-theme.md) - [@ohos.arkui.UIContext (UIContext)](js-apis-arkui-UIContext.md) - [@ohos.arkui.uiExtension (uiExtension)](js-apis-arkui-uiExtension.md) - [@ohos.arkui.StateManagement (State Management)](js-apis-StateManagement.md) @@ -37,7 +37,7 @@ - [@ohos.arkui.UIContext (UIContext) (System API)](js-apis-arkui-UIContext-sys.md) - [@ohos.promptAction (Prompt) (System API)](js-apis-promptAction-sys.md) - - arkui + - ArkUI - [BuilderNode](js-apis-arkui-builderNode.md) - [ComponentContent](js-apis-arkui-ComponentContent.md) - [FrameNode](js-apis-arkui-frameNode.md) @@ -47,21 +47,24 @@ - [AttributeUpdater](js-apis-arkui-AttributeUpdater.md) - [Content](js-apis-arkui-Content.md) - [NodeContent](js-apis-arkui-NodeContent.md) - - Graphics - - [@ohos.display (Display)](js-apis-display.md) + - Window Manager - [@ohos.PiPWindow (PiP Window)](js-apis-pipWindow.md) - [@ohos.window (Window)](js-apis-window.md) - - [@ohos.screenshot (Screenshot)](js-apis-screenshot.md) - [@ohos.animation.windowAnimationManager (Window Animation Management) (System API)](js-apis-windowAnimationManager-sys.md) - [@ohos.application.WindowExtensionAbility (WindowExtensionAbility) (System API)](js-apis-application-windowExtensionAbility-sys.md) + - [@ohos.window (Window) (System API)](js-apis-window-sys.md) + - [WindowExtensionContext (System API)](js-apis-inner-application-windowExtensionContext-sys.md) + + - Display Management + - [@ohos.display (Display)](js-apis-display.md) + - [@ohos.screenshot (Screenshot)](js-apis-screenshot.md) + - [@ohos.display (Display) (System API)](js-apis-display-sys.md) - [@ohos.screen (Screen) (System API)](js-apis-screen-sys.md) - [@ohos.screenshot (Screenshot) (System API)](js-apis-screenshot-sys.md) - - [@ohos.window (Window) (System API)](js-apis-window-sys.md) - - [WindowExtensionContext (System API)](js-apis-inner-application-windowExtensionContext-sys.md) - - APIs No Longer Maintained + - APIs No Longer Maintained - [@ohos.prompt (Prompt)](js-apis-prompt.md) - [@system.app (Application Context)](js-apis-system-app.md) - [@system.configuration (Application Configuration)](js-apis-system-configuration.md) @@ -69,118 +72,133 @@ - [@system.prompt (Prompt)](js-apis-system-prompt.md) - [@system.router (Page Routing)](js-apis-system-router.md) - [XComponentNode](js-apis-arkui-xcomponentNode.md) -- ArkTS Components - - Universal Component Information - - Universal Events - - [Click Event](arkui-ts/ts-universal-events-click.md) +- ArkTS Components + - Universal Component Information + - [Universal Events](arkui-ts/ts-component-general-events.md) - [Touch Event](arkui-ts/ts-universal-events-touch.md) - - [Show/Hide Event](arkui-ts/ts-universal-events-show-hide.md) - - [Drag/Drop Event](arkui-ts/ts-universal-events-drag-drop.md) - - [Key Event](arkui-ts/ts-universal-events-key.md) - - [Focus Event](arkui-ts/ts-universal-focus-event.md) - [Mouse Event](arkui-ts/ts-universal-mouse-key.md) + - [Axis Event](arkui-ts/ts-universal-events-axis.md) + - [Key Event](arkui-ts/ts-universal-events-key.md) - [Crown Event](arkui-ts/ts-universal-events-crown.md) + - [Focus Axis Event](arkui-ts/ts-universal-events-focus_axis.md) + - [Click Event](arkui-ts/ts-universal-events-click.md) + - [Drag/Drop Event](arkui-ts/ts-universal-events-drag-drop.md) + - [Drag Event (System API)](arkui-ts/ts-universal-events-drag-drop-sys.md) + - [Focus Event](arkui-ts/ts-universal-focus-event.md) - [Hover Event](arkui-ts/ts-universal-events-hover.md) + - [Component Keyboard Shortcut Event](arkui-ts/ts-universal-events-keyboardshortcut.md) + - [Custom Event Interception](arkui-ts/ts-universal-attributes-on-touch-intercept.md) + - [Custom Event Dispatch](arkui-ts/ts-universal-attributes-on-child-touch-test.md) + - [Accessibility Event](arkui-ts/ts-universal-accessibility-event.md) - [Accessibility Hover Event](arkui-ts/ts-universal-accessibility-hover-event.md) + - [Show/Hide Event](arkui-ts/ts-universal-events-show-hide.md) - [Component Area Change Event](arkui-ts/ts-universal-component-area-change-event.md) - [Component Size Change Event](arkui-ts/ts-universal-component-size-change-event.md) - [Visible Area Change Event](arkui-ts/ts-universal-component-visible-area-change-event.md) - - [Component Keyboard Shortcut Event](arkui-ts/ts-universal-events-keyboardshortcut.md) - - [Custom Event Dispatch](arkui-ts/ts-universal-attributes-on-child-touch-test.md) - - [Custom Event Interception](arkui-ts/ts-universal-attributes-on-touch-intercept.md) - - [Focus Axis Event](arkui-ts/ts-universal-events-focus_axis.md) - - Universal attributes + - [Universal Attributes](arkui-ts/ts-component-general-attributes.md) + - Basic Attributes + - [Component ID](arkui-ts/ts-universal-attributes-component-id.md) + - [restoreId](arkui-ts/ts-universal-attributes-restoreId.md) + - [Visibility](arkui-ts/ts-universal-attributes-visibility.md) + - [Background](arkui-ts/ts-universal-attributes-background.md) + - [Overlay](arkui-ts/ts-universal-attributes-overlay.md) + - [Z-order Control](arkui-ts/ts-universal-attributes-z-order.md) + - [Obscuring](arkui-ts/ts-universal-attributes-obscured.md) + - Layout and Borders - [Size](arkui-ts/ts-universal-attributes-size.md) - [Location](arkui-ts/ts-universal-attributes-location.md) - [Layout Constraints](arkui-ts/ts-universal-attributes-layout-constraints.md) - - [Component-Level Pixel Rounding](arkui-ts/ts-universal-attributes-pixelRound.md) - [Flex Layout](arkui-ts/ts-universal-attributes-flex-layout.md) + - [Safe Area](arkui-ts/ts-universal-attributes-expand-safe-area.md) + - [Component-Level Pixel Rounding](arkui-ts/ts-universal-attributes-pixelRound.md) - [Border](arkui-ts/ts-universal-attributes-border.md) - [Border Image](arkui-ts/ts-universal-attributes-border-image.md) - - [Background](arkui-ts/ts-universal-attributes-background.md) + - Visual Effects - [Opacity](arkui-ts/ts-universal-attributes-opacity.md) - - [Visibility](arkui-ts/ts-universal-attributes-visibility.md) - - [Enable/Disable](arkui-ts/ts-universal-attributes-enable.md) - - [Overlay](arkui-ts/ts-universal-attributes-overlay.md) - - [Z-order Control](arkui-ts/ts-universal-attributes-z-order.md) - [Transformation](arkui-ts/ts-universal-attributes-transformation.md) - [Image Effect](arkui-ts/ts-universal-attributes-image-effect.md) - [Shape Clipping](arkui-ts/ts-universal-attributes-sharp-clipping.md) - - [Gradient Color](arkui-ts/ts-universal-attributes-gradient-color.md) - - [Popup Control](arkui-ts/ts-universal-attributes-popup.md) - - [Menu Control](arkui-ts/ts-universal-attributes-menu.md) - - [Focus Control](arkui-ts/ts-universal-attributes-focus.md) - - [Hover Effect](arkui-ts/ts-universal-attributes-hover-effect.md) - - [Component ID](arkui-ts/ts-universal-attributes-component-id.md) - - [Reuse ID](arkui-ts/ts-universal-attributes-reuse-id.md) - - [Polymorphic Style](arkui-ts/ts-universal-attributes-polymorphic-style.md) - - [restoreId](arkui-ts/ts-universal-attributes-restoreId.md) + - [Color Gradient](arkui-ts/ts-universal-attributes-gradient-color.md) - [Foreground Color](arkui-ts/ts-universal-attributes-foreground-color.md) - [Foreground Effect](arkui-ts/ts-universal-attributes-foreground-effect.md) + - [Outline](arkui-ts/ts-universal-attributes-outline.md) + - [Visual Effect](arkui-ts/ts-universal-attributes-filter-effect.md) - [Foreground Blur](arkui-ts/ts-universal-attributes-foreground-blur-style.md) - [Motion Blur](arkui-ts/ts-universal-attributes-motionBlur.md) - [Click Effect](arkui-ts/ts-universal-attributes-click-effect.md) - - [Accessibility](arkui-ts/ts-universal-attributes-accessibility.md) - - [Attribute Modifier](arkui-ts/ts-universal-attributes-attribute-modifier.md) - - [Gesture Modifier](arkui-ts/ts-universal-attributes-gesture-modifier.md) - - [Outline](arkui-ts/ts-universal-attributes-outline.md) - - [Visual Effect](arkui-ts/ts-universal-attributes-filter-effect.md) - - [Drawing Modifier](arkui-ts/ts-universal-attributes-draw-modifier.md) - - [Content Modifier](arkui-ts/ts-universal-attributes-content-modifier.md) - - [Custom Property](arkui-ts/ts-universal-attributes-custom-property.md) - - Touch Interactions - - [Touch Target](arkui-ts/ts-universal-attributes-touch-target.md) - - [Hit Test Control](arkui-ts/ts-universal-attributes-hit-test-behavior.md) - - Transition - - [Modal Transition](arkui-ts/ts-universal-attributes-modal-transition.md) - - [Sheet Transition](arkui-ts/ts-universal-attributes-sheet-transition.md) - - [Sheet Transition (System API)](arkui-ts/ts-universal-attributes-sheet-transition-sys.md) - - [Obscuring](arkui-ts/ts-universal-attributes-obscured.md) - - [Universal Text Attributes](arkui-ts/ts-universal-attributes-text-style.md) - - [Drag and Drop Control](arkui-ts/ts-universal-attributes-drag-drop.md) - - [Safe Area](arkui-ts/ts-universal-attributes-expand-safe-area.md) - - [Render Fit](arkui-ts/ts-universal-attributes-renderfit.md) - - [Event Monopolization](arkui-ts/ts-universal-attributes-monopolize-events.md) - - [Cursor Control](arkui-ts/ts-universal-attributes-cursor.md) - [Special Effect Drawing Combination](arkui-ts/ts-universal-attributes-use-effect.md) + - [Render Fit](arkui-ts/ts-universal-attributes-renderfit.md) - [Point Light Style (System API)](arkui-ts/ts-universal-attributes-point-light-style-sys.md) - [Image Effect (System API)](arkui-ts/ts-universal-attributes-image-effect-sys.md) - - Gesture Handling + - Interaction Properties + - [Enable/Disable](arkui-ts/ts-universal-attributes-enable.md) + - [Focus Control](arkui-ts/ts-universal-attributes-focus.md) + - [Drag and Drop Control](arkui-ts/ts-universal-attributes-drag-drop.md) + - [Hover Effect](arkui-ts/ts-universal-attributes-hover-effect.md) + - Touch Interactions + - [Touch Target](arkui-ts/ts-universal-attributes-touch-target.md) + - [Hit Test Control](arkui-ts/ts-universal-attributes-hit-test-behavior.md) + - [Event Monopolization](arkui-ts/ts-universal-attributes-monopolize-events.md) + - [Cursor Control](arkui-ts/ts-universal-attributes-cursor.md) + - [Polymorphic Style](arkui-ts/ts-universal-attributes-polymorphic-style.md) + - Dialog Box Control + - [Popup Control](arkui-ts/ts-universal-attributes-popup.md) + - [Tooltip Control](arkui-ts/ts-universal-attributes-tips.md) + - [Menu Control](arkui-ts/ts-universal-attributes-menu.md) + - [Accessibility](arkui-ts/ts-universal-attributes-accessibility.md) + - [Universal Text Attributes](arkui-ts/ts-universal-attributes-text-style.md) + - Transition + - [Modal Transition](arkui-ts/ts-universal-attributes-modal-transition.md) + - [Sheet Transition](arkui-ts/ts-universal-attributes-sheet-transition.md) + + - [Sheet Transition (System API)](arkui-ts/ts-universal-attributes-sheet-transition-sys.md) + + - Modifiers and Custom Property + - [Attribute Modifier](arkui-ts/ts-universal-attributes-attribute-modifier.md) + - [Gesture Modifier](arkui-ts/ts-universal-attributes-gesture-modifier.md) + - [Drawing Modifier](arkui-ts/ts-universal-attributes-draw-modifier.md) + - [Content Modifier](arkui-ts/ts-universal-attributes-content-modifier.md) + - [Custom Property](arkui-ts/ts-universal-attributes-custom-property.md) + - Other + - [Reuse ID](arkui-ts/ts-universal-attributes-reuse-id.md) + - [Reuse Options](arkui-ts/ts-universal-attributes-reuse.md) + - [Toolbar](arkui-ts/ts-universal-attributes-toolbar.md) + - Gesture Handling + - Gesture Binding - [Gesture Binding Methods](arkui-ts/ts-gesture-settings.md) + - [Bound Gesture Configuration](arkui-ts/ts-uigestureevent.md) + - Basic Gestures - [TapGesture](arkui-ts/ts-basic-gestures-tapgesture.md) - [LongPressGesture](arkui-ts/ts-basic-gestures-longpressgesture.md) - [PanGesture](arkui-ts/ts-basic-gestures-pangesture.md) - [PinchGesture](arkui-ts/ts-basic-gestures-pinchgesture.md) - [RotationGesture](arkui-ts/ts-basic-gestures-rotationgesture.md) - [SwipeGesture](arkui-ts/ts-basic-gestures-swipegesture.md) - - [Combined Gestures](arkui-ts/ts-combined-gestures.md) + - [Combined Gestures](arkui-ts/ts-combined-gestures.md) + - Gesture Control - [Custom Gesture Judgment](arkui-ts/ts-gesture-customize-judge.md) - - [Bound Gesture Configuration](arkui-ts/ts-uigestureevent.md) - [Gesture Blocking Enhancement](arkui-ts/ts-gesture-blocking-enhancement.md) - - Rows, Columns, and Stacking + - Rows, Columns, and Stacking - [Flex](arkui-ts/ts-container-flex.md) - [Column](arkui-ts/ts-container-column.md) - [Row](arkui-ts/ts-container-row.md) - [Stack](arkui-ts/ts-container-stack.md) - [RelativeContainer](arkui-ts/ts-container-relativecontainer.md) - - [FolderStack](arkui-ts/ts-container-folderstack.md) - [Flex (System API)](arkui-ts/ts-container-flex-sys.md) - [Column (System API)](arkui-ts/ts-container-column-sys.md) - [Row (System API)](arkui-ts/ts-container-row-sys.md) - [Stack (System API)](arkui-ts/ts-container-stack-sys.md) - - Grid and Column Layout + - Grid and Column Layout - [GridRow](arkui-ts/ts-container-gridrow.md) - [GridCol](arkui-ts/ts-container-gridcol.md) - [ColumnSplit](arkui-ts/ts-container-columnsplit.md) - [RowSplit](arkui-ts/ts-container-rowsplit.md) - - [SplitLayout](arkui-ts/ohos-arkui-advanced-SplitLayout.md) - - [FoldSplitContainer](arkui-ts/ohos-arkui-advanced-FoldSplitContainer.md) - [SideBarContainer](arkui-ts/ts-container-sidebarcontainer.md) - - Scroll and Swipe + - Scroll and Swipe - [List](arkui-ts/ts-container-list.md) - [ListItem](arkui-ts/ts-container-listitem.md) - [ListItemGroup](arkui-ts/ts-container-listitemgroup.md) @@ -190,19 +208,18 @@ - [GridItem](arkui-ts/ts-container-griditem.md) - [Scroll](arkui-ts/ts-container-scroll.md) - [Swiper](arkui-ts/ts-container-swiper.md) + - [ArcSwiper](arkui-ts/ts-container-arcswiper.md) - [WaterFlow](arkui-ts/ts-container-waterflow.md) - [FlowItem](arkui-ts/ts-container-flowitem.md) + - [LazyVGridLayout](arkui-ts/ts-container-lazyvgridlayout.md) - [ScrollBar](arkui-ts/ts-basic-components-scrollbar.md) - [Refresh](arkui-ts/ts-container-refresh.md) - - [ComposeListItem](arkui-ts/ohos-arkui-advanced-ComposeListItem.md) - - [GridObjectSortComponent](arkui-ts/ohos-arkui-advanced-GridObjectSortComponent.md) - - [SwipeRefresher](arkui-ts/ohos-arkui-advanced-SwipeRefresher.md) - [ArcScrollBar](arkui-ts/ts-basic-components-arcscrollbar.md) - [Scrollable Component Common APIs](arkui-ts/ts-container-scrollable-common.md) - [List (System API)](arkui-ts/ts-container-list-sys.md) - - Navigation and Switching + - Navigation and Switching - [Indicator](arkui-ts/ts-swiper-components-indicator.md) - [Navigation](arkui-ts/ts-basic-components-navigation.md) - [NavDestination](arkui-ts/ts-basic-components-navdestination.md) @@ -211,7 +228,8 @@ - [StepperItem](arkui-ts/ts-basic-components-stepperitem.md) - [Tabs](arkui-ts/ts-container-tabs.md) - [TabContent](arkui-ts/ts-container-tabcontent.md) - - Buttons and Selections + - [ToolBarItem](arkui-ts/ts-basic-components-toolbaritem.md) + - Buttons and Selections - [Button](arkui-ts/ts-basic-components-button.md) - [Toggle](arkui-ts/ts-basic-components-toggle.md) - [Checkbox](arkui-ts/ts-basic-components-checkbox.md) @@ -224,13 +242,10 @@ - [Rating](arkui-ts/ts-basic-components-rating.md) - [Select](arkui-ts/ts-basic-components-select.md) - [Slider](arkui-ts/ts-basic-components-slider.md) - - [DownloadFileButton](arkui-ts/ohos-arkui-advanced-DownloadFileButton.md) - - [ProgressButton](arkui-ts/ohos-arkui-advanced-ProgressButton.md) - - [SegmentButton](arkui-ts/ohos-arkui-advanced-SegmentButton.md) - [SegmentButtonV2](arkui-ts/ohos-arkui-advanced-SegmentButtonV2.md) - - [Filter](arkui-ts/ohos-arkui-advanced-Filter.md) - [ArcButton](arkui-ts/ohos-arkui-advanced-ArcButton.md) - - Text and Input + - [ArcSlider](arkui-ts/ohos-arkui-advanced-ArcSlider.md) + - Text and Input - [Text](arkui-ts/ts-basic-components-text.md) - [TextArea](arkui-ts/ts-basic-components-textarea.md) - [TextInput](arkui-ts/ts-basic-components-textinput.md) @@ -243,14 +258,15 @@ - [SymbolGlyph](arkui-ts/ts-basic-components-symbolGlyph.md) - [Hyperlink](arkui-ts/ts-container-hyperlink.md) - [RichText](arkui-ts/ts-basic-components-richtext.md) - - [SelectionMenu](arkui-ts/ohos-arkui-advanced-SelectionMenu.md) - [Styled String](arkui-ts/ts-universal-styled-string.md) - [Text Component Common APIs](arkui-ts/ts-text-common.md) + - [Text Component Common APIs (System API)](arkui-ts/ts-text-common-sys.md) - [TextInput (System API)](arkui-ts/ts-basic-components-textinput-sys.md) - [Styled String (System API)](arkui-ts/ts-universal-styled-string-sys.md) + - [RichEditor (System API)](arkui-ts/ts-basic-components-richeditor-sys.md) - - Images and Videos + - Images and Videos - [Image](arkui-ts/ts-basic-components-image.md) - [ImageAnimator](arkui-ts/ts-basic-components-imageanimator.md) - [Video](arkui-ts/ts-media-components-video.md) @@ -258,32 +274,27 @@ - [Image (System API)](arkui-ts/ts-basic-components-image-sys.md) - [MediaCachedImage (System API)](arkui-ts/ts-basic-components-mediacachedimage-sys.md) + - [Video (System API)](arkui-ts/ts-media-components-video-sys.md) - - Information Display + - Information Display - [AlphabetIndexer](arkui-ts/ts-container-alphabet-indexer.md) - [ArcAlphabetIndexer](arkui-ts/ts-container-arc-alphabet-indexer.md) - [Badge](arkui-ts/ts-container-badge.md) - - [Chip](arkui-ts/ohos-arkui-advanced-Chip.md) - - [ChipGroup](arkui-ts/ohos-arkui-advanced-ChipGroup.md) - [Counter](arkui-ts/ts-container-counter.md) - [advanced.Counter](arkui-ts/ohos-arkui-advanced-Counter.md) - [DataPanel](arkui-ts/ts-basic-components-datapanel.md) - - [ExceptionPrompt](arkui-ts/ohos-arkui-advanced-ExceptionPrompt.md) - [Gauge](arkui-ts/ts-basic-components-gauge.md) - [LoadingProgress](arkui-ts/ts-basic-components-loadingprogress.md) - - [LinearIndicator](arkui-ts/ts-basic-components-linearindicator.md) - [Marquee](arkui-ts/ts-basic-components-marquee.md) - [PatternLock](arkui-ts/ts-basic-components-patternlock.md) - [Progress](arkui-ts/ts-basic-components-progress.md) - - [Popup](arkui-ts/ohos-arkui-advanced-Popup.md) - [QRCode](arkui-ts/ts-basic-components-qrcode.md) - [TextClock](arkui-ts/ts-basic-components-textclock.md) - [TextTimer](arkui-ts/ts-basic-components-texttimer.md) - - [TreeView](arkui-ts/ohos-arkui-advanced-TreeView.md) - - Blank and Divider + - Blank and Divider - [Blank](arkui-ts/ts-basic-components-blank.md) - [Divider](arkui-ts/ts-basic-components-divider.md) - - Canvas Drawing + - Canvas Drawing - [Canvas](arkui-ts/ts-components-canvas-canvas.md) - [CanvasGradient](arkui-ts/ts-components-canvas-canvasgradient.md) - [CanvasPattern](arkui-ts/ts-components-canvas-canvaspattern.md) @@ -295,7 +306,7 @@ - [OffscreenCanvas](arkui-ts/ts-components-offscreencanvas.md) - [OffscreenCanvasRenderingContext2D](arkui-ts/ts-offscreencanvasrenderingcontext2d.md) - [Path2D](arkui-ts/ts-components-canvas-path2d.md) - - Graphic Drawing + - Graphic Drawing - [Circle](arkui-ts/ts-drawing-components-circle.md) - [Ellipse](arkui-ts/ts-drawing-components-ellipse.md) - [Line](arkui-ts/ts-drawing-components-line.md) @@ -304,24 +315,17 @@ - [Path](arkui-ts/ts-drawing-components-path.md) - [Rect](arkui-ts/ts-drawing-components-rect.md) - [Shape](arkui-ts/ts-drawing-components-shape.md) - - Rendering Drawing + - Rendering Drawing - [XComponent](arkui-ts/ts-basic-components-xcomponent.md) - [Component3D](arkui-ts/ts-basic-components-component3d.md) - [EmbeddedComponent](arkui-ts/ts-container-embedded-component.md) - [XComponent (System API)](arkui-ts/ts-basic-components-xcomponent-sys.md) - - Title Bars and Toolbars - - [ComposeTitleBar](arkui-ts/ohos-arkui-advanced-ComposeTitleBar.md) - - [EditableTitleBar](arkui-ts/ohos-arkui-advanced-EditableTitleBar.md) - - [SelectTitleBar](arkui-ts/ohos-arkui-advanced-SelectTitleBar.md) - - [TabTitleBar](arkui-ts/ohos-arkui-advanced-TabTitleBar.md) - - [ToolBar](arkui-ts/ohos-arkui-advanced-ToolBar.md) - - [SubHeader](arkui-ts/ohos-arkui-advanced-SubHeader.md) - - Menus + - Menus - [Menu](arkui-ts/ts-basic-components-menu.md) - [MenuItem](arkui-ts/ts-basic-components-menuitem.md) - [MenuItemGroup](arkui-ts/ts-basic-components-menuitemgroup.md) - [ContextMenu](arkui-ts/ts-methods-menu.md) - - Animation + - Animation - [Property Animation (animation)](arkui-ts/ts-animatorproperty.md) - [Explicit Animation (animateTo)](arkui-ts/ts-explicit-animation.md) - [Keyframe Animation (keyframeAnimateTo)](arkui-ts/ts-keyframeAnimateTo.md) @@ -335,7 +339,7 @@ - [Implicit Shared Element Transition (geometryTransition) (System API)](arkui-ts/ts-transition-animation-geometrytransition-sys.md) - - Dialog Boxes + - Dialog Boxes - [Alert Dialog Box (AlertDialog)](arkui-ts/ts-methods-alert-dialog-box.md) - [Action Sheet (ActionSheet)](arkui-ts/ts-methods-action-sheet.md) - [Custom Dialog Box (CustomDialog)](arkui-ts/ts-methods-custom-dialog-box.md) @@ -344,47 +348,77 @@ - [Time Picker Dialog Box (TimePickerDialog)](arkui-ts/ts-methods-timepicker-dialog.md) - [Text Picker Dialog Box (TextPickerDialog)](arkui-ts/ts-methods-textpicker-dialog.md) - [Dialog Box (Dialog)](arkui-ts/ohos-arkui-advanced-Dialog.md) - - Service Widgets + - Service Widgets - [FormLink](arkui-ts/ts-container-formlink.md) - - [FormMenu](arkui-ts/ohos-arkui-advanced-formmenu.md) - [FormComponent (System API)](arkui-ts/ts-basic-components-formcomponent-sys.md) - - Security + - Security - [Security Component Universal Attributes](arkui-ts/ts-securitycomponent-attributes.md) - [PasteButton](arkui-ts/ts-security-components-pastebutton.md) - [SaveButton](arkui-ts/ts-security-components-savebutton.md) - [SaveButton (System API)](arkui-ts/ts-security-components-savebutton-sys.md) - - Themes + - Themes - [WithTheme](arkui-ts/ts-container-with-theme.md) - - Atomic Services + - Atomic Services - [AtomicServiceNavigation](arkui-ts/ohos-atomicservice-AtomicServiceNavigation.md) + - [AtomicServiceSearch](arkui-ts/ohos-atomicservice-AtomicServiceSearch.md) - [AtomicServiceTabs](arkui-ts/ohos-atomicservice-AtomicServiceTabs.md) - [AtomicServiceWeb](arkui-ts/ohos-atomicservice-AtomicServiceWeb.md) - [InterstitialDialogAction](arkui-ts/ohos-atomicservice-InterstitialDialogAction.md) - - [FullScreenLaunchComponent](arkui-ts/ohos-arkui-advanced-FullScreenLaunchComponent.md) + - [HalfScreenLaunchComponent](arkui-ts/ohos-atomicservice-HalfScreenLaunchComponent.md) - [InnerFullScreenLaunchComponent (System API)](arkui-ts/ohos-arkui-advanced-InnerFullScreenLaunchComponent-sys.md) - [NavPushPathHelper](arkui-ts/ohos-atomicservice-NavPushPathHelper.md) - - Custom Placeholder Components + - Custom Placeholder Components - [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md) - [ContentSlot](arkui-ts/ts-components-contentSlot.md) - - Custom Components + - Custom Components - [Custom Component Lifecycle](arkui-ts/ts-custom-component-lifecycle.md) - [Custom Component Layout](arkui-ts/ts-custom-component-layout.md) - [Custom Component Built-in APIs](arkui-ts/ts-custom-component-api.md) - - State Management and Rendering Control + - System Preset UI Component Library + - [Chip](arkui-ts/ohos-arkui-advanced-Chip.md) + - [ChipGroup](arkui-ts/ohos-arkui-advanced-ChipGroup.md) + - [ComposeListItem](arkui-ts/ohos-arkui-advanced-ComposeListItem.md) + - [ComposeTitleBar](arkui-ts/ohos-arkui-advanced-ComposeTitleBar.md) + - [DownloadFileButton](arkui-ts/ohos-arkui-advanced-DownloadFileButton.md) + - [DialogV2](arkui-ts/ohos-arkui-advanced-DialogV2.md) + - [EditableTitleBar](arkui-ts/ohos-arkui-advanced-EditableTitleBar.md) + - [ExceptionPrompt](arkui-ts/ohos-arkui-advanced-ExceptionPrompt.md) + - [Filter](arkui-ts/ohos-arkui-advanced-Filter.md) + - [FolderStack](arkui-ts/ts-container-folderstack.md) + - [FoldSplitContainer](arkui-ts/ohos-arkui-advanced-FoldSplitContainer.md) + - [FormMenu](arkui-ts/ohos-arkui-advanced-formmenu.md) + - [FullScreenLaunchComponent](arkui-ts/ohos-arkui-advanced-FullScreenLaunchComponent.md) + - [GridObjectSortComponent](arkui-ts/ohos-arkui-advanced-GridObjectSortComponent.md) + - [Popup](arkui-ts/ohos-arkui-advanced-Popup.md) + - [ProgressButton](arkui-ts/ohos-arkui-advanced-ProgressButton.md) + - [ProgressButtonV2](arkui-ts/ohos-arkui-advanced-ProgressButtonV2.md) + - [SegmentButton](arkui-ts/ohos-arkui-advanced-SegmentButton.md) + - [SelectTitleBar](arkui-ts/ohos-arkui-advanced-SelectTitleBar.md) + - [SelectionMenu](arkui-ts/ohos-arkui-advanced-SelectionMenu.md) + - [SplitLayout](arkui-ts/ohos-arkui-advanced-SplitLayout.md) + - [SubHeader](arkui-ts/ohos-arkui-advanced-SubHeader.md) + - [SubHeaderV2](arkui-ts/ohos-arkui-advanced-SubHeaderV2.md) + - [SwipeRefresher](arkui-ts/ohos-arkui-advanced-SwipeRefresher.md) + - [TabTitleBar](arkui-ts/ohos-arkui-advanced-TabTitleBar.md) + - [ToolBar](arkui-ts/ohos-arkui-advanced-ToolBar.md) + - [ToolBarV2](arkui-ts/ohos-arkui-advanced-ToolBarV2.md) + - [TreeView](arkui-ts/ohos-arkui-advanced-TreeView.md) + - State Management and Rendering Control - [State Management with Application-level Variables](arkui-ts/ts-state-management.md) + - [State Variable Change Listening](arkui-ts/ts-state-management-watch-monitor.md) - [ForEach](arkui-ts/ts-rendering-control-foreach.md) - [LazyForEach](arkui-ts/ts-rendering-control-lazyforeach.md) - [Repeat](arkui-ts/ts-rendering-control-repeat.md) - [State Management with Application-level Variables (System API)](arkui-ts/ts-state-management-sys.md) - - Common Definitions + - Common Definitions - [Basic Types](arkui-ts/ts-types.md) - [Pixel Units](arkui-ts/ts-pixel-units.md) - [Enums](arkui-ts/ts-appendix-enums.md) @@ -394,14 +428,14 @@ - [Enums (System API)](arkui-ts/ts-appendix-enums-sys.md) - - Other + - Other - [EffectComponent (System API)](arkui-ts/ts-container-effectcomponent-sys.md) - [IsolatedComponent (System API)](arkui-ts/ts-container-isolated-component-sys.md) - [RemoteWindow (System API)](arkui-ts/ts-basic-components-remotewindow-sys.md) - [PluginComponent (System API)](arkui-ts/ts-basic-components-plugincomponent-sys.md) - [UIExtensionComponent (System API)](arkui-ts/ts-container-ui-extension-component-sys.md) - - Components and APIs No Longer Maintained + - Components and APIs No Longer Maintained - [AbilityComponent](arkui-ts/ts-container-ability-component-sys.md) @@ -412,19 +446,19 @@ - [Navigator](arkui-ts/ts-container-navigator.md) - [Click Control](arkui-ts/ts-universal-attributes-click.md) - [Grid](arkui-ts/ts-universal-attributes-grid.md) -- JavaScript Components +- JavaScript Components - [JavaScript-compatible Web-like Development Paradigm (ArkUI.Full)](arkui-js/Readme-EN.md) - [JavaScript-compatible Web-like Development Paradigm (ArkUI.Lite)](arkui-js-lite/Readme-EN.md) - [JavaScript Service Widget UI Components](js-service-widget-ui/Readme-EN.md) -- C APIs - - Modules +- C API + - Modules - [ArkUI_NativeModule](_ark_u_i___native_module.md) - [Native Accessibility](arkui_native_interface_accessibility.md) - [Native XComponent](_o_h___native_x_component.md) - [ArkUI_EventModule](_ark_u_i___event_module.md) - - [WindowManager_NativeModule](_window_manager___native_module.md) - - [OH_DisplayManager](_o_h___display_manager.md) - - Header Files + - [WindowManager](capi-windowmanager.md) + - [OH_DisplayManager](capi-oh-displaymanager.md) + - Header Files - [drag_and_drop.h](drag__and__drop_8h.md) - [drawable_descriptor.h](drawable__descriptor_8h.md) - [native_animate.h](native__animate_8h.md) @@ -441,12 +475,14 @@ - [native_xcomponent_key_event.h](native__xcomponent__key__event_8h.md) - [styled_string.h](styled__string_8h.md) - [ui_input_event.h](ui__input__event_8h.md) - - [oh_window_comm.h](oh__window__comm_8h.md) - - [oh_window_event_filter.h](oh__window__event__filter_8h.md) - - [oh_display_capture.h](oh__display__capture_8h.md) - - [oh_display_info.h](oh__display__info_8h.md) - - [oh_display_manager.h](oh__display__manager_8h.md) - - Structs + - [oh_window.h](capi-oh-window-h.md) + - [oh_window_comm.h](capi-oh-window-comm-h.md) + - [oh_window_event_filter.h](capi-oh-window-event-filter-h.md) + - [oh_window_pip.h](capi-oh-window-pip-h.md) + - [oh_display_capture.h](capi-oh-display-capture-h.md) + - [oh_display_info.h](capi-oh-display-info-h.md) + - [oh_display_manager.h](capi-oh-display-manager-h.md) + - Structs - [ArkUI_AnimateCompleteCallback](_ark_u_i___animate_complete_callback.md) - [ArkUI_AttributeItem](_ark_u_i___attribute_item.md) - [ArkUI_ColorStop](_ark_u_i___color_stop.md) @@ -457,7 +493,10 @@ - [ArkUI_Margin](_ark_u_i___margin.md) - [ArkUI_NativeAnimateAPI_1](_ark_u_i___native_animate_a_p_i__1.md) - [ArkUI_NativeDialogAPI_1](_ark_u_i___native_dialog_a_p_i__1.md) + - [ArkUI_NativeDialogAPI_2](_ark_u_i___native_dialog_a_p_i__2.md) + - [ArkUI_NativeDialogAPI_3](_ark_u_i___native_dialog_a_p_i__3.md) - [ArkUI_NativeGestureAPI_1](_ark_u_i___native_gesture_a_p_i__1.md) + - [ArkUI_NativeGestureAPI_2](_ark_u_i___native_gesture_a_p_i__2.md) - [ArkUI_NativeNodeAPI_1](_ark_u_i___native_node_a_p_i__1.md) - [ArkUI_NodeComponentEvent](_ark_u_i___node_component_event.md) - [ArkUI_NumberValue](union_ark_u_i___number_value.md) @@ -465,6 +504,7 @@ - [ArkUI_RotationOptions](_ark_u_i___rotation_options.md) - [ArkUI_ScaleOptions](_ark_u_i___scale_options.md) - [ArkUI_StringAsyncEvent](_ark_u_i___string_async_event.md) + - [ArkUI_TextChangeEvent](_ark_u_i___text_change_event.md) - [ARKUI_TextPickerCascadeRangeContent](_a_r_k_u_i___text_picker_cascade_range_content.md) - [ARKUI_TextPickerRangeContent](_a_r_k_u_i___text_picker_range_content.md) - [ArkUI_TranslationOptions](_ark_u_i___translation_options.md) @@ -474,19 +514,23 @@ - [OH_NativeXComponent_MouseEvent_Callback](_o_h___native_x_component___mouse_event___callback.md) - [OH_NativeXComponent_TouchEvent](_o_h___native_x_component___touch_event.md) - [OH_NativeXComponent_TouchPoint](_o_h___native_x_component___touch_point.md) - - [NativeDisplayManager_CutoutInfo](_native_display_manager___cutout_info.md) - - [NativeDisplayManager_DisplayColorSpace](_native_display_manager___display_color_space.md) - - [NativeDisplayManager_DisplayHdrFormat](_native_display_manager___display_hdr_format.md) - - [NativeDisplayManager_DisplayInfo](_native_display_manager___display_info.md) - - [NativeDisplayManager_DisplaysInfo](_native_display_manager___displays_info.md) - - [NativeDisplayManager_Rect](_native_display_manager___rect.md) - - [NativeDisplayManager_WaterfallDisplayAreaRects](ive_display_manager___waterfall_display_area_rects.md) -- Error Codes - - UI + - [PictureInPicture_PipConfig](capi-pictureinpicture-pipconfig.md) + - [WindowManager_Rect](capi-windowmanager-rect.md) + - [struct](capi-struct.md) + - [WindowManager_WindowProperties](capi-windowmanager-windowproperties.md) + - [WindowManager_AvoidArea](capi-windowmanager-avoidarea.md) + - [NativeDisplayManager_Rect](capi-nativedisplaymanager-rect.md) + - [NativeDisplayManager_WaterfallDisplayAreaRects](capi-nativedisplaymanager-waterfalldisplayarearects.md) + - [NativeDisplayManager_CutoutInfo](capi-nativedisplaymanager-cutoutinfo.md) + - [NativeDisplayManager_DisplayHdrFormat](capi-nativedisplaymanager-displayhdrformat.md) + - [NativeDisplayManager_DisplayColorSpace](capi-nativedisplaymanager-displaycolorspace.md) + - [NativeDisplayManager_DisplayInfo](capi-nativedisplaymanager-displayinfo.md) + - [NativeDisplayManager_DisplaysInfo](capi-nativedisplaymanager-displaysinfo.md) +- Error Codes + - UI - [Animator Error Codes](errorcode-animator.md) - [promptAction Error Codes](errorcode-promptAction.md) - [Router Error Codes](errorcode-router.md) - - [UI Appearance Error Codes](errorcode-uiappearance.md) - [Drag Event Error Codes](errorcode-drag-event.md) - [AI Image Analyzer Error Codes](errorcode-image-analyzer.md) - [Focus Error Codes](errorcode-focus.md) @@ -494,7 +538,17 @@ - [Sheet Error Codes](errorcode-bindSheet.md) - [Scrollable Component Error Codes](errorcode-scroll.md) - [Snapshot Error Codes](errorcode-snapshot.md) - - Graphics + - [Styled String Error Codes](errorcode-styled-string.md) + - [UI Context Error Codes](errorcode-uicontext.md) + - [注册节点渲染状态监听错误码](errorcode-node-render-monitor.md) + - [Interaction Event Error Codes](errorcode-event.md) + - [Canvas Error Codes](errorcode-canvas.md) + - [Custom Node Error Codes](errorcode-node.md) + - [UIExtension Error Codes](errorcode-uiextension.md) + - [UI Appearance Error Codes](errorcode-uiappearance.md) + - [NodeAdapter Error Codes](errorcode-nodeadapter.md) + - Graphics - [Display Error Codes](errorcode-display.md) - [Window Error Codes](errorcode-window.md) - \ No newline at end of file + - UI Compilation + - [Compilation Error Codes](_ark_ui_compile.md_) diff --git a/en/application-dev/reference/apis-arkui/arkui-ts/ts-container-grid.md b/en/application-dev/reference/apis-arkui/arkui-ts/ts-container-grid.md index b0fc7f7221beb42b7921cf19efff8e52eaefc9f4..97aed91418b2ae1bdd1a71e0659f10194c962605 100644 --- a/en/application-dev/reference/apis-arkui/arkui-ts/ts-container-grid.md +++ b/en/application-dev/reference/apis-arkui/arkui-ts/ts-container-grid.md @@ -375,7 +375,7 @@ When **layoutDirection** is **Column** or **ColumnReverse**, the value indicates multiSelectable(value: boolean) -Whether to enable multiselect. When multiselect is enabled, you can use the **selected** attribute and **onSelect** event to obtain the selected status of grid items; you can also set the [style](./ts-universal-attributes-polymorphic-style.md) for the selected state (by default, no style is set for the selected state). +Whether to enable multi-select. When multi-select is enabled, you can use the **selected** attribute and **onSelect** event to obtain the selected status of grid items; you can also set the [style](./ts-universal-attributes-polymorphic-style.md) for the selected state (by default, no style is set for the selected state). **Atomic service API**: This API can be used in atomic services since API version 11. @@ -385,7 +385,7 @@ Whether to enable multiselect. When multiselect is enabled, you can use the **se | Name| Type | Mandatory| Description | | ------ | ------- | ---- | ------------------------------------------------------------ | -| value | boolean | Yes | Whether to enable multiselect.
Default value: **false**
**false**: Multiselect is disabled. **true**: Multiselect is disabled.| +| value | boolean | Yes | Whether to enable multi-select.
Default value: **false**
**false**: Multi-select is disabled. **true**: Multi-select is disabled.| ### supportAnimation8+ diff --git a/en/application-dev/reference/apis-arkui/arkui-ts/ts-container-isolated-component-sys.md b/en/application-dev/reference/apis-arkui/arkui-ts/ts-container-isolated-component-sys.md index 76d3c06524947ffad57b5ef61ee270804e1ce08a..200676b02712c5de05dadc075e0aa2408c144f43 100644 --- a/en/application-dev/reference/apis-arkui/arkui-ts/ts-container-isolated-component-sys.md +++ b/en/application-dev/reference/apis-arkui/arkui-ts/ts-container-isolated-component-sys.md @@ -1,6 +1,6 @@ # IsolatedComponent (System API) -**IsolatedComponent** is designed to support the embedding and display of UIs provided by independent .abc files within the current page, with the displayed content running in a restricted worker thread. +**IsolatedComponent** is designed to support the embedding and display of UIs provided by independent .abc files within the current page, with the displayed content running in a restricted Worker thread. The **FolderStack** component is usually used in modular development scenarios where .abc file hot update is required. @@ -16,25 +16,25 @@ The **FolderStack** component is usually used in modular development scenarios w 1. This component does not support preview. -2. .abc files must pass the [VerifyAbc](../../apis-ability-kit/js-apis-bundleManager-sys.md#bundlemanagerverifyabc11) verification to be used in this component. +2. The .abc file must pass the [VerifyAbc](../../apis-ability-kit/js-apis-bundleManager-sys.md#bundlemanagerverifyabc11) verification before use. -3. Construction parameter updates are not supported; only the initial input is effective. +3. Constructor parameter updates are not supported; only the initial input is effective. 4. Nesting of **IsolatedComponent** components is not supported. **Experience Constraints** -1. When an **IsolatedComponent** component is created, there is a certain amount of time required for the restricted worker thread to load and render the .abc file layout. During this period, the background color of the **IsolatedComponent** is displayed. +1. When an **IsolatedComponent** component is created, there is a certain amount of time required for the restricted Worker thread to load and render the .abc file layout. During this period, the background color of the **IsolatedComponent** is displayed. -2. The main thread and the restricted worker thread handle layout rendering asynchronously, which can lead to desynchronization in page changes caused by layout alterations or rotations. +2. The main thread and the restricted Worker thread handle layout rendering asynchronously, which can lead to desynchronization in page changes caused by layout alterations or rotations. -3. Event transmission between the main thread and the restricted worker thread is managed asynchronously, and there is no support for event bubbling between threads. As a result, UI interactions between threads may encounter event conflicts. +3. Event passing between the main thread and the restricted Worker thread is managed asynchronously, and there is no support for event bubbling between threads. As a result, UI interactions between threads may encounter event conflicts. **Security Constraints** 1. Displaying an independent .abc file through the **IsolatedComponent** component in the host process means that the .abc file content is fully accessible to the host, granting the host the control over the file content. For security-sensitive situations where such open access could be a risk, the use of this feature is disabled. -2. Running independent .abc files in a restricted worker thread offers a level of security, as the .abc file content is isolated and does not interfere with the main thread. +2. Running independent .abc files in a restricted Worker thread offers a level of security, as the .abc file content is isolated and does not interfere with the main thread. ## Child Components @@ -44,7 +44,11 @@ Not supported IsolatedComponent(options: IsolatedOptions) -Creates an **IsolatedComponent** component to display the .abc file executed in a restricted worker thread. +Creates an **IsolatedComponent** component to display the .abc file executed in a restricted Worker thread. + +**System API**: This is a system API. + +**System capability**: SystemCapability.ArkUI.ArkUI.Full **Parameters** @@ -60,7 +64,7 @@ Describes the optional construction parameters during **IsolatedComponent** cons | Name | Type | Mandatory| Description | | ---- | ---------------------------------------- | ---- | --------------- | | want | [Want](../../apis-ability-kit/js-apis-app-ability-want.md) | Yes | .abc file information to load.| -| worker | [RestrictedWorker](../../apis-arkts/js-apis-worker-sys.md#restrictedworker11) | Yes | Restricted worker thread where the .abc file is running.| +| worker | [RestrictedWorker](../../apis-arkts/js-apis-worker-sys.md#restrictedworker11) | Yes | Restricted Worker thread where the .abc file is running.| ## Attributes Only the [width](ts-universal-attributes-size.md#width), [height](ts-universal-attributes-size.md#height), and [backgroundColor](ts-universal-attributes-background.md#backgroundcolor) universal attributes are supported. @@ -69,7 +73,7 @@ Only the [width](ts-universal-attributes-size.md#width), [height](ts-universal-a The [universal events](ts-component-general-events.md) are not supported. -Events are asynchronously passed to the restricted worker thread after coordinate conversion. +Events are asynchronously passed to the restricted Worker thread after coordinate conversion. The following events are supported: @@ -79,11 +83,15 @@ onError(callback:ErrorCallback) Invoked when an error occurs during the running of the **IsolatedComponent**. You can obtain the error information based on the **code**, **name**, and **message** parameters in the callback and rectify the exception accordingly. +**System API**: This is a system API. + +**System capability**: SystemCapability.ArkUI.ArkUI.Full + **Parameters** -| Name | Type | Description | -| ---------------------------- | ------ | ------------------------------------------------------------ | -| callback | [ErrorCallback](../../apis-basic-services-kit/js-apis-base.md#errorcallback) | Error information. | +| Name | Type | Mandatory| Description | +| --------------------- | ---------------------------------------------------------- | ---- | ------------------ | +| callback | [ErrorCallback](../../apis-basic-services-kit/js-apis-base.md#errorcallback) | Yes | Error information.| ## Example: Loading an IsolatedComponent @@ -107,7 +115,7 @@ This example demonstrates the basic usage of the **IsolatedComponent** component - Home page (**ets/pages/Index.ets**) loaded by the entry ability (**EntryAbility**): ```ts import { worker } from '@kit.ArkTS'; - import { bundleManager } from '@kit.AbilityKit'; + import { bundleManager, common } from '@kit.AbilityKit'; import { BusinessError } from '@kit.BasicServicesKit'; // Verify the .abc file and copy it to the specified sandbox path. @@ -133,6 +141,7 @@ This example demonstrates the basic usage of the **IsolatedComponent** component @State resourcePath: string = ""; @State abcPath: string = ""; @State entryPoint: string = ""; + @State context: Context = this.getUIContext().getHostContext() as common.UIAbilityContext; // .abc file name private fileName: string = "modules"; // Bundle name of the application to which the .abc file belongs @@ -145,7 +154,7 @@ This example demonstrates the basic usage of the **IsolatedComponent** component Column() { // 1. Verify the .abc file. Button("verifyAbc").onClick(() => { - let abcFilePath = `${getContext(this).filesDir}/${this.fileName}.abc`; + let abcFilePath = `${this.context.filesDir}/${this.fileName}.abc`; console.log("abcFilePath: " + abcFilePath); VerifyAbc([abcFilePath], false); }).height(100).width(100) @@ -154,9 +163,9 @@ This example demonstrates the basic usage of the **IsolatedComponent** component Button("showIsolatedComponent").onClick(() => { if (!this.isShow) { // Resource path - this.resourcePath = `${getContext(this).filesDir}/${this.fileName}.hap`; + this.resourcePath = `${this.context.filesDir}/${this.fileName}.hap`; // Sandbox path after the .abc file is verified - this.abcPath = `/abcs${getContext(this).filesDir}/${this.fileName}`; + this.abcPath = `/abcs${this.context.filesDir}/${this.fileName}`; // Entry to the page to be displayed this.entryPoint = `${this.bundleName}/entry/ets/pages/extension`; this.isShow = true; diff --git a/en/application-dev/reference/apis-arkui/arkui-ts/ts-container-list.md b/en/application-dev/reference/apis-arkui/arkui-ts/ts-container-list.md index 90f7ca50bb57d6b192681284b80440208462ff79..5a3d046316c97ea9ec3ead9a40ac6c2b0f8c0e58 100644 --- a/en/application-dev/reference/apis-arkui/arkui-ts/ts-container-list.md +++ b/en/application-dev/reference/apis-arkui/arkui-ts/ts-container-list.md @@ -246,7 +246,7 @@ For chained animations to work properly, the following conditions must be met: multiSelectable(value: boolean) -Sets whether to enable multiselect. +Sets whether to enable multi-select. **Widget capability**: This API can be used in ArkTS widgets since API version 9. @@ -258,7 +258,7 @@ Sets whether to enable multiselect. | Name| Type | Mandatory| Description | | ------ | ------- | ---- | ------------------------------------------------------------ | -| value | boolean | Yes | Whether to enable multiselect.
**false** (default): Multiselect is disabled.
**true**: Multiselect is enabled. | +| value | boolean | Yes | Whether to enable multi-select.
**false** (default): Multi-select is disabled.
**true**: Multi-select is enabled. | ### lanes9+ diff --git a/en/application-dev/reference/apis-arkui/arkui-ts/ts-container-listitem.md b/en/application-dev/reference/apis-arkui/arkui-ts/ts-container-listitem.md index 4d2e3bd4f7c65169f2ff02d56caf3106622fde82..3b7c068692b96208228ddd65e3d53a2de5c0e6b7 100644 --- a/en/application-dev/reference/apis-arkui/arkui-ts/ts-container-listitem.md +++ b/en/application-dev/reference/apis-arkui/arkui-ts/ts-container-listitem.md @@ -237,7 +237,7 @@ Describes the swipe action item.
For a list in vertical layout, it refers to onSelect(event: (isSelected: boolean) => void) -Triggered when the selected state of the list item for multiselect changes. +Triggered when the selected state of the list item for multi-select changes. **Widget capability**: This API can be used in ArkTS widgets since API version 9. diff --git a/en/application-dev/reference/apis-arkui/arkui-ts/ts-universal-attributes-accessibility.md b/en/application-dev/reference/apis-arkui/arkui-ts/ts-universal-attributes-accessibility.md index 3d92b26e81631507917ff74db6623f1818116dbd..7db456606a5133b83517505f471a109ee9f0ffde 100644 --- a/en/application-dev/reference/apis-arkui/arkui-ts/ts-universal-attributes-accessibility.md +++ b/en/application-dev/reference/apis-arkui/arkui-ts/ts-universal-attributes-accessibility.md @@ -170,7 +170,7 @@ Sets an accessibility virtual child node. For custom drawing components, a **Cus accessibilityChecked(isCheck: boolean) -Sets the checked state of the accessibility component. This property is used in multiselect scenarios. +Sets the checked state of the accessibility component. This property is used in multi-select scenarios. **Widget capability**: This API can be used in ArkTS widgets since API version 13. diff --git a/en/application-dev/reference/apis-arkui/arkui-ts/ts-universal-attributes-drag-drop.md b/en/application-dev/reference/apis-arkui/arkui-ts/ts-universal-attributes-drag-drop.md index 0c4b70fd7c6801c3346b124afe42ce9f7b5777af..eaa3b9fee133acccadcc2c075b4f23b9378fecfe 100644 --- a/en/application-dev/reference/apis-arkui/arkui-ts/ts-universal-attributes-drag-drop.md +++ b/en/application-dev/reference/apis-arkui/arkui-ts/ts-universal-attributes-drag-drop.md @@ -146,7 +146,7 @@ Enumerates the transition effects for switching between the long-press preview ( | Name| Type| Mandatory| Description| | -------- | -------- | -------- | -------- | -| isMultiSelectionEnabled | boolean | No| Whether to enable multiselect for the drag preview.
**true**: Enable multiselect for the drag preview.
**false**: Disable multiselect for the drag preview.
This parameter takes effect only for the [grid items](ts-container-griditem.md) and [list items](ts-container-listitem.md) in the [Grid](ts-container-grid.md) and [List](ts-container-list.md) containers.
When multiselect is enabled for an item, the child components of the item cannot be dragged. The precendence levels of drag previews for multiselect, from high to low, are as follows: preview specified through a string value in [dragPreview](#dragpreview11), preview specified through **PixelMap** in **dragPreview**, and component snapshot. The Builder format in **dragPreview** is not supported.
The context menu bound to the component through [bindContextMenu](ts-universal-attributes-menu.md#bindcontextmenu12) cannot contain the **isShown** parameter.
Default value: **false**
| +| isMultiSelectionEnabled | boolean | No| Whether to enable multi-select for the drag preview.
**true**: Enable multi-select for the drag preview.
**false**: Disable multi-select for the drag preview.
This parameter takes effect only for the [grid items](ts-container-griditem.md) and [list items](ts-container-listitem.md) in the [Grid](ts-container-grid.md) and [List](ts-container-list.md) containers.
When multi-select is enabled for an item, the child components of the item cannot be dragged. The precendence levels of drag previews for multi-select, from high to low, are as follows: preview specified through a string value in [dragPreview](#dragpreview11), preview specified through **PixelMap** in **dragPreview**, and component snapshot. The Builder format in **dragPreview** is not supported.
The context menu bound to the component through [bindContextMenu](ts-universal-attributes-menu.md#bindcontextmenu12) cannot contain the **isShown** parameter.
Default value: **false**
| | defaultAnimationBeforeLifting | boolean | No| Whether to enable the default pressed state animation (compressing in size) of the component before a lift animation starts.
**true**: Enable the default pressed state animation.
**false**: Disable the default pressed state animation.
Default value: **false**
| | isLiftingDisabled15+ | boolean | No| Whether to disable the lifting effect during dragging.
**true**: Disable the lifting effect during dragging.
**false**: Enable the lifting effect during dragging.
With the value **true**, only the custom menu preview (set using [bindContextMenu](ts-universal-attributes-menu.md#bindcontextmenu8)), also known as the long-press preview, is displayed if both the long-press preview and drag preview are configured.
Default value: **false**| | enableEdgeAutoScroll18+ | boolean | No| Whether to trigger automatic scrolling for dragging to the edge of a scrollable component.
**true**: Trigger automatic scrolling.
**false**: Do not trigger automatic scrolling.
Default value: **true**| @@ -375,9 +375,9 @@ struct dragPreviewOptionsDemo{ ![dragPreviewMode.gif](figures/dragPreviewMode.gif) -### Example 4: Enabling Multiselect for Dragging +### Example 4: Enabling Multi-Select for Dragging -This example demonstrates how to enable multiselect for dragging in a **Grid** component by configuring **isMultiSelectionEnabled**. +This example demonstrates how to enable multi-select for dragging in a **Grid** component by configuring **isMultiSelectionEnabled**. ```ts @Entry diff --git a/en/application-dev/ui/arkts-common-events-drag-event.md b/en/application-dev/ui/arkts-common-events-drag-event.md index de643d52668083cda8fdca0dc3cbe78bf6c1763a..5a945f0450d1977b0c116c07b99fdc34f8306902 100644 --- a/en/application-dev/ui/arkts-common-events-drag-event.md +++ b/en/application-dev/ui/arkts-common-events-drag-event.md @@ -604,7 +604,7 @@ struct GridEts { this.numberBadge--; } }) - // Enable multiselect and set the number badge. + // Enable multi-select and set the number badge. .dragPreviewOptions({numberBadge: this.numberBadge},{isMultiSelectionEnabled:true,defaultAnimationBeforeLifting:true}) .onDragStart(()=>{ }) diff --git a/en/application-dev/ui/arkts-dialog-controller.md b/en/application-dev/ui/arkts-dialog-controller.md new file mode 100644 index 0000000000000000000000000000000000000000..f86ac3825d19026702acf09d834cd69760e7dbc0 --- /dev/null +++ b/en/application-dev/ui/arkts-dialog-controller.md @@ -0,0 +1,367 @@ +# Dialog Box Controller +The dialog controller in ArkUI provides the capability to operate on a bound dialog box. Currently, it supports the close functionality. You can pass the controller into the dialog box content area to perform operations. + +Since API version 18, you can set the [controller](../reference/apis-arkui/js-apis-promptAction.md#dialogcontroller18) parameter to bind the controller, and operate the dialog box through the controller. + +## Constraints + +Currently, the [openCustomDialogWithController](../reference/apis-arkui/js-apis-arkui-UIContext.md#opencustomdialogwithcontroller18) and [presentCustomDialog](../reference/apis-arkui/js-apis-arkui-UIContext.md#presentcustomdialog18) APIs support binding dialog controllers through the **controller** parameter. The [getDialogController](../reference/apis-arkui/arkui-ts/ts-custom-component-api.md#getdialogcontroller18) API can obtain the dialog controller for the custom component where the dialog box is located. + +> **NOTE** +> +> A dialog controller can be bound to only one dialog box, and operations only affect that dialog box. +> When [getDialogController](../reference/apis-arkui/arkui-ts/ts-custom-component-api.md#getdialogcontroller18) is used to obtain the dialog controller, if the current custom component is not displayed in a dialog box, the result will be **undefined**. + +## Creating a Dialog Box Controller with ComponentContent as Custom Content + +> **NOTE** +> +> For details about the variables, see [Example](#example). + +1. Initialize a parameter class for the custom dialog box content area, which includes the dialog controller. + + ```ts + class Params { + public text: string = '' + public dialogController: promptAction.CommonController = new promptAction.DialogController() + constructor(text: string, dialogController: promptAction.CommonController) { + this.text = text + this.dialogController = dialogController + } + } + ``` + +2. Initialize a custom dialog box content area that includes a button, which closes the dialog box using the dialog controller provided by the custom component. + + ```ts + @Component + struct MyComponent { + build() { + Column({ space: 5 }) { + Button('Close Dialog Box: Using Built-in DialogController') + .onClick(() => { + let dialogController: promptAction.DialogController = this.getDialogController() + if (dialogController !== undefined) { + dialogController.close() + } + }) + } + } + } + ``` + +3. Initialize another custom dialog box content area that includes a **Text** component and a button, which closes the dialog box using the externally passed dialog controller. This content area also includes the previous custom dialog box content area. + + ```ts + @Builder + function buildText(params: Params) { + Column({ space: 5 }) { + Text(params.text) + .fontSize(30) + if (params.dialogController !== undefined) { + Button('Close Dialog Box: Using Externally Passed DialogController') + .onClick(() => { + params.dialogController.close() + }) + } + MyComponent() + } + .width(300) + .height(200) + .backgroundColor('#FFF0F0F0') + } + ``` + +4. Initialize a dialog controller and create a dialog box content entity object by setting the **controller** parameter. Finally, obtain a [PromptAction](../reference/apis-arkui/js-apis-arkui-UIContext.md#promptaction) object through the [getPromptAction](../reference/apis-arkui/js-apis-arkui-UIContext.md#getpromptaction) API of [UIContext](../reference/apis-arkui/js-apis-arkui-UIContext.md#uicontext), and call the [openCustomDialogWithController](../reference/apis-arkui/js-apis-arkui-UIContext.md#opencustomdialogwithcontroller18) API with the initialized content entity object and **controller** parameter to create the dialog box. + + ```ts + let dialogController: promptAction.CommonController = new promptAction.DialogController() + let contentNode: ComponentContent = + new ComponentContent(this.getUIContext(), wrapBuilder(buildText), new Params(this.message, dialogController)) + this.getUIContext().getPromptAction().openCustomDialogWithController( + contentNode, dialogController, this.baseDialogOptions).catch((err: BusinessError) => { + console.error('openCustomDialogWithController error: ' + err.code + ' ' + err.message) + }) + ``` + +## Creating a Dialog Box Controller with CustomBuilder as Custom Content + +> **NOTE** +> +> For details about the variables, see [Example](#example). + +1. Initialize a custom dialog box content area that includes a **Text** component and a button, which closes the dialog box using the externally passed dialog controller. + + ```ts + @Builder customDialogComponent(dialogController: promptAction.DialogController) { + Column({ space: 5 }) { + Text(this.message) + .fontSize(30) + if (dialogController !== undefined) { + Button('Close Dialog Box: Using Externally Passed DialogController') + .onClick(() => { + dialogController.close() + }) + } + } + .height(200) + .padding(5) + .justifyContent(FlexAlign.SpaceBetween) + .backgroundColor('#FFF0F0F0') + } + ``` + +2. Initialize a dialog box controller and obtain a [PromptAction](../reference/apis-arkui/js-apis-arkui-UIContext.md#promptaction) object through the [getPromptAction](../reference/apis-arkui/js-apis-arkui-UIContext.md#getpromptaction) API of [UIContext](../reference/apis-arkui/js-apis-arkui-UIContext.md#uicontext), and call the [presentCustomDialog](../reference/apis-arkui/js-apis-arkui-UIContext.md#presentcustomdialog18) API with the initialized content entity object and **controller** parameter to create the dialog box. + + ```ts + let dialogController: promptAction.CommonController = new promptAction.DialogController() + this.getUIContext().getPromptAction().presentCustomDialog(() => { + this.customDialogComponent(dialogController) + }, dialogController, this.dialogOptions).catch((err: BusinessError) => { + console.error('presentCustomDialog error: ' + err.code + ' ' + err.message) + }) + ``` + +## Creating a Dialog Box Controller with CustomBuilderWithId as Custom Content + +> **NOTE** +> +> For details about the variables, see [Example](#example). + +1. Initialize a dialog box content area that includes a **Text** component, a button that closes the dialog box using the externally passed dialog ID, and a button that closes the dialog box using the externally passed dialog controller. + + ```ts + @Builder customDialogComponentWithId(dialogId: number, dialogController: promptAction.DialogController) { + Column({ space: 5 }) { + Text(this.message) + .fontSize(30) + if (dialogId !== undefined) { + Button('Close Dialog Box: Using DialogID') + .onClick(() => { + this.getUIContext().getPromptAction().closeCustomDialog(dialogId) + }) + } + if (dialogController !== undefined) { + Button('Close Dialog Box: Using Externally Passed DialogController') + .onClick(() => { + dialogController.close() + }) + } + } + } + ``` + +2. Initialize a dialog box controller and obtain a [PromptAction](../reference/apis-arkui/js-apis-arkui-UIContext.md#promptaction) object through the [getPromptAction](../reference/apis-arkui/js-apis-arkui-UIContext.md#getpromptaction) API of [UIContext](../reference/apis-arkui/js-apis-arkui-UIContext.md#uicontext), and call the [presentCustomDialog](../reference/apis-arkui/js-apis-arkui-UIContext.md#presentcustomdialog18) API with the initialized content entity object and **controller** parameter to create the dialog box. + + ```ts + let dialogController: promptAction.CommonController = new promptAction.DialogController() + this.getUIContext().getPromptAction().presentCustomDialog((dialogId: number) => { + this.customDialogComponentWithId(dialogId, dialogController) + }, dialogController, this.dialogOptions).catch((err: BusinessError) => { + console.error('presentCustomDialog error: ' + err.code + ' ' + err.message) + }) + ``` + +## Directly Obtaining the Dialog Box Controller in the CustomDialogController Content Area + +> **NOTE** +> +> For details about the variables, see [Example](#example). + +1. Initialize a custom dialog box content area that includes a **Text** component and a button, which closes the dialog box using the dialog controller. + +```ts +@CustomDialog +@Component +struct CustomDialogExample { + controller?: CustomDialogController + + build() { + Column({ space: 5 }) { + Text('I am content') + .fontSize(30) + Button('Close Dialog Box: Using Built-in DialogController') + .onClick(() => { + let dialogController: PromptActionDialogController = this.getDialogController() + if (dialogController !== undefined) { + dialogController.close() + } + }) + } + .height(200) + .backgroundColor('#FFF0F0F0') + } +} +``` + +2. Initialize a custom dialog box constructor and associate it with the custom dialog box content area. + + ```ts + let customDialogController: CustomDialogController = new CustomDialogController({ + builder: CustomDialogExample(), + }) + customDialogController.open() + ``` + +## Example +The example demonstrates how to use both the externally passed dialog controller and the dialog controller provided by the custom component to close the dialog box within the custom dialog box content area. + ```ts + import { ComponentContent, promptAction } from '@kit.ArkUI' + import { BusinessError } from '@kit.BasicServicesKit' + + class Params { + public text: string = '' + public dialogController: promptAction.CommonController = new promptAction.DialogController() + constructor(text: string, dialogController: promptAction.CommonController) { + this.text = text + this.dialogController = dialogController + } + } + + @Component + struct MyComponent { + build() { + Column({ space: 5 }) { + Button('Close Dialog Box: Using Built-in DialogController') + .onClick(() => { + let dialogController: promptAction.DialogController = this.getDialogController() + if (dialogController !== undefined) { + dialogController.close() + } + }) + } + } + } + + @Builder + function buildText(params: Params) { + Column({ space: 5 }) { + Text(params.text) + .fontSize(30) + if (params.dialogController !== undefined) { + Button('Close Dialog Box: Using Externally Passed DialogController') + .onClick(() => { + params.dialogController.close() + }) + } + MyComponent() + } + .width(300) + .height(200) + .backgroundColor('#FFF0F0F0') + } + + @CustomDialog + @Component + struct CustomDialogExample { + controller?: CustomDialogController + + build() { + Column({ space: 5 }) { + Text('I am content') + .fontSize(30) + Button('Close Dialog Box: Using Built-in DialogController') + .onClick(() => { + let dialogController: PromptActionDialogController = this.getDialogController() + if (dialogController !== undefined) { + dialogController.close() + } + }) + } + .height(200) + .backgroundColor('#FFF0F0F0') + } + } + + @Entry + @Component + export struct Index { + private message = 'Dialog box' + @Builder customDialogComponent(dialogController: promptAction.DialogController) { + Column({ space: 5 }) { + Text(this.message) + .fontSize(30) + if (dialogController !== undefined) { + Button('Close Dialog Box: Using Externally Passed DialogController') + .onClick(() => { + dialogController.close() + }) + } + } + .height(200) + .padding(5) + .justifyContent(FlexAlign.SpaceBetween) + .backgroundColor('#FFF0F0F0') + } + + @Builder customDialogComponentWithId(dialogId: number, dialogController: promptAction.DialogController) { + Column({ space: 5 }) { + Text(this.message) + .fontSize(30) + if (dialogId !== undefined) { + Button('Close Dialog Box: Using DialogID') + .onClick(() => { + this.getUIContext().getPromptAction().closeCustomDialog(dialogId) + }) + } + if (dialogController !== undefined) { + Button('Close Dialog Box: Using Externally Passed DialogController') + .onClick(() => { + dialogController.close() + }) + } + } + } + + private baseDialogOptions: promptAction.BaseDialogOptions = { + isModal: false, + autoCancel: false + } + + private dialogOptions: promptAction.DialogOptions = { + isModal: false, + autoCancel: false + } + + build() { + Column({ space: 5 }) { + Button('openCustomDialogWithController') + .onClick(() => { + let dialogController: promptAction.CommonController = new promptAction.DialogController() + let contentNode: ComponentContent = + new ComponentContent(this.getUIContext(), wrapBuilder(buildText), new Params(this.message, dialogController)) + this.getUIContext().getPromptAction().openCustomDialogWithController( + contentNode, dialogController, this.baseDialogOptions).catch((err: BusinessError) => { + console.error('openCustomDialogWithController error: ' + err.code + ' ' + err.message) + }) + }) + Button('presentCustomDialog+CustomBuilder') + .onClick(() => { + let dialogController: promptAction.CommonController = new promptAction.DialogController() + this.getUIContext().getPromptAction().presentCustomDialog(() => { + this.customDialogComponent(dialogController) + }, dialogController, this.dialogOptions).catch((err: BusinessError) => { + console.error('presentCustomDialog error: ' + err.code + ' ' + err.message) + }) + }) + Button('presentCustomDialog+CustomBuilderWithId') + .onClick(() => { + let dialogController: promptAction.CommonController = new promptAction.DialogController() + this.getUIContext().getPromptAction().presentCustomDialog((dialogId: number) => { + this.customDialogComponentWithId(dialogId, dialogController) + }, dialogController, this.dialogOptions).catch((err: BusinessError) => { + console.error('presentCustomDialog error: ' + err.code + ' ' + err.message) + }) + }) + Button('CustomDialogController') + .onClick(() => { + let customDialogController: CustomDialogController = new CustomDialogController({ + builder: CustomDialogExample(), + }) + customDialogController.open() + }) + }.width('100%') + } + } + ``` +![dialog-controller-demo1](figures/dialog-controller-demo1.gif) diff --git a/en/application-dev/ui/arkts-embedded-components.md b/en/application-dev/ui/arkts-embedded-components.md new file mode 100644 index 0000000000000000000000000000000000000000..42d145d4a168b17ad635ebc56a2b610281b0f878 --- /dev/null +++ b/en/application-dev/ui/arkts-embedded-components.md @@ -0,0 +1,256 @@ +# In-Application Embedded Component (EmbeddedComponent) + +The **EmbeddedComponent** allows the current page to embed UI content provided by other EmbeddedUIExtensionAbilities within the same application. These UIs run in independent processes, offering enhanced security and stability. + +The **EmbeddedComponent** is primarily used for cross-module, cross-process embedded UI integration. Its core objective is to improve application flexibility and user experience through modular design. + +Be aware of the component's usage constraints and lifecycle management to maximize its benefits in application architecture. + +## Basic Concepts + +- [EmbeddedComponent](../reference/apis-arkui/arkui-ts/ts-container-embedded-component.md) + + The **EmbeddedComponent** enables embedding UI content from another EmbeddedUIExtensionAbility within the same application. It supports modular development scenarios requiring process isolation, allowing flexible UI design by integrating specific functionalities or interfaces into another page. + +- [EmbeddedUIExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-embeddedUIExtensionAbility.md) + + Defined and used in the provider application, the EmbeddedUIExtensionAbility enables cross-process UI embedding. It can only be launched by a UIAbility within the same application and requires multi-process permissions. + +## Constraints + +- Device Requirements + + The **EmbeddedComponent** is supported only on devices configured with multi-process permissions. + +- Applicable Scope + + The **EmbeddedComponent** can be used only in the UIAbility, and the EmbeddedUIExtensionAbility to start must belong to the same application as the UIAbility. + +- Attribute Restrictions + + The **EmbeddedComponent** supports [universal attributes](../reference/apis-arkui/arkui-ts/ts-component-general-attributes.md), with default and minimum width and height values set to 10 vp. + + The following width- and height-related attributes are not supported: + **constraintSize**, **aspectRatio**, **layoutWeight**, **flexBasis**, **flexGrow**, and **flexShrink**. + +- Event handling + + Event information related to screen coordinates is converted based on the position, width, and height of the **EmbeddedComponent**, before being passed to the EmbeddedUIExtensionAbility for processing. + + The **EmbeddedComponent** does not support universal events, including the [click event](../reference/apis-arkui/arkui-ts/ts-universal-events-click.md). It only supports the [onTerminated](../reference/apis-arkui/arkui-ts/ts-container-embedded-component.md#onterminated) and [onError](../reference/apis-arkui/arkui-ts/ts-container-embedded-component.md#onerror) events. + +## Scenario Example + +This example demonstrates the basic usage of the **EmbeddedComponent** and EmbeddedUIExtensionAbility. + +**Host Page** + +The host page is the parent page of the **EmbeddedComponent**, embedding and displaying the UI from the EmbeddedUIExtensionAbility. Below is a complete implementation: + +```ts +import { Want } from '@kit.AbilityKit'; + +@Entry +@Component +struct Index { + @State message: string = 'Message: ' + private want: Want = { + bundleName: "com.example.embeddeddemo", + abilityName: "ExampleEmbeddedAbility", + } + + build() { + Row() { + Column() { + Text(this.message).fontSize(30) + EmbeddedComponent(this.want, EmbeddedType.EMBEDDED_UI_EXTENSION) + .width('100%') + .height('90%') + .onTerminated((info) => { + // Triggered when the terminateSelfWithResult button is clicked on the extension page. + this.message = 'Termination: code = ' + info.code + ', want = ' + JSON.stringify(info.want); + }) + .onError((error) => { + // Triggered on failure or exception. + this.message = 'Error: code = ' + error.code; + }) + } + .width('100%') + } + .height('100%') + } +} +``` + +In an ArkTS project, the implementation code for EmbeddedUIExtensionAbility is typically located in the **ets/extensionAbility** directory of the project. For example, the **ExampleEmbeddedAbility.ets** file is located in the **./ets/extensionAbility/** directory. + +Key considerations for implementing the host page: + +- Multi-process model check + + Check whether the device has multi-process mode enabled during application startup. Provide clear error messages or guidance if it is disabled. + +- Exception handling + + Use the [onError](../reference/apis-arkui/arkui-ts/ts-container-embedded-component.md#onerror) event to handle errors during embedded ability loading or execution. + +- Lifecycle management + + Manage the lifecycle of the **EmbeddedComponent** to ensure proper resource cleanup. + +- Style configuration + + Properly configure the size and position of the **EmbeddedComponent** to display embedded UIs as expected. + +**Provider Application Lifecycle Implementation** + +The provider application implements embedded UI extension abilities. Below is an example lifecycle implementation: + +```ts +import { EmbeddedUIExtensionAbility, UIExtensionContentSession, Want } from '@kit.AbilityKit'; + +const TAG: string = '[ExampleEmbeddedAbility]' + +export default class ExampleEmbeddedAbility extends EmbeddedUIExtensionAbility { + onCreate() { + console.log(TAG, `onCreate`); + } + + onForeground() { + console.log(TAG, `onForeground`); + } + + onBackground() { + console.log(TAG, `onBackground`); + } + + onDestroy() { + console.log(TAG, `onDestroy`); + } + + onSessionCreate(want: Want, session: UIExtensionContentSession) { + console.log(TAG, `onSessionCreate, want: ${JSON.stringify(want)}`); + let param: Record = { + 'session': session + }; + let storage: LocalStorage = new LocalStorage(param); + // Load the pages/extension.ets content. + session.loadContent('pages/extension', storage); + } + + onSessionDestroy(session: UIExtensionContentSession) { + console.log(TAG, `onSessionDestroy`); + } +} +``` + +Key implementation details: + +- Lifecycle stages + + **onCreate** -> **onForeground**: from initialization to the visible state. + + **onBackground** -> **onForeground**: state transition during foreground-background switching. + + **onDestroy**: resource cleanup when the component is actively destroyed by the host. + +- Session management + + **onSessionCreate**: creates an independent storage context and loads the UI. + + **onSessionDestroy**: handles cleanup when the session ends. + +- Context passing + + Use LocalStorage to pass the **UIExtensionContentSession** across components. + + Bind ArkTS pages to extension ability contexts through **loadContent**. + +**Entry Page** + +The following is an implementation of the entry component of the provider application, which demonstrates how to use **UIExtensionContentSession** and how to exit the embedded page and return the result through a button click event. This code file needs to be declared in the **main_pages.json** configuration file. + +```ts +import { UIExtensionContentSession } from '@kit.AbilityKit'; + +let storage = new LocalStorage(); + +@Entry(storage) +@Component +struct Extension { + @State message: string = 'EmbeddedUIExtensionAbility Index'; + private session: UIExtensionContentSession | undefined = storage.get('session'); + + build() { + Column() { + Text(this.message) + .fontSize(20) + .fontWeight(FontWeight.Bold) + Button("terminateSelfWithResult").fontSize(20).onClick(() => { + // Call terminateSelfWithResult to exit when the button is clicked. + this.session?.terminateSelfWithResult({ + resultCode: 1, + want: { + bundleName: "com.example.embeddeddemo", + abilityName: "ExampleEmbeddedAbility", + } + }); + }) + }.width('100%').height('100%') + } +} +``` + +Key considerations for implementing the entry page: + +1. Session management + + Properly obtain and use the **UIExtensionContentSession** instances to ensure communication with the host application. + +2. Result return + + When returning results to the host through **terminateSelfWithResult**, specify: + + - **resultCode**: result code. + + - **want**: recipient of the result. + +3. Page lifecycle + + Manage the lifecycle of the entry page to ensure proper resource cleanup. + +4. Style configuration + + Properly configure page element styles to display the page as expected. + +**Configuration** + + To enable embedded UI extension abilities, configure the application's configuration file. + + Add the ExampleEmbeddedAbility configuration under the **extensionAbilities** tag in the **module.json5** file: + +```json +{ + "name": "ExampleEmbeddedAbility", + "srcEntry": "./ets/extensionAbility/ExampleEmbeddedAbility.ets", + "type": "embeddedUI" +} +``` + +**Expected Results** + +1. An error message appears since multi-process mode is disabled by default. + +![en-us_image_0000001502261185](figures/en-us_image_0000001502261185.jpg) + +2. Use the following hdc command to enable multi-process mode. Then, restart the device: + +```bash +hdc shell param set persist.sys.abilityms.multi_process_model true +``` + +3. The UI is displayed correctly after the application starts. + +![en-us_image_0000001502261065](figures/en-us_image_0000001502261065.jpg) + +4. Clicking the **terminateSelfWithResult** button hides the provider content and displays **onTerminated** information on the host page. diff --git a/en/application-dev/ui/arkts-isolated-components.md b/en/application-dev/ui/arkts-isolated-components.md new file mode 100644 index 0000000000000000000000000000000000000000..b16fc11faad0bbc444e31a6892ba1980902f0e3d --- /dev/null +++ b/en/application-dev/ui/arkts-isolated-components.md @@ -0,0 +1,239 @@ +# Cross-Thread Embedded Component (IsolatedComponent, for System Applications Only) + +The **IsolatedComponent** is a tool for building isolated components, enabling you to create independent and reusable components that can be used across different applications without conflicts. + +Each **IsolatedComponent** exists independently with its own scope and lifecycle, not sharing state or data with other components. This facilitates reuse across applications, reducing repetitive development efforts. + +## Basic Concepts + +[IsolatedComponent](../reference/apis-arkui/arkui-ts/ts-container-isolated-component-sys.md): a component designed to embed and display a UI provided by an independent .abc file within the current page, with the displayed content executed in a restricted Worker thread. + +This component is primarily used in modular development scenarios requiring hot updates for .abc files. + +## Constraints + +1. The .abc file must pass [VerifyAbc](../reference/apis-ability-kit/js-apis-bundleManager-sys.md#bundlemanagerverifyabc11) verification before use. + +2. Constructor parameter updates are not supported; only the initial input is effective. + +3. Nesting of **IsolatedComponent** components is not supported. + +4. The main thread and the restricted Worker thread handle layout rendering asynchronously, which can lead to desynchronization in page changes caused by layout alterations or rotations. + +5. Event passing between the main thread and the restricted Worker thread is managed asynchronously, and there is no support for event bubbling between threads. As a result, UI interactions between threads may encounter event conflicts. + +6. When an independent .abc file is embedded into the host process using the **IsolatedComponent**, its content is fully open to the host, which can operate on the content. Therefore, this feature should be disabled in security-sensitive scenarios. + +7. The independent .abc file runs in a restricted Worker thread, ensuring relative security and not affecting the main thread. + +## Scenario Example + +This example demonstrates the basic usage of the **IsolatedComponent** component. The sample application's **bundleName** is **"com.example.isolateddemo"**, and the component uses the .abc file and an extension page from the same application as the embedded content. + +**Importing the Core Module** + +When using the **IsolatedComponent**, first import the **@kit.AbilityKit** module, which provides the necessary functionality for building isolated components, including key APIs like **bundleManager**. + +As a core component of Ability Kit, **bundleManager** provides the capability to manage application packages, serving as the foundation for building the **IsolatedComponent**. Importing this module enables the use of its APIs to create and manage isolated components, ensuring data and resource isolation between different components and enhancing application security. + +```ts +import { bundleManager } from '@kit.AbilityKit'; +``` + +**Managing Permissions** + +When using the **IsolatedComponent**, properly configure the [requestPermissions](../security/AccessToken/declare-permissions.md) tag, which is crucial for ensuring the secure operation of components in restricted environments. This configuration allows you to specify the permissions required by the component, enabling fine-grained permission management. + +In restricted mode, the **IsolatedComponent** does not have the capability to execute dynamic code by default. By adding the **requestPermissions** tag in the **module.json5** configuration file, you enable the component to be authorized to execute dynamically delivered Ark bytecode under specific conditions. + +```json +"requestPermissions": [ + { + "name": "ohos.permission.RUN_DYN_CODE", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "inuse" + } + } +] +``` + +**Restricted Worker** + +A restricted [Worker](../reference/apis-arkts/js-apis-worker.md) thread runs in an isolated environment. This isolation ensures memory isolation between the restricted Worker thread and other threads or components, preventing mutual interference or security issues. + +In the scenario where the **IsolatedComponent** is used, components often need to dynamically load external HAP resources. The restricted Worker thread ensures security through the following mechanisms: + +- [Sandbox path](../file-management/app-sandbox-directory.md) validation + + **abcPath** points to a secure directory verified by the system, preventing malicious code injection. + +- Communication control + + Only standardized message events are allowed for communication between the main thread and the Worker thread, with direct data sharing prohibited. + +- Exception isolation + + Errors within the Worker thread can be handled controllably through the **onerror** event and do not cause the main application to crash. + +```ts +// OhCardWorker.ets +import { worker, ThreadWorkerGlobalScope, MessageEvents, ErrorEvent } from '@kit.ArkTS'; +const workerPort: ThreadWorkerGlobalScope = worker.workerPort; + +workerPort.onmessage = (e: MessageEvents) => {} +workerPort.onmessageerror = (e: MessageEvents) => {} +workerPort.onerror = (e: ErrorEvent) => {} +``` + +```ts +IsolatedComponent({ + want: { + "parameters": { + // Resource path + "resourcePath": `${getContext(this).filesDir}/${this.fileName}.hap`, + // Verified sandbox path for the .abc file + "abcPath": `/abcs${getContext(this).filesDir}/${this.fileName}`, + // Entry path for the page to be displayed + "entryPoint": `${this.bundleName}/entry/ets/pages/extension`, + } + }, + // Restricted Worker thread + worker: new worker.RestrictedWorker("entry/ets/workers/OhCardWorker.ets") +}) +``` + +The **IsolatedComponent** achieves dynamic component loading and isolated execution through the **want** and **worker** properties, which together form the security boundary. Properly setting these properties is key to ensuring the secure operation of the component. + +The entry page file **ets/pages/extension.ets** running in the restricted Worker thread contains the following reference content: + +```ts +@Entry +@Component +struct Extension { + @State message: string = 'Hello World'; + + build() { + RelativeContainer() { + Text(this.message) + .id('HelloWorld') + .fontSize(50) + .fontWeight(FontWeight.Bold) + .alignRules({ + center: { anchor: '__container__', align: VerticalAlign.Center }, + middle: { anchor: '__container__', align: HorizontalAlign.Center } + }) + } + .height('100%') + .width('100%') + } +} +``` + +**Sample Application Code** + +The following example shows the content of the home page file **ets/pages/Index.ets** loaded by EntryAbility (UIAbility) in the application. + +```ts +import { worker } from '@kit.ArkTS'; +import { bundleManager, common } from '@kit.AbilityKit'; +import { BusinessError } from '@kit.BasicServicesKit'; + +// Verify the .abc file and copy it to the specified sandbox path. +function VerifyAbc(abcPaths: Array, deleteOriginalFiles: boolean) { + try { + bundleManager.verifyAbc(abcPaths, deleteOriginalFiles, (err) => { + if (err) { + console.error("VerifyAbc failed, error message: " + err.message); + } else { + console.info("VerifyAbc successfully."); + } + }); + } catch (err) { + let message = (err as BusinessError).message; + console.error("VerifyAbc failed, error message: " + message); + } +} + +@Entry +@Component +struct Index { + @State isShow: boolean = false; + @State resourcePath: string = ""; + @State abcPath: string = ""; + @State entryPoint: string = ""; + @State context: Context = this.getUIContext().getHostContext() as common.UIAbilityContext; + // .abc file name + private fileName: string = "modules"; + // Bundle name of the application to which the .abc file belongs + private bundleName: string = "com.example.isolateddemo"; + // Restricted Worker thread + private worker ?: worker.RestrictedWorker = new worker.RestrictedWorker("entry/ets/workers/OhCardWorker.ets"); + + build() { + Row() { + Column({ space: 20 }) { + // 1. Verify the .abc file. + Button("verifyAbc").onClick(() => { + let abcFilePath = `${this.context.filesDir}/${this.fileName}.abc`; + console.log("abcFilePath: " + abcFilePath); + VerifyAbc([abcFilePath], false); + }).height(100).width(200) + + // 2. Display the IsolatedComponent. + Button("showIsolatedComponent").onClick(() => { + if (!this.isShow) { + // Resource path + this.resourcePath = `${this.context.filesDir}/${this.fileName}.hap`; + // Verified sandbox path for the .abc file + this.abcPath = `/abcs${this.context.filesDir}/${this.fileName}`; + // Entry path for the page to be displayed + this.entryPoint = `${this.bundleName}/entry/ets/pages/extension`; + this.isShow = true; + } + }).height(100).width(200) + + if (this.isShow) { + IsolatedComponent({ + want: { + "parameters": { + "resourcePath": this.resourcePath, + "abcPath": this.abcPath, + "entryPoint": this.entryPoint + } + }, + worker: this.worker + }) + .width(300) + .height(300) + .onError((err) => { + console.info("onError : " + JSON.stringify(err)); + }) + } + } + .width('100%') + } + .height('100%') + } +} +``` + +**Expected Results** + +1. Build the HAP in DevEco Studio and install it on the device. + +2. Upload the **modules.abc** file generated by the application to the application sandbox path **/data/app/el2/100/base/com.example.isolateddemo/haps/entry/files** using DevEco Studio or the hdc tool. The reference command for the hdc tool is as follows: + +```bash +hdc file send modules.abc /data/app/el2/100/base/com.example.isolateddemo/haps/entry/files/ +``` + +3. Open the application page and click the **verifyAbc** button to verify the .abc file. The log "VerifyAbc successfully" should be output. + +![en-us_image_0000001746521386](figures/en-us_image_0000001746521386.jpg) + +![en-us_image_0000001502381065](figures/en-us_image_0000001502381065.png) + +4. Click the **showIsolatedComponent** button to display the **IsolatedComponent** with the content "Hello World." diff --git a/en/application-dev/ui/arkts-layout-development-create-waterflow.md b/en/application-dev/ui/arkts-layout-development-create-waterflow.md new file mode 100644 index 0000000000000000000000000000000000000000..b021fe6539fd3386ab020c7d5f7a1d7f63fbbb22 --- /dev/null +++ b/en/application-dev/ui/arkts-layout-development-create-waterflow.md @@ -0,0 +1,309 @@ +# Creating a Waterfall Flow (WaterFlow) + +You can use the [WaterFlow](../reference/apis-arkui/arkui-ts/ts-container-waterflow.md) component in ArkUI to create a waterfall flow layout, which is commonly used to display image collections, especially in e-commerce and news applications. +The WaterFlow component supports conditional rendering, loop rendering (rendering of repeated content), and lazy loading to generate child components. + +## Layout and Constraints + +The waterfall flow supports both horizontal and vertical layouts. In a vertical layout, you can set the number of columns using [columnsTemplate](../reference/apis-arkui/arkui-ts/ts-container-waterflow.md#columnstemplate). In a horizontal layout, you can set the number of rows using [rowsTemplate](../reference/apis-arkui/arkui-ts/ts-container-waterflow.md#rowstemplate). + +In the vertical layout, child nodes in the first row are arranged from left to right. From the second row onward, each child node is placed in the column with the smallest total height. If multiple columns have the same total height, they are filled in order from left to right. The following figure shows this arrangement logic. + +![](figures/waterflow.png) + +In the horizontal layout, each child node is placed in the row with the smallest total width. If multiple rows have the same width, they are filled in order from left to right. + +![](figures/waterflow-row.png) + +## Infinite Scrolling + +### Adding Data When Reaching the End + +The waterfall flow layout is often used for infinite scrolling feeds. You can add new data to [LazyForEach](../reference/apis-arkui/arkui-ts/ts-rendering-control-lazyforeach.md) in the [onReachEnd](../reference/apis-arkui/arkui-ts/ts-container-waterflow.md#onreachend) event callback when the **WaterFlow** component reaches the end position, and create a footer that indicates loading new data (using the [LoadingProgress](../reference/apis-arkui/arkui-ts/ts-basic-components-loadingprogress.md) component). + +```ts + @Builder + itemFoot() { + Row() { + LoadingProgress() + .color(Color.Blue).height(50).aspectRatio(1).width('20%') + Text(`Loading`) + .fontSize(20) + .width('30%') + .height(50) + .align(Alignment.Center) + .margin({ top: 2 }) + }.width('100%').justifyContent(FlexAlign.Center) + } + + build() { + Column({ space: 2 }) { + WaterFlow({ footer: this.itemFoot(), layoutMode: WaterFlowLayoutMode.SLIDING_WINDOW }) { + LazyForEach(this.dataSource, (item: number) => { + FlowItem() { + ReusableFlowItem({ item: item }) + } + .width('100%') + .aspectRatio(this.itemHeightArray[item % 100] / this.itemWidthArray[item%100]) + .backgroundColor(this.colors[item % 5]) + }, (item: string) => item) + } + .columnsTemplate('1fr '.repeat(this.columns)) + .backgroundColor(0xFAEEE0) + .width('100%') + .height('100%') + .layoutWeight(1) + // Load data once the component reaches the bottom. + .onReachEnd(() => { + setTimeout(() => { + this.dataSource.addNewItems(); + }, 1000); + }) + } + } + + // Method in WaterFlowDataSource to append count-specified elements to the data + public addNewItems(count: number): void { + let len = this.dataArray.length; + for (let i = 0; i < count; i++) { + this.dataArray.push(this.dataArray.length); + } + this.listeners.forEach(listener => { + listener.onDatasetChange([{ type: DataOperationType.ADD, index: len, count: count }]); + }) + } + +``` + +Always add data to the end of the data array (**dataArray**) instead of modifying the array directly using the **onDataReloaded()** API of **LazyForEach**. + +Since the heights of the child nodes in the **WaterFlow** component are inconsistent, the position of the lower nodes depends on the upper nodes. Therefore, reloading all data triggers full layout recalculation, potentially causing lag. After adding data to the end of the data array, you must use **onDatasetChange([{ type: DataOperationType.ADD, index: len, count: count }])** to notify the **WaterFlow** component of new data without reprocessing existing items. + +![](figures/waterflow-demo1.gif) + +### Pre-loading Data + +Triggering data loading at **onReachEnd()** can cause noticeable pause when the component scrolls to the bottom. + +To enable smooth infinite scrolling, you need to adjust the timing of adding new data. For example, you can preload new data when there are still several items left to be traversed in **LazyForEach**. The following code monitors the scroll position (distance of the last displayed child node from the end of the dataset) in the [onScrollIndex](../reference/apis-arkui/arkui-ts/ts-container-waterflow.md#onscrollindex11) API of **WaterFlow** and pre-loads new data at the right time to achieve smooth infinite scrolling. + +```ts + build() { + Column({ space: 2 }) { + WaterFlow({ layoutMode: WaterFlowLayoutMode.SLIDING_WINDOW }) { + LazyForEach(this.dataSource, (item: number) => { + FlowItem() { + ReusableFlowItem({ item: item }) + } + .width('100%') + .aspectRatio(this.itemHeightArray[item % 100] / this.itemWidthArray[item%100]) + .backgroundColor(this.colors[item % 5]) + }, (item: string) => item) + } + .columnsTemplate('1fr '.repeat(this.columns)) + .backgroundColor(0xFAEEE0) + .width('100%') + .height('100%') + .layoutWeight(1) + // Pre-load data when approaching the bottom. + .onScrollIndex((first: number, last: number) => { + if (last + 20 >= this.dataSource.totalCount()) { + setTimeout(() => { + this.dataSource.addNewItems(100); + }, 1000); + } + }) + } + } +``` + +![](figures/waterflow-demo2.gif) + +## Dynamically Adjusting the Column Count + +Dynamically adjusting the column count allows applications to switch between list and waterfall flow modes or adapt to screen width changes. For faster transitions, use the sliding window layout mode. + +```ts +// Use a state variable to manage the column count and trigger layout updates. +@State columns: number = 2; + +@Reusable +@Component +struct ReusableListItem { + @State item: number = 0; + + aboutToReuse(params: Record) { + this.item = params.item; + } + + build() { + Row() { + Image('res/waterFlow(' + this.item % 5 + ').JPG') + .objectFit(ImageFit.Fill) + .height(100) + .aspectRatio(1) + Text("N" + this.item).fontSize(12).height('16').layoutWeight(1).textAlign(TextAlign.Center) + } + } +} + + build() { + Column({ space: 2 }) { + Button('Switch Columns').fontSize(20).onClick(() => { + if (this.columns === 2) { + this.columns = 1; + } else { + this.columns = 2; + } + }) + WaterFlow({ layoutMode: WaterFlowLayoutMode.SLIDING_WINDOW }) { + LazyForEach(this.dataSource, (item: number) => { + FlowItem() { + if (this.columns === 1) { + ReusableListItem({ item: item }) + } else { + ReusableFlowItem({ item: item }) + } + } + .width('100%') + .aspectRatio(this.columns === 2 ? this.itemHeightArray[item % 100] / this.itemWidthArray[item % 100] : 0) + .backgroundColor(this.colors[item % 5]) + }, (item: string) => item) + } + .columnsTemplate('1fr '.repeat(this.columns)) + .backgroundColor(0xFAEEE0) + .width('100%') + .height('100%') + .layoutWeight(1) + // Pre-load data when approaching the bottom. + .onScrollIndex((first: number, last: number) => { + if (last + 20 >= this.dataSource.totalCount()) { + setTimeout(() => { + this.dataSource.addNewItems(100); + }, 1000); + } + }) + } + } +``` + +![](figures/waterflow-columns.gif) + +## Mixed Section Layout + +Many application UIs feature supplementary content above the **WaterFlow** component. This scenario can be implemented by nesting a **WaterFlow** within a **Scroll** or **List** container, as illustrated in the following figure: + +![](figures/waterflow-sections1.png) + +When child nodes from different sections can be integrated into a single data source, using **WaterFlowSections** enables mixed layouts within a single **WaterFlow** container. This approach simplifies scroll event handling logic compared to nested scrolling implementations. + +Each **WaterFlow** section can individually set its own number of columns, row spacing, column spacing, margin, and total number of child nodes. The following code can achieve the above effect: + +```ts +@Entry +@Component +struct WaterFlowDemo { + minSize: number = 80; + maxSize: number = 180; + colors: number[] = [0xFFC0CB, 0xDA70D6, 0x6B8E23, 0x6A5ACD, 0x00FFFF, 0x00FF7F]; + dataSource: WaterFlowDataSource = new WaterFlowDataSource(100); + private itemWidthArray: number[] = []; + private itemHeightArray: number[] = []; + private gridItems: number[] = []; + @State sections: WaterFlowSections = new WaterFlowSections(); + sectionMargin: Margin = { + top: 10, + left: 5, + bottom: 10, + right: 5 + }; + oneColumnSection: SectionOptions = { + itemsCount: 1, + crossCount: 1, + columnsGap: 5, + rowsGap: 10, + margin: this.sectionMargin, + }; + twoColumnSection: SectionOptions = { + itemsCount: 98, + crossCount: 2, + }; + // Use the last section as a footer, since footers are not supported with sections. + lastSection: SectionOptions = { + itemsCount: 1, + crossCount: 1, + }; + + // Calculate the FlowItem width and height. + getSize() { + let ret = Math.floor(Math.random() * this.maxSize); + return (ret > this.minSize ? ret : this.minSize); + } + + // Set the FlowItem size array. + setItemSizeArray() { + for (let i = 0; i < 100; i++) { + this.itemWidthArray.push(this.getSize()); + this.itemHeightArray.push(this.getSize()); + } + } + + aboutToAppear() { + this.setItemSizeArray(); + for (let i = 0; i < 15; ++i) { + this.gridItems.push(i); + } + // The total number of itemCount values across sections must match the data source item count of the WaterFlow. + let sectionOptions: SectionOptions[] = [this.oneColumnSection, this.twoColumnSection, this.lastSection]; + this.sections.splice(0, 0, sectionOptions); + } + + build() { + WaterFlow({ layoutMode: WaterFlowLayoutMode.SLIDING_WINDOW, sections: this.sections }) { + LazyForEach(this.dataSource, (item: number) => { + FlowItem() { + if (item === 0) { + Grid() { + ForEach(this.gridItems, (day: number) => { + GridItem() { + Text('GridItem').fontSize(14).height(16) + }.backgroundColor(0xFFC0CB) + }, (day: number) => day.toString()) + } + .height('30%') + .rowsGap(5) + .columnsGap(5) + .columnsTemplate('1fr '.repeat(5)) + .rowsTemplate('1fr '.repeat(3)) + } else { + ReusableFlowItem({ item: item }) + } + } + .width('100%') + .aspectRatio(item != 0 ? this.itemHeightArray[item % 100] / this.itemWidthArray[item % 100] : 0) + .backgroundColor(item != 0 ? this.colors[item % 5] : Color.White) + }, (item: string) => item) + } + .backgroundColor(0xFAEEE0) + .height('100%') + // Pre-load data when approaching the bottom. + .onScrollIndex((first: number, last: number) => { + if (last + 20 >= this.dataSource.totalCount()) { + setTimeout(() => { + this.dataSource.addNewItems(100); + // Update the itemCount values for sections after adding data. + this.twoColumnSection.itemsCount += 100; + this.sections.update(1, this.twoColumnSection); + }, 1000); + } + }) + .margin(10) + } +} +``` + +>**NOTE** +> +>Footers are not supported with **WaterFlowSections**; use the last section as a footer instead. +> +>Always update the corresponding **itemsCount** when adding or removing data to maintain layout consistency. diff --git a/en/application-dev/ui/arkts-navigation-navigation.md b/en/application-dev/ui/arkts-navigation-navigation.md index 8a44e7b606974fc2389d7355e644deff714faee3..35e0578abed26585390acaffcef23fa32dea5c2a 100644 --- a/en/application-dev/ui/arkts-navigation-navigation.md +++ b/en/application-dev/ui/arkts-navigation-navigation.md @@ -318,7 +318,7 @@ Navigation-related routing operations are all based on the APIs provided by [Nav @Component struct Index { // Create a NavPathStack object and pass it to Navigation. - pageStack: NavPathStack = new NavPathStack() + pageStack: NavPathStack = new NavPathStack(); build() { Navigation(this.pageStack) { @@ -335,8 +335,8 @@ struct Index { 1. Normal navigation: Navigation is conducted by page name and allows for passing of **param**. ```ts - this.pageStack.pushPath({ name: "PageOne", param: "PageOne Param" }) - this.pageStack.pushPathByName("PageOne", "PageOne Param") + this.pageStack.pushPath({ name: "PageOne", param: "PageOne Param" }); + this.pageStack.pushPathByName("PageOne", "PageOne Param"); ``` 2. Navigation with a return callback: An **onPop** callback is added during navigation to obtain return information and process it upon page popping. @@ -370,13 +370,13 @@ struct Index { ```ts // Return to the previous page. -this.pageStack.pop() +this.pageStack.pop(); // Return to the previous PageOne page. -this.pageStack.popToName("PageOne") +this.pageStack.popToName("PageOne"); // Return to the page whose index is 1. -this.pageStack.popToIndex(1) +this.pageStack.popToIndex(1); // Return to the root home page (clear all pages in the stack). -this.pageStack.clear() +this.pageStack.clear(); ``` ### Page Replacement @@ -385,8 +385,8 @@ this.pageStack.clear() ```ts // Replace the top page of the stack with PageOne. -this.pageStack.replacePath({ name: "PageOne", param: "PageOne Param" }) -this.pageStack.replacePathByName("PageOne", "PageOne Param") +this.pageStack.replacePath({ name: "PageOne", param: "PageOne Param" }); +this.pageStack.replacePathByName("PageOne", "PageOne Param"); // Replacement with an error code: Upon failure, an asynchronous callback is triggered to provide the error code information. this.pageStack.replaceDestination({name: "PageOne", param: "PageOne Param"}) .catch((error: BusinessError) => { @@ -402,9 +402,9 @@ this.pageStack.replaceDestination({name: "PageOne", param: "PageOne Param"}) ```ts // Remove all pages whose name is PageOne from the stack. -this.pageStack.removeByName("PageOne") +this.pageStack.removeByName("PageOne"); // Remove the page with the specified index. -this.pageStack.removeByIndexes([1,3,5]) +this.pageStack.removeByIndexes([1, 3, 5]); // Remove the page with the specified ID. this.pageStack.removeByNavDestinationId("1"); ``` @@ -426,13 +426,13 @@ this.pageStack.moveIndexToTop(1); ```ts // Obtain all page names in the stack. -this.pageStack.getAllPathName() +this.pageStack.getAllPathName(); // Obtain the parameters of the page whose index is 1. -this.pageStack.getParamByIndex(1) +this.pageStack.getParamByIndex(1); // Obtain the parameters of the PageOne page. -this.pageStack.getParamByName("PageOne") +this.pageStack.getParamByName("PageOne"); // Obtain the index set of the PageOne page. -this.pageStack.getIndexByName("PageOne") +this.pageStack.getIndexByName("PageOne"); ``` ### Route Interception @@ -477,7 +477,7 @@ this.pageStack.setInterception({ - Standard mode - By default, subpages in the **NavDestination** component are in standard mode, which corresponds to the **NavDestinationMode.STANDARD** value of the **mode** attribute. The lifecycle of a standard type **NavDestination** follows the changes in its position in the **NavPathStack**. + By default, subpages in the [NavDestination](../reference/apis-arkui/arkui-ts/ts-basic-components-navdestination.md) component are in standard mode, which corresponds to the **NavDestinationMode.STANDARD** value of the **mode** attribute. The lifecycle of a standard type **NavDestination** follows the changes in its position in the **NavPathStack**. - Dialog mode @@ -488,12 +488,12 @@ this.pageStack.setInterception({ @Entry @Component struct Index { - @Provide('NavPathStack') pageStack: NavPathStack = new NavPathStack() + @Provide('NavPathStack') pageStack: NavPathStack = new NavPathStack(); @Builder PagesMap(name: string) { if (name == 'DialogPage') { - DialogPage() + DialogPage(); } } @@ -524,7 +524,7 @@ this.pageStack.setInterception({ .fontSize(20) .margin({ bottom: 100 }) Button("Close").onClick(() => { - this.pageStack.pop() + this.pageStack.pop(); }).width('30%') } .justifyContent(FlexAlign.Center) @@ -577,7 +577,7 @@ To facilitate the decoupling of components from pages, custom components within // Custom components within NavDestination @Component struct MyComponent { - navDesInfo: uiObserver.NavDestinationInfo | undefined + navDesInfo: uiObserver.NavDestinationInfo | undefined; aboutToAppear(): void { this.navDesInfo = this.queryNavDestinationInfo(); @@ -625,20 +625,20 @@ The **Navigation** component provides default transition animations for switchin To enable or disable all transition animations in the current **Navigation** component, you can use the [disableAnimation](../reference/apis-arkui/arkui-ts/ts-basic-components-navigation.md#disableanimation11) API provided in **NavPathStack**. ```ts - pageStack: NavPathStack = new NavPathStack() + pageStack: NavPathStack = new NavPathStack(); aboutToAppear(): void { - this.pageStack.disableAnimation(true) + this.pageStack.disableAnimation(true); } ``` - On a One-time Basis To disable the transition animation for a single operation (implemented by APIs provided by **NavPathStack**, such as **Push**, **Pop**, and **Replace**), set the **animated** parameter in the API to **false**. This setting does not affect the next transition. ```ts - pageStack: NavPathStack = new NavPathStack() + pageStack: NavPathStack = new NavPathStack(); - this.pageStack.pushPath({ name: "PageOne" }, false) - this.pageStack.pop(false) + this.pageStack.pushPath({ name: "PageOne" }, false); + this.pageStack.pop(false); ``` ### Customizing a Transition @@ -694,7 +694,7 @@ You can implement shared element transitions between navigation destination page .onClick(() => { this.getUIContext()?.animateTo({ duration: 1000 }, () => { this.pageStack.pushPath({ name: 'ToPage' }, false) - }) + }); }) } } @@ -766,19 +766,19 @@ The custom route table and system route table can be used together. // Entry point function for redirection to the target page @Builder export function PageOneBuilder() { - PageOne() + PageOne(); } @Component struct PageOne { - pathStack: NavPathStack = new NavPathStack() + pathStack: NavPathStack = new NavPathStack(); build() { NavDestination() { } .title('PageOne') .onReady((context: NavDestinationContext) => { - this.pathStack = context.pathStack + this.pathStack = context.pathStack; }) } } diff --git a/en/application-dev/ui/arkts-uicontext-component-snapshot.md b/en/application-dev/ui/arkts-uicontext-component-snapshot.md new file mode 100644 index 0000000000000000000000000000000000000000..21c60daa3d0b20ab2ec30eb0e8b8aa264612b9fc --- /dev/null +++ b/en/application-dev/ui/arkts-uicontext-component-snapshot.md @@ -0,0 +1,311 @@ +# Using Component Snapshot (ComponentSnapshot) +## Overview +Component snapshot is the capability to generate a pixel map ([PixelMap](../reference/apis-image-kit/js-apis-image.md#pixelmap7)) from the rendering result of a component node tree within an application. It supports two approaches: + +- Taking a snapshot of a component that is already attached to the UI tree +- Taking a snapshot of an offline component implemented using **Builder** or **ComponentContent**. + +> **NOTE** +> +> Component snapshot relies on UI context and must be called in an environment with a clear context. Therefore, preferably use the [ComponentSnapshot](../reference/apis-arkui/js-apis-arkui-UIContext.md#componentsnapshot12) object returned by the **getComponentSnapshot** API of **UIContext**. Avoid using the **componentSnapshot** API imported directly from @kit.ArkUI. + + +### Taking a Snapshot of a Component Attached to the UI Tree +To take a snapshot of a component that is already attached to the UI tree, use [get](../reference/apis-arkui/js-apis-arkui-UIContext.md#get12-1) or [getSync](../reference/apis-arkui/js-apis-arkui-UIContext.md#getsync12). Pass the component ID (configured in advance using the **id** universal attribute) to specify the component root node. The system only traverses components attached to the tree when searching for the component to take a snapshot; it does not search cached or off-screen components. The system uses the first found result, so the application must ensure the uniqueness of component IDs. + +If you know the ID of the component with [getUniqueId](../reference/apis-arkui/js-apis-arkui-frameNode.md#getuniqueid12), you can also use [getWithUniqueId](../reference/apis-arkui/js-apis-arkui-UIContext.md#getwithuniqueid15) or [getSyncWithUniqueId](../reference/apis-arkui/js-apis-arkui-UIContext.md#getsyncwithuniqueid15) to take a snapshot of the component directly, bypassing the component search process. + +The snapshot captures only the most recent frame. If you trigger a component update and immediately take a snapshot, the updated content will not be captured; the snapshot will return the previous frame's content. + +> **NOTE** +> +> Avoid triggering updates of the component being snapped to prevent interference with the snapshot content. + + +### Taking a Snapshot of an Offline Component +Offline components are components that are encapsulated using **Builder** or **ComponentContent** but have not yet been attached to the tree. To take snapshots of them, use [createFromBuilder](../reference/apis-arkui/js-apis-arkui-UIContext.md#createfrombuilder12-1) and [createFromComponent](../reference/apis-arkui/js-apis-arkui-UIContext.md#createfromcomponent18). + +Since offline components do not participate in actual rendering, taking snapshots of them takes longer because the system must first perform offline construction, layout, and resource loading. Snapshots taken before these operations complete may return unexpected results. Therefore, it is usually necessary to set a sufficient delay to ensure the system completes these operations. For image resources, set the [syncLoad](../reference/apis-arkui/arkui-ts/ts-basic-components-image.md#syncload8) attribute of the **Image** component to **true** to force synchronous loading. This ensures images are loaded, downloaded, and decoded during offline component construction, allowing the image pixels to be correctly displayed during the snapshot process. + +## Use Cases +The following use cases illustrate common usage methods of the component snapshot capability. + +### Capturing Long Content (Scrolling Snapshot) +Long content is usually implemented using scrollable container components. When you take a snapshot, only the visible content within the container is captured, and content beyond the boundary is not included. If **LazyForEach** or **Repeat** is used, content outside the display range is not built or captured by the system. + +You can use scrollable container APIs to simulate user swiping for page-by-page snapshots, then stitch the **PixelMap** objects of each page by offset to generate a complete long image. The key points are simulating swiping, maintaining the relationship between displacement and pixel maps, and implementing **PixelMap** read and write operations. + +**Step 1: Add a scroll controller and event listener.** + +To simulate scrolling and listen for the component's scroll offset, you need to add a scroll controller and scroll listener to the scrollable container (**List** component in this example). + +```ts +// src/main/ets/view/ScrollSnapshot.ets +@Component +export struct ScrollSnapshot { + private scroller: Scroller = new Scroller(); + private listComponentWidth: number = 0; + private listComponentHeight: number = 0; + // Current offset of the List component + private curYOffset: number = 0; + // Scroll distance per step + private scrollHeight: number = 0; + + + // ... + build() { + // ... + Stack() { + // ... + // 1.1 Bind the scroll controller and configure a unique component ID using .id. + List({ + scroller: this.scroller + })// ... + .id(LIST_ID) + // 1.2 Obtain the scroll offset through a callback. + .onDidScroll(() => { + this.curYOffset = this.scroller.currentOffset().yOffset; + }) + .onAreaChange((oldValue, newValue) => { + // 1.3 Obtain the width and height of the component. + this.listComponentWidth = newValue.width as number; + this.listComponentHeight = newValue.height as number; + }) + } + } +} +``` + +**Step 2: Implement recursive scrolling snapshot and caching.** + +Implement a recursive method to scroll and snapshot in a loop, combined with animation effects during scrolling. + +```ts + /** + * Recursively scroll, take snapshots, and merge all snapshots when scrolling ends. + */ + async scrollSnapAndMerge() { + // Record the scroll offset. + this.scrollYOffsets.push(this.curYOffset - this.yOffsetBefore); + // Call the component snapshot API to obtain the List component's snapshot. + const pixelMap = await this.getUIContext().getComponentSnapshot().get(LIST_ID); + // Obtain the pixel bytes of the pixel map and save them in an array. + let area: image.PositionArea = + await this.getSnapshotArea(pixelMap, this.scrollYOffsets, this.listComponentWidth, this.listComponentHeight) + this.areaArray.push(area); + + // Check whether scrolling has reached the end and if the user has forced a stop. + if (!this.scroller.isAtEnd() && !this.isClickStop) { + // If scrolling is not at the end or stopped, play a scroll animation, wait for a period, then continue recursive snapshot taking. + CommonUtils.scrollAnimation(this.scroller, 1000, this.scrollHeight); + await CommonUtils.sleep(1500); + await this.scrollSnapAndMerge(); + } else { + // When scrolling ends, call mergeImage to stitch all saved pixel map data and return the long snapshot pixel map object. + this.mergedImage = + await this.mergeImage(this.areaArray, this.scrollYOffsets[this.scrollYOffsets.length - 1], + this.listComponentWidth, this.listComponentHeight); + } + } + +// src/main/ets/common/CommonUtils.ets +static scrollAnimation(scroller: Scroller, duration: number, scrollHeight: number): void { + scroller.scrollTo({ + xOffset: 0, + yOffset: (scroller.currentOffset().yOffset + scrollHeight), + animation: { + duration: duration, + curve: Curve.Smooth, + canOverScroll: false + } + }); +} +``` + +**Step 3: Stitch the long snapshot.** + +Call **image.createPixelMapSync()** to create a long snapshot **longPixelMap** and iterate through the previously saved image fragment data (**this.areaArray**). Construct an **image.PositionArea** object **area**, and call **longPixelMap.writePixelsSync(area)** to write these fragments into the correct positions one by one, thereby stitching them into a complete long snapshot. + +```ts +async mergeImage(areaArray: image.PositionArea[], lastOffsetY: number, listWidth: number, + listHeight: number): Promise { + // Create a long snapshot pixel map object. + let opts: image.InitializationOptions = { + editable: true, + pixelFormat: 4, + size: { + width: this.getUIContext().vp2px(listWidth), + height: this.getUIContext().vp2px(lastOffsetY + listHeight) + } + }; + let longPixelMap = image.createPixelMapSync(opts); + let imgPosition: number = 0; + + + for (let i = 0; i < areaArray.length; i++) { + let readArea = areaArray[i]; + let area: image.PositionArea = { + pixels: readArea.pixels, + offset: 0, + stride: readArea.stride, + region: { + size: { + width: readArea.region.size.width, + height: readArea.region.size.height + }, + x: 0, + y: imgPosition + } + } + imgPosition += readArea.region.size.height; + longPixelMap.writePixelsSync(area); + } + return longPixelMap; +} +``` + +**Step 4: Save the snapshot.** + +Use the **SaveButton** security component to save the snapshot. + +```ts +// src/main/ets/view/SnapshotPreview.ets +SaveButton({ + icon: SaveIconStyle.FULL_FILLED, + text: SaveDescription.SAVE_IMAGE, + buttonType: ButtonType.Capsule +}) + .onClick((event, result) => { + this.saveSnapshot(result); + }) + +async saveSnapshot(result: SaveButtonOnClickResult): Promise { + if (result === SaveButtonOnClickResult.SUCCESS) { + const helper = photoAccessHelper.getPhotoAccessHelper(this.context); + const uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'png'); + const file = await fileIo.open(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE); + const imagePackerApi: image.ImagePacker = image.createImagePacker(); + const packOpts: image.PackingOption = { + format: 'image/png', + quality: 100, + }; + imagePackerApi.packing(this.mergedImage, packOpts).then((data) => { + fileIo.writeSync(file.fd, data); + fileIo.closeSync(file.fd); + Logger.info(TAG, `Succeeded in packToFile`); + promptAction.showToast({ + message: $r('app.string.save_album_success'), + duration: 1800 + }) + }).catch((error: BusinessError) => { + Logger.error(TAG, `Failed to packToFile. Error code is ${error.code}, message is ${error.message}`); + }); + } + // ... +} +``` + +**Step 5: Release the pixel map after saving.** + +When the **PixelMap** object is no longer in use, assign it to **undefined** in a timely manner, as in **this.mergedImage = undefined;**. + +```ts + closeSnapPopup(): void { + // Close the popup. + this.isShowPreview = false; + // Release the pixel map object. + this.mergedImage = undefined; + // Reset related parameters. + this.snapPopupWidth = 100; + this.snapPopupHeight = 200; + this.snapPopupPosition = + PopupUtils.calcPopupCenter(this.screenWidth, this.screenHeight, this.snapPopupWidth, this.snapPopupHeight); + this.isLargePreview = false; + } +``` + +### Encapsulating a Global Screenshot API +As mentioned earlier, snapshot APIs must be used where the UI context is clear. However, applications sometimes need to encapsulate a unified global snapshot API for different modules. For example, in the following example, the component built by **awardBuilder** has a fixed structure. **GlobalStaticSnapshot** provides a global method **getAwardSnapshot** that meets the needs of different modules to take snapshots of components in the same fixed mode, achieving the encapsulation of a global snapshot API. + +```ts +import { image } from '@kit.ImageKit'; +import { ComponentContent } from '@kit.ArkUI'; + +export class Params { + text: string | undefined | null = ""; + + constructor(text: string | undefined | null) { + this.text = text; + } +} + +@Builder +function awardBuilder(params: Params) { + Column() { + Text(params.text) + .fontSize(90) + .fontWeight(FontWeight.Bold) + .margin({ bottom: 36 }) + .width('100%') + .height('100%') + }.backgroundColor('#FFF0F0F0') +} + +export class GlobalStaticSnapshot { + /** + * A static method to obtain a snapshot of a fixed object. + */ + static getAwardSnapshot(uiContext: UIContext, textParam: Params): image.PixelMap | undefined { + let resultPixmap: image.PixelMap | undefined = undefined + let contentNode = new ComponentContent(uiContext, wrapBuilder(awardBuilder), textParam); + uiContext.getComponentSnapshot() + .createFromComponent(contentNode, 320, true, { scale: 1, waitUntilRenderFinished: true }) + .then((pixmap: image.PixelMap) => { + resultPixmap = pixmap + }) + .catch((err: Error) => { + console.error("error: " + err) + }) + return resultPixmap; + } +} +``` + +## Best Practices for Component Screenshot +### Reasonably Controlling Snapshot Timing +When implementing snapshot functionality, note that the component rendering process is not completed in one go. When building and displaying components, the system goes through complex steps, such as measurement, layout, and command submission, before finally presenting them on the screen during a hardware refresh. Therefore, in specific cases, calling the snapshot API immediately after component refresh may not obtain the expected content. + +To ensure accurate snapshot results, it is recommended that you execute the snapshot operation after the component is fully rendered. + +**Understanding the Component Drawing Status** + +To ensure the snapshot content meets expectations, you should understand when the code modifies the UI state and allow time for the system to process it, which can usually be achieved by adding a delay. + +Although you can use [ComponentObserver](../reference/apis-arkui/js-apis-arkui-inspector.md#componentobserver) in the Inspector to perceive component drawing (**draw**) and display notifications, note that the component drawing notification from **ComponentObserver** does not mean the system has actually executed the drawing commands, as this depends on the load of the graphics system service. + +**Waiting for Drawing to Complete** + +The main factor affecting the snapshot expectation is the time difference between the snapshot timing and the system service executing the drawing commands. When a snapshot call is initiated, all previously submitted drawing commands on the application side may not have been truly executed by the graphics service. To address this, you can specify **waitUntilRenderFinished** as **true** in the [SnapshotOptions](../reference/apis-arkui/js-apis-arkui-componentSnapshot.md#snapshotoptions12) parameter to ensure the system waits for all previous drawing commands to complete before executing the snapshot request, thereby capturing more complete content. + +> **NOTE** +> +> It is recommended that the **waitUntilRenderFinished** parameter be always set to **true**. + +**Understanding the Impact of Resource Loading on Snapshot** + +Another common reason for unexpected snapshots is image resource loading. Image components support both online resource links and local resources, and most image resources are in compressed formats such as PNG and JPEG. These resources need to be decoded by the system into a pixel map format that can be submitted for drawing, a process that occurs on an asynchronous I/O thread by default. This can lead to unexpected snapshot behavior due to the uncertainty of the process duration. + +The following optimization approaches can be taken: +1. Pre-parse images into PixelMap format and configure the PixelMap for the image component. This approach is recommended for optimization. +2. Set the **syncLoad** attribute of the **Image** component to **true** to force synchronous loading, ensuring resources can be directly submitted when the component is built. +3. Specify the delay duration and set **checkImageStatus** to **true** to attempt to take a snapshot. If error 160001 is returned, retry with an increased delay. + + +### Timely Saving and Releasing Pixel Map Objects +To release resources promptly, assign the **PixelMap** object returned by the snapshot API to null when it is no longer in use. + +### Appropriately Controlling Sampling Precision +Avoid capturing images that are excessively large, ideally not larger than the screen size. If the size of the image to capture exceeds device-specific underlying limits, the capture will fail. You can reduce sampling precision by controlling the **scale** parameter in **SnapshotOptions**, which significantly saves memory and improves snapshot efficiency. + +### Using Other Capabilities for Self-Rendering Scenarios +Although snapshots can be taken by simply passing a component root node, this is not the recommended way when the child components include [Video](../reference/apis-arkui/arkui-ts/ts-media-components-video.md), [XComponent](../reference/apis-arkui/arkui-ts/ts-basic-components-xcomponent.md), or [Web](../reference/apis-arkweb/ts-basic-components-web.md) components. It is recommended that you use the [image.createPixelMapFromSurface](../reference/apis-image-kit/js-apis-image.md#imagecreatepixelmapfromsurface11) API. diff --git a/en/application-dev/ui/arkts-universal-attributes-accessibility.md b/en/application-dev/ui/arkts-universal-attributes-accessibility.md new file mode 100644 index 0000000000000000000000000000000000000000..70fb51f9d12fc995fd4d6b5ba9bb10d1c0451113 --- /dev/null +++ b/en/application-dev/ui/arkts-universal-attributes-accessibility.md @@ -0,0 +1,220 @@ +# Supporting Accessibility + +## Overview + +ArkUI provides comprehensive accessibility capabilities, enabling you to create accessible application UIs that meet the needs of users with visual, auditory, motor, and cognitive impairments. + +When the [accessibility attributes](../reference/apis-arkui/arkui-ts/ts-universal-attributes-accessibility.md) of a component change, it triggers responses such as screen readers re-reading component information, accessibility services rescanning the component tree, state announcements, and dynamic updates of virtual nodes. These mechanisms ensure that assistive tools (such as screen readers) can promptly perceive and adapt to changes, providing a consistent experience for users with disabilities. + +## Setting Accessibility Groups + +The **accessibilityGroup** attribute sets whether to enable accessibility grouping. If this feature is enabled, the component and all its child components are treated as a whole, and accessibility services no longer process child components individually. The **accessibilityGroup** attribute supports the following values: + +- **false** (default): Accessibility grouping is disabled. + +- **true**: Accessibility grouping is enabled. + +Here is an example using the **Column** component to enable accessibility grouping: + +```ts +Column() { +} +.accessibilityGroup(true) +``` + +## Setting the Accessibility Level + +The **accessibilityLevel** attribute indicates the accessibility level of a component, controlling whether it can be recognized by accessibility services. It supports the following values: + +- **"auto"** (default): The component's recognizability is determined by the accessibility grouping service and ArkUI. + +- **"yes"**: The component can be recognized by accessibility services. + +- **"no"**: The component cannot be recognized by accessibility services. + +- **"no-hide-descendants"**: Neither the component nor its child components can be recognized by accessibility services. + +Here is an example using the **Column** component to set its accessibility level to **"yes"**: + +```ts +Column() { +} +.accessibilityGroup(true) +.accessibilityLevel("yes") +``` + +## Setting the Accessibility Text + +The **accessibilityText** attribute provides readable text for components without text content. If a component already has text, the accessibility text takes precedence during announcement. + +This attribute supports strings or resource references. + +Here is an example using the **Column** component to set its accessibility text to **"Group"**: + +```ts +Column() { +} +.accessibilityGroup(true) +.accessibilityLevel("yes") +.accessibilityText("Group") +``` + +## Setting Accessibility Description + +The **accessibilityDescription** attribute provides a more detailed description of the component, which is read after the text content. + +Here is an example using the **Column** component to set its accessibility description: + +```ts +Column() { +} +.accessibilityGroup(true) +.accessibilityLevel("yes") +.accessibilityText("Group") +.accessibilityDescription("The Column component can be selected, and the announced content is 'Group'") +``` + +## Setting Accessibility Virtual Nodes + +The **accessibilityVirtualNode** attribute adds virtual accessibility nodes to self-drawn components. Assistive tools read information from these nodes instead of the actual displayed content. + +```ts +@Entry +@Component +struct VirtualNodeExample { + @Builder customAccessibilityNode() { + Text("Text 2") + .fontSize(50) + .fontWeight(FontWeight.Bold) + } + + build() { + Column() { + Text("Text 1") + .fontSize(50) + .fontWeight(FontWeight.Bold) + } + .accessibilityGroup(true) + .accessibilityLevel("yes") + .accessibilityVirtualNode(this.customAccessibilityNode) + } +} +``` + +## Setting Whether an Accessibility Node Is Selected + +The **accessibilityChecked** and **accessibilitySelected** attributes enhance accessibility by communicating the selection state of components to assistive tools like screen readers. + +### Setting Selection State for Multi-Select Scenarios + +The **accessibilityChecked** attribute indicates whether a component is checked in multi-select scenarios (for example, check boxes and toggle buttons). It applies to scenarios requiring clear "selected/unselected" semantics and supports the following values: + +- **undefined** (default): automatically determined by the system (depending on the component's own state, such as the **isOn** attribute of a **Toggle** component). + +- **false**: not selected. + +- **true**: selected (for example, check box checked). + +Here is an example using the **Column** component to set it as checked when multi-select is supported: + +```ts +Column() { +} +.accessibilityGroup(true) +.accessibilityLevel("yes") +.accessibilityText("Group") +.accessibilityDescription("The Column component can be selected, and the announced content is 'Group'") +.accessibilityChecked(true) +``` + +### Setting Selection State for Single-Select Scenarios + +The **accessibilitySelected** attribute indicates whether a component is selected in single-select scenarios (for example, single-select lists and tabs). It applies to scenarios requiring differentiation of "current selected items" (for example, single-select groups and navigation menus) and supports the following values: + +- **undefined** (default): automatically determined by the system. + +- **false**: not selected. + +- **true**: currently selected. + +Here is an example using the **Column** component to let the system determine its selection state when single-select is supported: + +```ts +Column() { +} +.accessibilityGroup(true) +.accessibilityLevel("yes") +.accessibilityText("Group") +.accessibilityDescription("The Column component can be selected, and the announced content is 'Group'") +.accessibilitySelected(undefined) +``` + +### Key Differences Between accessibilityChecked and accessibilitySelected + +In ArkUI accessibility attributes, both **accessibilityChecked** and **accessibilitySelected** are used to indicate the state of a component, but they have fundamentally different application scenarios and semantic meanings. The following table provides a comparison of these two. + +| Attribute | accessibilityChecked | accessibilitySelected | +| ------- | ------------------------ | --------------------- | +| Use cases| Binary or ternary components, such as check boxes and toggles.| Mutually exclusive selection scenarios, such as single-select lists and tabs.| +| Semantic objectives| Physical state of components (for example, whether a switch is on).| Navigation focus item (for example, current selected item in a list).| +| State persistence| Usually requires explicit saving (such as form submission).| Temporary (changes with focus movement).| +| Typical components| **Checkbox** and **Toggle**. | **List** and **Tabs**. | + +## Recommendations + +- Priority control + + Use **accessibilityLevel** to ensure key operations are recognizable. + +- Semantic descriptions + + Add **accessibilityText** and **accessibilityDescription** for non-text elements like icons and images. + +- Grouping optimization + + Use **accessibilityGroup** to reduce redundant announcements for complex layouts. + +## Scenario Example + +This example demonstrates how to use **accessibilityText** and **accessibilityDescription** to customize the content announced by screen readers. + +If a component has both text and accessibility text attributes, only the accessibility text is announced when the component is selected. + +```ts +@Entry +@Component +struct Index { + + @Builder customAccessibilityNode() { + Column() { + Text(`virtual node`) + } + .width(10) + .height(10) + } + + build() { + Row() { + Column() { + Text("Text 1") + .fontSize(50) + .fontWeight(FontWeight.Bold) + Text("Text 2") + .fontSize(50) + .fontWeight(FontWeight.Bold) + } + .width('100%') + .accessibilityGroup(true) + .accessibilityLevel("yes") + .accessibilityText("Group") + .accessibilityDescription("The Column component can be selected, and the announced content is 'Group'") + .accessibilityVirtualNode(this.customAccessibilityNode) + .accessibilityChecked(true) + .accessibilitySelected(undefined) + } + .height('100%') + } +} +``` + +![en-us_image_0000001745415556](figures/en-us_image_0000001745415556.jpg) diff --git a/en/application-dev/ui/arkts-user-defined-draw.md b/en/application-dev/ui/arkts-user-defined-draw.md new file mode 100644 index 0000000000000000000000000000000000000000..0cc4595f526e91e7bd7d569173363096d7cc62c6 --- /dev/null +++ b/en/application-dev/ui/arkts-user-defined-draw.md @@ -0,0 +1,127 @@ +# Custom Drawing +When the registered event is detected as a drawing type, you can use the custom drawing feature to implement your own drawing logic and render custom content. +> **NOTE** +> - During event registration, you must register the event as a drawing event (for example, **ARKUI_NODE_CUSTOM_EVENT_ON_DRAW**). You can find the event types and their meanings by referring to the [ArkUI_NodeCustomEventType](../reference/apis-arkui/_ark_u_i___native_module.md#arkui_nodecustomeventtype) enum. +> +> - To implement custom drawing logic, you must define custom **UserData** and pass it during event registration. + +- Use the **create** API of **ArkUI_NativeNodeAPI_1** to create a custom node, passing **ARKUI_NODE_CUSTOM**. + ```c++ + auto customNode = nodeAPI->createNode(ARKUI_NODE_CUSTOM); + ``` + +- Register the custom event with the custom node, event type (for example, **ARKUI_NODE_CUSTOM_EVENT_ON_FOREGROUND_DRAW**), event ID, and **UserData**. + ```c++ + //UserData + struct A { + int32_t a =6; + bool flag = true; + ArkUI_NodeHandle node; + }; + A *a = new A; + a->node = customNode; + nodeAPI->registerNodeCustomEvent(customNode,ARKUI_NODE_CUSTOM_EVENT_ON_FOREGROUND_DRAW,1,a); + nodeAPI->registerNodeCustomEventReceiver([](ArkUI_NodeCustomEvent *event) { + // Event callback logic + }); + ``` + +- In the callback, obtain the event type, event ID, and UserData to determine the logic to execute, using the following APIs: [OH_ArkUI_NodeCustomEvent_GetEventType](../reference/apis-arkui/_ark_u_i___native_module.md#oh_arkui_nodecustomevent_geteventtype), [OH_ArkUI_NodeCustomEvent_GetEventTargetId](../reference/apis-arkui/_ark_u_i___native_module.md#oh_arkui_nodecustomevent_geteventtargetid), [OH_ArkUI_NodeCustomEvent_GetUserData](../reference/apis-arkui/_ark_u_i___native_module.md#oh_arkui_nodecustomevent_getuserdata). + + ```c++ + auto type = OH_ArkUI_NodeCustomEvent_GetEventType(event); + auto targetId = OH_ArkUI_NodeCustomEvent_GetEventTargetId(event); + auto userData =reinterpret_cast( OH_ArkUI_NodeCustomEvent_GetUserData(event)); + ``` + +- Use [OH_ArkUI_NodeCustomEvent_GetDrawContextInDraw](../reference/apis-arkui/_ark_u_i___native_module.md#oh_arkui_nodecustomevent_getdrawcontextindraw) to obtain the drawing context from the custom event, and then pass it to [OH_ArkUI_DrawContext_GetCanvas](../reference/apis-arkui/_ark_u_i___native_module.md#oh_arkui_drawcontext_getcanvas) to obtain the drawing canvas pointer. This pointer is then cast to an **OH_Drawing_Canvas** pointer for drawing operations. + ```c++ + // Obtain the drawing context for the custom event. + auto *drawContext = OH_ArkUI_NodeCustomEvent_GetDrawContextInDraw(event); + // Obtain the drawing canvas pointer. + auto *canvas1 = OH_ArkUI_DrawContext_GetCanvas(drawContext); + // Cast the pointer to an OH_Drawing_Canvas pointer for drawing. + OH_Drawing_Canvas *canvas = reinterpret_cast(canvas1); + // Drawing logic. + int32_t width = 1000; + int32_t height = 1000; + auto path = OH_Drawing_PathCreate(); + OH_Drawing_PathMoveTo(path, width / 4, height / 4); + OH_Drawing_PathLineTo(path, width * 3 / 4, height * 3 / 4); + OH_Drawing_PathLineTo(path, width * 3 / 4, height * 3 / 4); + OH_Drawing_PathLineTo(path, width * 3 / 4, height * 3 / 4); + OH_Drawing_PathLineTo(path, width * 3 / 4, height * 3 / 4); + OH_Drawing_PathClose(path); + auto pen = OH_Drawing_PenCreate(); + OH_Drawing_PenSetWidth(pen, 10); + OH_Drawing_PenSetColor(pen, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0x00, 0x00)); + OH_Drawing_CanvasAttachPen(canvas, pen); + OH_Drawing_CanvasDrawPath(canvas, path); + ``` +**Example** + +```c++ +ArkUI_NodeHandle test(ArkUI_NativeNodeAPI_1 *nodeAPI) { + // Create a node. + auto column = nodeAPI->createNode(ARKUI_NODE_COLUMN); + auto customNode = nodeAPI->createNode(ARKUI_NODE_CUSTOM); + ArkUI_NumberValue value[] = {480}; + ArkUI_AttributeItem item = {value, 1}; + // Set attributes. + nodeAPI->setAttribute(column, NODE_WIDTH, &item); + value[0].i32 = 720; + nodeAPI->setAttribute(column, NODE_HEIGHT, &item); + ArkUI_NumberValue NODE_WIDTH_value[] = {200}; + ArkUI_AttributeItem NODE_WIDTH_Item[] = {NODE_WIDTH_value, 1}; + ArkUI_NumberValue NODE_HEIGHT_value[] = {200}; + ArkUI_AttributeItem NODE_HEIGHT_Item[] = {NODE_HEIGHT_value, 1}; + ArkUI_NumberValue NODE_BACKGROUND_COLOR_item_value[] = {{.u32 = 0xFFFFFF00}}; + ArkUI_AttributeItem NODE_BACKGROUND_COLOR_Item[] = {NODE_BACKGROUND_COLOR_item_value, 1}; + // Define custom UserData. + struct A { + int32_t a =6; + bool flag = true; + ArkUI_NodeHandle node; + }; + A *a = new A; + a->node = customNode; + nodeAPI->setAttribute(customNode, NODE_WIDTH, NODE_WIDTH_Item); + nodeAPI->setAttribute(customNode, NODE_HEIGHT, NODE_HEIGHT_Item); + nodeAPI->setAttribute(customNode, NODE_BACKGROUND_COLOR, NODE_BACKGROUND_COLOR_Item); + // Register the event. + nodeAPI->registerNodeCustomEvent(customNode,ARKUI_NODE_CUSTOM_EVENT_ON_FOREGROUND_DRAW,1,a); + // Define the event callback. + nodeAPI->registerNodeCustomEventReceiver([](ArkUI_NodeCustomEvent *event) { + // Obtain information from the custom event. + auto type = OH_ArkUI_NodeCustomEvent_GetEventType(event); + auto targetId = OH_ArkUI_NodeCustomEvent_GetEventTargetId(event); + auto userData =reinterpret_cast( OH_ArkUI_NodeCustomEvent_GetUserData(event)); + if (type == ARKUI_NODE_CUSTOM_EVENT_ON_FOREGROUND_DRAW && targetId == 1 && userData->flag) { + // Obtain the drawing context for the custom event. + auto *drawContext = OH_ArkUI_NodeCustomEvent_GetDrawContextInDraw(event); + // Obtain the drawing canvas pointer. + auto *canvas1 = OH_ArkUI_DrawContext_GetCanvas(drawContext); + // Cast the pointer to an OH_Drawing_Canvas pointer for drawing. + OH_Drawing_Canvas *canvas = reinterpret_cast(canvas1); + int32_t width = 1000; + int32_t height = 1000; + auto path = OH_Drawing_PathCreate(); + OH_Drawing_PathMoveTo(path, width / 4, height / 4); + OH_Drawing_PathLineTo(path, width * 3 / 4, height * 3 / 4); + OH_Drawing_PathLineTo(path, width * 3 / 4, height * 3 / 4); + OH_Drawing_PathLineTo(path, width * 3 / 4, height * 3 / 4); + OH_Drawing_PathLineTo(path, width * 3 / 4, height * 3 / 4); + OH_Drawing_PathClose(path); + auto pen = OH_Drawing_PenCreate(); + OH_Drawing_PenSetWidth(pen, 10); + OH_Drawing_PenSetColor(pen, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0x00, 0x00)); + OH_Drawing_CanvasAttachPen(canvas, pen); + OH_Drawing_CanvasDrawPath(canvas, path); + } + }); + // Add the custom node to the tree. + nodeAPI->addChild(column, customNode); + return column; + } +``` +![Custom drawing](figures/custom_drawing.jpg) diff --git a/en/application-dev/ui/figures/custom_drawing.jpg b/en/application-dev/ui/figures/custom_drawing.jpg new file mode 100644 index 0000000000000000000000000000000000000000..18802491c7e82a33fe130824465ea5f5a7ecd282 Binary files /dev/null and b/en/application-dev/ui/figures/custom_drawing.jpg differ diff --git a/en/application-dev/ui/figures/en-us_image_0000001502261065.jpg b/en/application-dev/ui/figures/en-us_image_0000001502261065.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fc16d696810ba6d9dcdcd13a0f61dfaf138f2f90 Binary files /dev/null and b/en/application-dev/ui/figures/en-us_image_0000001502261065.jpg differ diff --git a/en/application-dev/ui/figures/en-us_image_0000001502261185.jpg b/en/application-dev/ui/figures/en-us_image_0000001502261185.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5149b6cc4c3e8e9e116a786e7e3ba3a0de4de8a0 Binary files /dev/null and b/en/application-dev/ui/figures/en-us_image_0000001502261185.jpg differ diff --git a/en/application-dev/ui/figures/en-us_image_0000001502381065.png b/en/application-dev/ui/figures/en-us_image_0000001502381065.png new file mode 100644 index 0000000000000000000000000000000000000000..b4a26588153bf38afe12476ddd0c6ae59799578c Binary files /dev/null and b/en/application-dev/ui/figures/en-us_image_0000001502381065.png differ diff --git a/en/application-dev/ui/figures/en-us_image_0000001745415556.jpg b/en/application-dev/ui/figures/en-us_image_0000001745415556.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1a748fd1e0ed74971d8bd5756f4b66c5dbcf5379 Binary files /dev/null and b/en/application-dev/ui/figures/en-us_image_0000001745415556.jpg differ diff --git a/en/application-dev/ui/figures/en-us_image_0000001746521386.jpg b/en/application-dev/ui/figures/en-us_image_0000001746521386.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6da6888061beb608e069e3a4fbc30fd6499dbb46 Binary files /dev/null and b/en/application-dev/ui/figures/en-us_image_0000001746521386.jpg differ diff --git a/en/application-dev/ui/figures/ndk_text_styled_string.png b/en/application-dev/ui/figures/ndk_text_styled_string.png new file mode 100644 index 0000000000000000000000000000000000000000..c44e2e231eeb089d0a658ba7cf9a4d54c18107b0 Binary files /dev/null and b/en/application-dev/ui/figures/ndk_text_styled_string.png differ diff --git a/en/application-dev/ui/figures/waterflow-columns.gif b/en/application-dev/ui/figures/waterflow-columns.gif new file mode 100644 index 0000000000000000000000000000000000000000..92004ea4061c110861cbf8bd77c4f203a1b151d3 Binary files /dev/null and b/en/application-dev/ui/figures/waterflow-columns.gif differ diff --git a/en/application-dev/ui/figures/waterflow-demo1.gif b/en/application-dev/ui/figures/waterflow-demo1.gif new file mode 100644 index 0000000000000000000000000000000000000000..5bea9797b6cba7ed74f413f5c9450df18b3e9471 Binary files /dev/null and b/en/application-dev/ui/figures/waterflow-demo1.gif differ diff --git a/en/application-dev/ui/figures/waterflow-demo2.gif b/en/application-dev/ui/figures/waterflow-demo2.gif new file mode 100644 index 0000000000000000000000000000000000000000..705ad43eb0c8ca3eda485ae535e467d0e3430218 Binary files /dev/null and b/en/application-dev/ui/figures/waterflow-demo2.gif differ diff --git a/en/application-dev/ui/figures/waterflow-row.png b/en/application-dev/ui/figures/waterflow-row.png new file mode 100644 index 0000000000000000000000000000000000000000..4c1c432b8004e4736461051037b522485b5bca2d Binary files /dev/null and b/en/application-dev/ui/figures/waterflow-row.png differ diff --git a/en/application-dev/ui/figures/waterflow-sections1.png b/en/application-dev/ui/figures/waterflow-sections1.png new file mode 100644 index 0000000000000000000000000000000000000000..c1b151c765c4a32d8c23d654fc13f2bc88017547 Binary files /dev/null and b/en/application-dev/ui/figures/waterflow-sections1.png differ diff --git a/en/application-dev/ui/figures/waterflow.png b/en/application-dev/ui/figures/waterflow.png new file mode 100644 index 0000000000000000000000000000000000000000..70015b05e2899dd550ed2982205b5bea0bbc0a7a Binary files /dev/null and b/en/application-dev/ui/figures/waterflow.png differ diff --git a/en/application-dev/ui/ndk-loading-long-list.md b/en/application-dev/ui/ndk-loading-long-list.md index 2a424490b076b46bef62c19d34bb5ad188e74c9c..44849a9f9d21a3ecb2516f78253a0fb772bc2928 100644 --- a/en/application-dev/ui/ndk-loading-long-list.md +++ b/en/application-dev/ui/ndk-loading-long-list.md @@ -1,28 +1,33 @@ -# Developing a Long List with Lazy Loading +# Using Lists -For the **List**, **Grid**, **WaterFlow**, and **Swiper** components, the [NodeAdapter](../reference/apis-arkui/_ark_u_i___native_module.md#arkui_nodeadapterhandle) object is provided as an alternative to the ArkTS **LazyForEach** feature for on-demand child component generation. The specific attribute enumeration values are as follows: -- **List**: **NODE_LIST_NODE_ADAPTER** -- **Grid**: **NODE_GRID_NODE_ADAPTER** -- **WaterFlow**: **NODE_WATER_FLOW_NODE_ADAPTER** -- **Swiper**: **NODE_SWIPER_NODE_ADAPTER** +The ArkUI development framework provides list components through NDK APIs, enabling efficient display of structured, scrollable content. List components allow you to control the scroll position, group display content, and use **NodeAdapter** for lazy loading to improve list creation performance. -Key specifications of **NodeAdapter** include: +## Creating a List +For details about how to create a list, see [Integrating with ArkTS Pages](../ui/ndk-access-the-arkts-page.md). + +## Listening for Scroll Events + +Implement list scroll event monitoring as instructed in the component event monitoring section. + +## Implementing Lazy Loading + +### NodeAdapter Overview + +The NDK provides the [NodeAdapter](../reference/apis-arkui/_ark_u_i___native_module.md#arkui_nodeadapterhandle) object as an alternative to the LazyForEach functionality in ArkTS for on-demand generation of child components. **NodeAdapter** works with **List**, **ListItemGroup**, **Grid**, **WaterFlow**, and **Swiper** components. - Nodes with **NodeAdapter** set do not support direct child addition APIs like **addChild**. Child components are managed entirely by **NodeAdapter**. If a parent component already has child nodes, setting **NodeAdapter** will fail and return an error code. -- **NodeAdapter** uses events to notify you to generate components on demand. You must register an [event listener](../reference/apis-arkui/_ark_u_i___native_module.md#oh_arkui_nodeadapter_registereventreceiver) and handle logic within listener events, which are defined by [ArkUI_NodeAdapterEventType](../reference/apis-arkui/_ark_u_i___native_module.md#arkui_nodeadaptereventtype). **NodeAdapter** does not automatically release off-screen component objects; you must manage object release or caching during the [NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER](../reference/apis-arkui/_ark_u_i___native_module.md#arkui_nodeadaptereventtype) event. The following image illustrates the event triggering mechanism in a typical list scrolling scenario. +- **NodeAdapter** notifies you of on-demand generation of components through relevant events. Similar to the component event mechanism, you need to register an [event listener](../reference/apis-arkui/_ark_u_i___native_module.md#oh_arkui_nodeadapter_registereventreceiver) when using **NodeAdapter** and handle logic in the listener events. Relevant events are defined by [ArkUI_NodeAdapterEventType](../reference/apis-arkui/_ark_u_i___native_module.md#arkui_nodeadaptereventtype). **NodeAdapter** does not actively release off-screen component objects; you must release or cache and reuse component objects in the [NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER](../reference/apis-arkui/_ark_u_i___native_module.md#arkui_nodeadaptereventtype) event. The following image illustrates the event triggering mechanism in a typical list scrolling scenario. ![en-us_image_0000001949769409](figures/en-us_image_0000001949769409.png) -The following example optimizes the code in the [Integrating with ArkTS Pages](ndk-access-the-arkts-page.md) section, by introducing a lazy loading mechanism for a text list: - +### Implementing a Lazy Loading Adapter -1. Integrate ArkTS into your project. For details, see [Integrating with ArkTS Pages](ndk-access-the-arkts-page.md). +Use the **ArkUListItemAdapter** class to manage the lazy loading adapter. Create a **NodeAdapter** object in the class constructor and set an event listener for the **NodeAdapter** object. In the class destructor, destroy the **NodeAdapter** object. -2. Implement lazy loading adapter functionality. - ``` + ```c++ // ArkUIListItemAdapter // Code for lazy loading functionality in a text list. @@ -71,9 +76,9 @@ The following example optimizes the code in the [Integrating with ArkTS Pages](n // Remove the item at the specified index. data_.erase(data_.begin() + index); // If the index change affects the visibility of items in the visible area, the NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER event will be triggered to remove the element. - // If items are added, the NODE_ADAPTER_EVENT_ON_GET_NODE_ID and NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER events will be triggered accordingly. + // Depending on whether there are new elements, the NODE_ADAPTER_EVENT_ON_GET_NODE_ID or NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER event will be triggered. OH_ArkUI_NodeAdapter_RemoveItem(handle_, index, 1); - // Update the new total count. + // Update the total count. OH_ArkUI_NodeAdapter_SetTotalNodeCount(handle_, data_.size()); } @@ -82,7 +87,7 @@ The following example optimizes the code in the [Integrating with ArkTS Pages](n // If the index change affects the visibility of elements in the visible area, the NODE_ADAPTER_EVENT_ON_GET_NODE_ID and NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER events will be triggered. // If items are removed, the NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER event will be triggered accordingly. OH_ArkUI_NodeAdapter_InsertItem(handle_, index, 1); - // Update the new total count. + // Update the total count. OH_ArkUI_NodeAdapter_SetTotalNodeCount(handle_, data_.size()); } @@ -90,7 +95,7 @@ The following example optimizes the code in the [Integrating with ArkTS Pages](n auto temp = data_[oldIndex]; data_.insert(data_.begin() + newIndex, temp); data_.erase(data_.begin() + oldIndex); - // If the move changes the visibility of items within the visible area, the corresponding events will be triggered. + // If the move changes the visibility of items within the visible area, the corresponding events will be triggered. Otherwise, no event is triggered. OH_ArkUI_NodeAdapter_MoveItem(handle_, oldIndex, newIndex); } @@ -112,7 +117,7 @@ The following example optimizes the code in the [Integrating with ArkTS Pages](n private: static void OnStaticAdapterEvent(ArkUI_NodeAdapterEvent *event) { - // Obtain the instance object and invoke its event callback. + // Obtain the instance object and invoke the instance event callback. auto itemAdapter = reinterpret_cast(OH_ArkUI_NodeAdapterEvent_GetUserData(event)); itemAdapter->OnAdapterEvent(event); } @@ -152,10 +157,10 @@ The following example optimizes the code in the [Integrating with ArkTS Pages](n auto textItem = std::dynamic_pointer_cast(recycledItem->GetChildren().back()); textItem->SetTextContent(data_[index]); handle = recycledItem->GetHandle(); - // Release the reference from the cache. + // Release the reference in the cache pool. cachedItems_.pop(); } else { - // Create a new item. + // Create an element. auto listItem = std::make_shared(); auto textNode = std::make_shared(); textNode->SetTextContent(data_[index]); @@ -167,10 +172,10 @@ The following example optimizes the code in the [Integrating with ArkTS Pages](n listItem->AddChild(textNode); listItem->RegisterOnClick([index]() { OH_LOG_INFO(LOG_APP, "on %{public}d list item click", index); }); handle = listItem->GetHandle(); - // Keep a reference to the text list item. + // Maintain a reference to the text list item. items_.emplace(handle, listItem); } - // Set the item to be displayed. + // Set the element to be displayed. OH_ArkUI_NodeAdapterEvent_SetItem(event, handle); } @@ -198,10 +203,12 @@ The following example optimizes the code in the [Integrating with ArkTS Pages](n #endif // MYAPPLICATION_ARKUILISTITEMADAPTER_H ``` -3. Enhance the encapsulated list class object used in the [Integrating with ArkTS Pages](ndk-access-the-arkts-page.md) section with additional lazy loading capabilities. - ``` +### Applying the Lazy Loading Adapter in a List + +1. Add the **SetLazyAdapter** function in **ArkUIListNode** to set the **NODE_LIST_NODE_ADAPTER** attribute for the list node and pass the **NodeAdapter** as an attribute parameter. + ```c++ // ArkUIListNode.h - // Encapsulated list class object. + // List encapsulation object. #ifndef MYAPPLICATION_ARKUILISTNODE_H #define MYAPPLICATION_ARKUILISTNODE_H @@ -219,7 +226,7 @@ The following example optimizes the code in the [Integrating with ArkTS Pages](n ~ArkUIListNode() override { nativeModule_->unregisterNodeEvent(handle_, NODE_LIST_ON_SCROLL_INDEX); if (adapter_) { - // Unmount UI components associated with the adapter upon destruction. + // Unload the UI components under the adapter during destruction. nativeModule_->resetAttribute(handle_, NODE_LIST_NODE_ADAPTER); adapter_.reset(); } @@ -272,72 +279,29 @@ The following example optimizes the code in the [Integrating with ArkTS Pages](n #endif // MYAPPLICATION_ARKUILISTNODE_H ``` -4. Write code for lazy loading of a list. - ``` - // ArkUILazyTextListExample - // Sample code for lazy loading a list. +2. Create example code for a **List** using lazy loading and call the **SetLazyAdapter** API of the **List** node to set the lazy loading adapter. + ```c++ + // LazyTextListExample + // Example code for a lazy loading text list. #ifndef MYAPPLICATION_LAZYTEXTLISTEXAMPLE_H #define MYAPPLICATION_LAZYTEXTLISTEXAMPLE_H #include "ArkUIBaseNode.h" #include "ArkUIListNode.h" - #include "UITimer.h" - #include - #include + namespace NativeModule { std::shared_ptr CreateLazyTextListExample(napi_env env) { - // Create components and mount them. + // Create and mount the component. // 1: Create a List component. auto list = std::make_shared(); list->SetPercentWidth(1); list->SetPercentHeight(1); - // 2: Create ListItem child components for lazy loading and mount them to the List component. + // 2: Create a ListItem child component for lazy loading and mount it to the List component. auto adapter = std::make_shared(); list->SetLazyAdapter(adapter); - - // 3: Simulate lazy loading operations. - CreateNativeTimer(env, adapter.get(), 4, [](void *userdata, int32_t count) { - auto adapter = reinterpret_cast(userdata); - switch (count) { - case 0: { - // Remove the 0th item. - adapter->RemoveItem(0); - break; - } - case 1: { - // Insert the 0th item. - adapter->InsertItem(0, "0"); - break; - } - case 2: { - // Move an item to a new position. - adapter->MoveItem(0, 2); - break; - } - case 3: { - // Reload a single item. - adapter->ReloadItem(0, "1112"); - break; - } - case 4: { - // Reload all items. - adapter->ReloadAllItem(); - break; - } - default: { - } - } - }); - - // 3: Register list-related listening events. - list->RegisterOnScrollIndex([](int32_t index) { OH_LOG_INFO(LOG_APP, "on list scroll index: %{public}d", index); }); - // 4: Register the appear event. - list->RegisterOnAppear([]() { OH_LOG_INFO(LOG_APP, "on list mount to tree"); }); - // 4: Register the disappear event. - list->RegisterOnDisappear([]() { OH_LOG_INFO(LOG_APP, "on list unmount from tree"); }); return list; } } // namespace NativeModule @@ -345,84 +309,9 @@ The following example optimizes the code in the [Integrating with ArkTS Pages](n #endif // MYAPPLICATION_LAZYTEXTLISTEXAMPLE_H ``` -5. Implement a simple timer module. - ``` - // UITimer.h - // Timer module. - - #ifndef MYAPPLICATION_UITIMER_H - #define MYAPPLICATION_UITIMER_H - - #include - #include - #include - #include - #include - #include - #include - #include - - namespace NativeModule { - - struct UIData { - void *userData = nullptr; - int32_t count = 0; - int32_t totalCount = 0; - void (*func)(void *userData, int32_t count) = nullptr; - }; - - napi_threadsafe_function threadSafeFunction = nullptr; - - void CreateNativeTimer(napi_env env, void *userData, int32_t totalCount, void (*func)(void *userData, int32_t count)) { - napi_value name; - std::string str = "UICallback"; - napi_create_string_utf8(env, str.c_str(), str.size(), &name); - // UI main thread callback function. - napi_create_threadsafe_function( - env, nullptr, nullptr, name, 0, 1, nullptr, nullptr, nullptr, - [](napi_env env, napi_value value, void *context, void *data) { - auto userdata = reinterpret_cast(data); - userdata->func(userdata->userData, userdata->count); - delete userdata; - }, - &threadSafeFunction); - // Start the timer to simulate data changes. - std::thread timerThread([data = userData, totalCount, func]() { - uv_loop_t *loop = uv_loop_new(); - uv_timer_t *timer = new uv_timer_t(); - uv_timer_init(loop, timer); - timer->data = new UIData{data, 0, totalCount, func}; - uv_timer_start( - timer, - [](uv_timer_t *handle) { - OH_LOG_INFO(LOG_APP, "on timeout"); - napi_acquire_threadsafe_function(threadSafeFunction); - auto *customData = reinterpret_cast(handle->data); - // Create callback data. - auto *callbackData = - new UIData{customData->userData, customData->count, customData->totalCount, customData->func}; - napi_call_threadsafe_function(threadSafeFunction, callbackData, napi_tsfn_blocking); - customData->count++; - if (customData->count > customData->totalCount) { - uv_timer_stop(handle); - delete handle; - delete customData; - } - }, - 4000, 4000); - uv_run(loop, UV_RUN_DEFAULT); - uv_loop_delete(loop); - }); - timerThread.detach(); - } - } // namespace NativeModule - - #endif // MYAPPLICATION_UITIMER_H - ``` - -6. Mount the lazy loading example code onto the **ContentSlot** as described in the [Integrating with ArkTS Pages](ndk-access-the-arkts-page.md) section. - ``` - // NDK API entry mount file. +3. Call the **List** lazy loading example code in **NativeEntry.cpp**. + ```c++ + // NDK API entry mounting file. #include "NativeEntry.h" @@ -437,11 +326,7 @@ The following example optimizes the code in the [Integrating with ArkTS Pages](n #include namespace NativeModule { - namespace { - napi_env g_env; - } - napi_env GetNapiEnv() { return g_env; } napi_value CreateNativeRoot(napi_env env, napi_callback_info info) { size_t argc = 1; @@ -454,20 +339,285 @@ The following example optimizes the code in the [Integrating with ArkTS Pages](n OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); NativeEntry::GetInstance()->SetContentHandle(contentHandle); - // Create a lazy-loaded text list. + // Create a lazy loading text list. auto node = CreateLazyTextListExample(env); - // Keep the native side object in the management class to maintain its lifecycle. + // Keep the native-side object in the management class to maintain its lifecycle. NativeEntry::GetInstance()->SetRootNode(node); g_env = env; return nullptr; } napi_value DestroyNativeRoot(napi_env env, napi_callback_info info) { - // Release the native side object from the management class. + // Release the native-side object from the management class. NativeEntry::GetInstance()->DisposeRootNode(); return nullptr; } } // namespace NativeModule ``` +## Controlling the List Scroll Position + +1. Control the list to scroll to a specified offset position. + ```c++ + //ArkUIListNode.h + // List encapsulation object. + class ArkUIListNode: public ArkUINode { + //... + void ScrollTo(float offset) { + ArkUI_NumberValue value[] = {{.f32 =0},{.f32 = offset},{.f32 = 0}}; + ArkUI_AttributeItem Item = {.value = value,.size = 3}; + nativeModule_->setAttribute(handle_, NODE_SCROLL_OFFSET, &Item); + } + }; + ``` +2. Control the list to scroll to a specified element. + ```c++ + //ArkUIListNode.h + // List encapsulation object. + class ArkUIListNode : public ArkUINode { + //... + void ScrollToIndex(int32_t index) { + ArkUI_NumberValue value[] = {{.i32 = index}}; + ArkUI_AttributeItem Item = {.value = value, .size = 1}; + nativeModule_->setAttribute(handle_, NODE_LIST_SCROLL_TO_INDEX, &Item); + } + }; + ``` + +3. Control the list to scroll by a specified offset. + ```c++ + //ArkUIListNode.h + // List encapsulation object. + class ArkUIListNode : public ArkUINode { + void ScrollBy(float offset) { + ArkUI_NumberValue value[] = {{.f32 =0},{.f32 = offset}}; + ArkUI_AttributeItem Item = {.value = value, .size = 2}; + nativeModule_->setAttribute(handle_, NODE_SCROLL_BY, &Item); + } + }; + ``` +## Implementing Swipe-to-Delete for List Items + +1. Set the **NODE_LIST_ITEM_SWIPE_ACTION** attribute for **ListItem** and pass the **ArkUI_ListItemSwipeActionOption** object as an attribute parameter. + ```c++ + // ArkUIListItemNode.h + // Encapsulation class for list items. + #ifndef MYAPPLICATION_ARKUISTACKNODE_H + #define MYAPPLICATION_ARKUISTACKNODE_H + #include "ArkUINode.h" + namespace NativeModule{ + class ArkUIListItemNode : public ArkUINode { + public: + ArkUIListItemNode() + : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_LIST_ITEM)) {} + ~ArkUIListItemNode() { + if(swipeAction_) { + OH_ArkUI_ListItemSwipeActionOption_Dispose(swipeAction_); + } + if (swipeItem_) { + OH_ArkUI_ListItemSwipeActionItem_Dispose(swipeItem_); + } + } + void SetSwiperAction(std::shared_ptr node) { + swipeContent_ = node; + swipeItem_ = OH_ArkUI_ListItemSwipeActionItem_Create(); + OH_ArkUI_ListItemSwipeActionItem_SetContent(swipeItem_, node->GetHandle()); + swipeAction_ = OH_ArkUI_ListItemSwipeActionOption_Create(); + OH_ArkUI_ListItemSwipeActionOption_SetEnd(swipeAction_, swipeItem_); + ArkUI_AttributeItem Item = {.object= swipeAction_ }; + nativeModule_->setAttribute(handle_,NODE_LIST_ITEM_SWIPE_ACTION, &Item); + } + std::shared_ptr GetSwipeContent() const { + return swipeContent_; + } + private: + ArkUI_ListItemSwipeActionOption* swipeAction_ = nullptr; + ArkUI_ListItemSwipeActionItem* swipeItem_ = nullptr; + std::shared_ptr swipeContent_ = nullptr; + }; + }// namespace NativeModule + #endif// MYAPPLICATION_ARKUISTACKNODE_H + ``` + +2. When creating a **ListItem**, create the swipe action item for the **ListItem** and bind a click event to perform the data source deletion operation in the click event. When reusing a **ListItem**, update the binding event of the swipe action item. + ```c++ + // ArkUIListItemAdapter.h + class ArkUIListItemAdapter { + //... + // Handle the display of new items in the visible area. + void OnNewItemAttached(ArkUI_NodeAdapterEvent *event) { + auto index = OH_ArkUI_NodeAdapterEvent_GetItemIndex(event); + ArkUI_NodeHandle handle = nullptr; + if (!cachedItems_.empty()) { + // Use and update the recycled cache. + auto recycledItem = cachedItems_.top(); + auto textItem = std::dynamic_pointer_cast(recycledItem->GetChildren().back()); + textItem->SetTextContent(data_[index]); + handle = recycledItem->GetHandle(); + auto swipeContent = recycledItem->GetSwipeContent(); + swipeContent->RegisterOnClick([this, data = data_[index]]() { + auto it = std::find(data_.begin(), data_.end(), data); + if (it != data_.end()) { + auto index = std::distance(data_.begin(), it); + RemoveItem(index); + } + }); + // Release the reference in the cache pool. + cachedItems_.pop(); + } else { + // Create an element. + auto listItem = std::make_shared(); + auto textNode = std::make_shared(); + textNode->SetTextContent(data_[index]); + textNode->SetFontSize(16); + textNode->SetPercentWidth(1); + textNode->SetHeight(100); + textNode->SetBackgroundColor(0xFFfffacd); + textNode->SetTextAlign(ARKUI_TEXT_ALIGNMENT_CENTER); + listItem->AddChild(textNode); + // Create the swipe action item for the ListItem. + auto swipeNode = std::make_shared(); + swipeNode->SetTextContent("del"); + swipeNode->SetFontSize(16); + swipeNode->SetFontColor(0xFFFFFFFF); + swipeNode->SetWidth(100); + swipeNode->SetHeight(100); + swipeNode->SetBackgroundColor(0xFFFF0000); + swipeNode->SetTextAlign(ARKUI_TEXT_ALIGNMENT_CENTER); + swipeNode->RegisterOnClick([this, data = data_[index]]() { + auto it = std::find(data_.begin(), data_.end(), data); + if (it != data_.end()) { + auto index = std::distance(data_.begin(), it); + RemoveItem(index); + } + }); + listItem->SetSwiperAction(swipeNode); + handle = listItem->GetHandle(); + // Maintain a reference to the text list item. + items_.emplace(handle, listItem); + } + // Set the element to be displayed. + OH_ArkUI_NodeAdapterEvent_SetItem(event, handle); + } + } + ``` +3. Add **RemoveItem** in **ArkUIListItemAdapter** to delete the data source and call the **OH_ArkUI_NodeAdapter_RemoveItem** API to instruct the framework to update the UI. + ```c++ + // ArkUIListItemAdapter.h + class ArkUIListItemAdapter { + //... + void RemoveItem(size_t index) { + // Remove the item at the specified index. + data_.erase(data_.begin() + index); + // If the index change affects the visibility of items in the visible area, the NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER event will be triggered to remove the element. + // Depending on whether there are new elements, the NODE_ADAPTER_EVENT_ON_GET_NODE_ID or NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER event will be triggered. + OH_ArkUI_NodeAdapter_RemoveItem(handle_, index, 1); + // Update the total count. + OH_ArkUI_NodeAdapter_SetTotalNodeCount(handle_, data_.size()); + } + }; + ``` +## Using a Grouped List +1. Implement a grouped list using the **ListItemGroup** component, which supports features to add headers and footers and use lazy loading. + ```c++ + // ArkUIListItemGroupNode.h + + #ifndef MYAPPLICATION_ARKUILISTITEMGROUPNODE_H + #define MYAPPLICATION_ARKUILISTITEMGROUPNODE_H + #include "ArkUINode.h" + #include "ArkUIListItemAdapter.h" + namespace NativeModule{ + class ArkUIListItemGroupNode : public ArkUINode { + public: + ArkUIListItemGroupNode() + : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_LIST_ITEM_GROUP)) {} + void SetHeader(std::shared_ptr node) { + if (node) { + ArkUI_AttributeItem Item = {.object = node->GetHandle()}; + nativeModule_->setAttribute(handle_, NODE_LIST_ITEM_GROUP_SET_HEADER, &Item); + } else { + nativeModule_->resetAttribute(handle_, NODE_LIST_ITEM_GROUP_SET_HEADER); + } + } + void SetFooter(std::shared_ptr node) { + if (node) { + ArkUI_AttributeItem Item = {.object= node->GetHandle()}; + nativeModule_->setAttribute(handle_, NODE_LIST_ITEM_GROUP_SET_FOOTER, &Item); + } else { + nativeModule_->resetAttribute(handle_, NODE_LIST_ITEM_GROUP_SET_FOOTER); + } + } + std::shared_ptr GetHeader() const { + return header_; + } + std::shared_ptr GetFooter() const { + return footer_; + } + // Import the lazy loading module. + void SetLazyAdapter(const std::shared_ptr &adapter) { + assert(handle_); + ArkUI_AttributeItem item{nullptr,0, nullptr, adapter->GetHandle()}; + nativeModule_->setAttribute(handle_, NODE_LIST_ITEM_GROUP_NODE_ADAPTER, &item); + adapter_ = adapter; + } + private: + std::shared_ptr header_; + std::shared_ptr footer_; + std::shared_ptr adapter_; + }; + }// namespace NativeModule + #endif//MYAPPLICATION_ARKUILISTITEMGROUPNODE_H + ``` +2. Set the sticky header for the **List** component. + ```c++ + // ArkUIListNode.h + // List encapsulation object. + class ArkUIListNode : public ArkUINode{ + //... + void SetSticky(ArkUI_StickyStyle style) { + assert(handle_); + ArkUI_NumberValue value[] = {{.i32 = style}}; + ArkUI_AttributeItem item = {value, 1}; + nativeModule_->setAttribute(handle_, NODE_LIST_STICKY, &item); + } + }; + ``` +3. Implement a grouped list UI using **ListItemGroup** under the **List** component. + ```c++ + // LazyTextListExample.h + // Example code for a lazy loading text list. + #ifndef MYAPPLICATION_LAZYTEXTLISTEXAMPLE_H + #define MYAPPLICATION_LAZYTEXTLISTEXAMPLE_H + #include "ArkUIBaseNode.h" + #include "ArkUIListNode.h" + #include "ArkUIListItemGroupNode.h" + namespace NativeModule { + std::shared_ptr CreateLazyTextListExample() { + // Create and mount the component. + // 1: Create a List component. + auto list = std::make_shared(); + list->SetPercentWidth(1); + list->SetPercentHeight(1); + // Set the sticky header. + list->SetSticky(ARKUI_STICKY_STYLE_BOTH); + // 2: Create a ListItemGroup and mount it to the List. + for (int32_t i = 0; i < 3; i++) { + auto header = std::make_shared(); + header->SetTextContent("header"); + header->SetFontSize(16); + header->SetPercentWidth(1); + header->SetHeight(50); + header->SetBackgroundColor(0xFFDCDCDC); + header->SetTextAlign(ARKUI_TEXT_ALIGNMENT_CENTER); + auto listItemGroup = std::make_shared(); + listItemGroup->SetHeader(header); + auto adapter = std::make_shared(4); + listItemGroup->SetLazyAdapter(adapter); + list->AddChild(listItemGroup); + } + return list; + } + }// namespace NativeModule + #endif// MYAPPLICATION_LAZYTEXTLISTEXAMPLE_H + ``` diff --git a/en/application-dev/ui/ndk-styled-string.md b/en/application-dev/ui/ndk-styled-string.md new file mode 100644 index 0000000000000000000000000000000000000000..3963873bc970723b38182441decd45c0044a7e36 --- /dev/null +++ b/en/application-dev/ui/ndk-styled-string.md @@ -0,0 +1,192 @@ +# Drawing and Displaying Text in Text Components +Some frameworks or applications have their own text layout capabilities, which are integrated into the [ArkGraphics2D text engine](../graphics/complex-text-c.md) during porting. To avoid the need for redeveloping text components, the **Text** component provides the [NODE_TEXT_CONTENT_WITH_STYLED_STRING](../../application-dev/reference/apis-arkui/_ark_u_i___native_module.md) API, which can directly render text generated by the Ark text engine. + +The following, based on the [Integrating with ArkTS Pages](../ui/ndk-access-the-arkts-page.md) section, explains how to create text engine text and use the **Text** component for rendering and display. + +> **NOTE** +> +> For APIs involving the font engine, add **target_link_libraries(entry PUBLIC libnative_drawing.so)** to **CMakeLists.txt**; otherwise, a linking error will occur. + +## Creating a Text Component + +Since text styles are set through font engine APIs, there is no need to configure style attributes such as text color and font size when creating a **Text** component. However, basic universal attributes such as width and height still need to be set. +```c++ +ArkUI_NativeNodeAPI_1 *nodeApi = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); +if (nodeApi == nullptr) { + return; +} +ArkUI_NodeHandle text = nodeApi->createNode(ARKUI_NODE_TEXT); +// Set the width. +ArkUI_NumberValue textWidth[] = {{.f32 = 300}}; +ArkUI_AttributeItem textWidthItem = {.value = textWidth, .size = 1}; +nodeApi->setAttribute(text, NODE_WIDTH, &textWidthItem); +// Set the height. +ArkUI_NumberValue textHeight[] = {{.f32 = 100}}; +ArkUI_AttributeItem textHeightItem = {.value = textHeight, .size = 1}; +nodeApi->setAttribute(text, NODE_HEIGHT, &textHeightItem); +``` +## Setting Paragraph and Text Styles + +- Setting the Paragraph Style + + The paragraph style defines the overall attributes of a paragraph of text, such as the maximum number of display lines and text direction. The following code example sets text centering and a maximum line limit of 10. + + > **NOTE** + > + > The **OH_Drawing_** prefixed APIs are provided by the Ark text engine. For details, see [Simple Text Drawing and Display (C/C++)++)](../graphics/simple-text-c.md) and [Complex Text Drawing and Display (C/C++)](../graphics/complex-text-c.md). + ```c++ + OH_Drawing_TypographyStyle *typographyStyle = OH_Drawing_CreateTypographyStyle(); + OH_Drawing_SetTypographyTextAlign(typographyStyle, OH_Drawing_TextAlign::TEXT_ALIGN_CENTER); + OH_Drawing_SetTypographyTextMaxLines(typographyStyle, 10); + ``` +- Setting the Text Style + + Different text contents can have different text styles, but the following three APIs must be called in the specified order; otherwise, they will not take effect. + + 1. **OH_ArkUI_StyledString_PushTextStyle**: pushes the text style onto the stack. + 2. **OH_ArkUI_StyledString_AddText**: adds the text content to which the style will be applied. + 3. **OH_ArkUI_StyledString_PopTextStyle**: pops the text style from the stack. + + > **NOTE** + > + > The **OH_ArkUI_StyledString_** prefixed APIs are provided by the **Text** component. + > + > The **OH_Drawing_** prefixed APIs are provided by the Ark text engine. For details, see [Simple Text Drawing and Display (C/C++)++)](../graphics/simple-text-c.md)、[Complex Text Drawing and Display (C/C++)](../graphics/complex-text-c.md). + + Create a text style with **OH_Drawing_CreateTextStyle**. Set the font size of **"Hello"** to 28 px and the color to **0xFF707070**. Set the font size of **"World!"** to 28 px and the color to **0xFF2787D9**. + ```c++ + ArkUI_StyledString *styledString = OH_ArkUI_StyledString_Create(typographyStyle,OH_Drawing_CreateFontCollection()); + + OH_Drawing_TextStyle *helloStyle = OH_Drawing_CreateTextStyle(); + // Set the font size. + OH_Drawing_SetTextStyleFontSize(helloStyle, 28); + // Set the color + OH_Drawing_SetTextStyleColor(helloStyle, OH_Drawing_ColorSetArgb(0xFF, 0x70, 0x70, 0x70)); + OH_ArkUI_StyledString_PushTextStyle(styledString, helloStyle); + OH_ArkUI_StyledString_AddText(styledString, "Hello"); + OH_ArkUI_StyledString_PopTextStyle(styledString); + + OH_Drawing_TextStyle *worldTextStyle = OH_Drawing_CreateTextStyle(); + OH_Drawing_SetTextStyleFontSize(worldTextStyle, 28); + OH_Drawing_SetTextStyleColor(worldTextStyle, OH_Drawing_ColorSetArgb(0xFF, 0x27,0x87, 0xD9)); + OH_ArkUI_StyledString_PushTextStyle(styledString, worldTextStyle); + OH_ArkUI_StyledString_AddText(styledString, "World!"); + OH_ArkUI_StyledString_PopTextStyle(styledString); + ``` +## Adding a Placeholder +A placeholder reserves a blank area of a specified size in the middle of text. No text is drawn in this area, but it still participates in text layout measurement. Therefore, its size affects text typesetting. +> **NOTE** +> +> The relative position of the placeholder and text is determined by the execution order of **OH_ArkUI_StyledString_AddPlaceholder**. + +```c++ +OH_Drawing_PlaceholderSpan placeHolder{ + .width = 100, + .height = 100, +}; +OH_ArkUI_StyledString_AddPlaceholder(styledString, placeHolder); +``` +## Implementing Text Layout and Drawing +- Text Layout + + After setting the text style and content, call the text engine API **OH_Drawing_TypographyLayout** to lay out the text, and pass in a specified width representing the maximum value for the text. + + > **NOTE** + > + > Text that has not been laid out is not displayed. + + ```c++ + OH_Drawing_Typography *typography = OH_ArkUI_StyledString_CreateTypography(styledString); + OH_Drawing_TypographyLayout(typography, 400); + ``` + +- Text Drawing + + Text drawing is completed through interaction between the text engine and graphics, requiring no additional settings. The **Text** component will call the text engine drawing API when the component triggers drawing under the ArkUI rendering mechanism. Here, only the created **StyledString** object needs to be passed to the created **Text** component. + ```c++ + ArkUI_AttributeItem styledStringItem = {.object = styledString}; + nodeApi->setAttribute(text, NODE_TEXT_CONTENT_WITH_STYLED_STRING, &styledStringItem); + ``` + +## Destroying an Object + +The **Text** component does not manage the lifecycle of any objects involved in this process. You are responsible for this. + +The text engine APIs involved all have corresponding destruction methods. + +**OH_Drawing_DestroyTextStyle(OH_Drawing_TextStyle *style)**: destroys the text style object. + +**OH_Drawing_DestroyTypographyStyle(OH_Drawing_TypographyStyle *style)**: destroys the paragraph style object. + +For details about more text engine destruction APIs, see [Simple Text Drawing and Display (C/C++)++)](../graphics/simple-text-c.md)、[Complex Text Drawing and Display (C/C++)](../graphics/complex-text-c.md). + +The **Text** component provides **OH_ArkUI_StyledString_Destroy** to destroy the styled string object. + +## Sample +```c++ +void CreateNativeNode() { + ArkUI_NativeNodeAPI_1 *nodeApi = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); + if (nodeApi == nullptr) { + return; + } + // Create a Column container component. + ArkUI_NodeHandle column = nodeApi->createNode(ARKUI_NODE_COLUMN); + ArkUI_NumberValue colWidth[] = {{.f32 = 300}}; + ArkUI_AttributeItem widthItem = {.value = colWidth, .size = 1}; + nodeApi->setAttribute(column, NODE_WIDTH, &widthItem); + // Create a Text component. + ArkUI_NodeHandle text = nodeApi->createNode(ARKUI_NODE_TEXT); + ArkUI_NumberValue textWidth[] = {{.f32 = 300}}; + ArkUI_AttributeItem textWidthItem = {.value = textWidth, .size = 1}; + nodeApi->setAttribute(text, NODE_WIDTH, &textWidthItem); + + ArkUI_NumberValue textHeight[] = {{.f32 = 100}}; + ArkUI_AttributeItem textHeightItem = {.value = textHeight, .size = 1}; + nodeApi->setAttribute(text, NODE_HEIGHT, &textHeightItem); + + ArkUI_NumberValue borderWidth[] = {{.f32 = 1}}; + ArkUI_AttributeItem borderWidthItem = {.value = borderWidth, .size = 1}; + nodeApi->setAttribute(text, NODE_BORDER_WIDTH, &borderWidthItem); + + // typographyStyle represents the paragraph style. + OH_Drawing_TypographyStyle *typographyStyle = OH_Drawing_CreateTypographyStyle(); + // Center the text. + OH_Drawing_SetTypographyTextAlign(typographyStyle, OH_Drawing_TextAlign::TEXT_ALIGN_CENTER); + OH_Drawing_SetTypographyTextMaxLines(typographyStyle, 10); + ArkUI_StyledString *styledString = OH_ArkUI_StyledString_Create(typographyStyle, OH_Drawing_CreateFontCollection()); + // Create a text style and set the font and color. + OH_Drawing_TextStyle *textStyle = OH_Drawing_CreateTextStyle(); + OH_Drawing_SetTextStyleFontSize(textStyle, 28); + OH_Drawing_SetTextStyleColor(textStyle, OH_Drawing_ColorSetArgb(0xFF, 0x70, 0x70, 0x70)); + // The setting order of text styles matters. + OH_ArkUI_StyledString_PushTextStyle(styledString, textStyle); + OH_ArkUI_StyledString_AddText(styledString, "Hello"); + OH_ArkUI_StyledString_PopTextStyle(styledString); + // Insert a 100 x 100 placeholder between "Hello" and "World!" + OH_Drawing_PlaceholderSpan placeHolder{ + .width = 100, + .height = 100, + }; + OH_ArkUI_StyledString_AddPlaceholder(styledString, &placeHolder); + OH_Drawing_TextStyle *worldTextStyle = OH_Drawing_CreateTextStyle(); + OH_Drawing_SetTextStyleFontSize(worldTextStyle, 28); + OH_Drawing_SetTextStyleColor(worldTextStyle, OH_Drawing_ColorSetArgb(0xFF, 0x27, 0x87, 0xD9)); + OH_ArkUI_StyledString_PushTextStyle(styledString, worldTextStyle); + OH_ArkUI_StyledString_AddText(styledString, "World!"); + OH_ArkUI_StyledString_PopTextStyle(styledString); + OH_Drawing_Typography *typography = OH_ArkUI_StyledString_CreateTypography(styledString); + OH_Drawing_TypographyLayout(typography, 400); + ArkUI_AttributeItem styledStringItem = {.object = styledString}; + nodeApi->setAttribute(text, NODE_TEXT_CONTENT_WITH_STYLED_STRING, &styledStringItem); + + OH_ArkUI_StyledString_Destroy(styledString); + // Add Text as a child component of Column. + nodeApi->addChild(column, text); + // Add Column as a child component of XComponent. + OH_NativeXComponent_AttachNativeRootNode(xComponent, column); +} +``` + +![ndk_text_styled_string](figures/ndk_text_styled_string.png) diff --git a/en/application-dev/ui/ndk-textarea-event.md b/en/application-dev/ui/ndk-textarea-event.md new file mode 100644 index 0000000000000000000000000000000000000000..d9c4fa0ddabeeaaad744dac084ef938d4926a227 --- /dev/null +++ b/en/application-dev/ui/ndk-textarea-event.md @@ -0,0 +1,136 @@ +# Listening for Text Box Events + +Text boxes support various interactive behaviors, allowing you to register event listeners and obtain status information. + +Real-time search: Register the [NODE_TEXT_AREA_ON_CHANGE](../../application-dev/reference/apis-arkui/_ark_u_i___native_module.md) event to receive notifications and obtain the current text content when the text box input changes. + +Text filtering: Register the [NODE_TEXT_AREA_ON_WILL_INSERT](../../application-dev/reference/apis-arkui/_ark_u_i___native_module.md) event to receive notifications before text is inserted and control whether to insert text through the return value. + +Layout changes during editing: Register the [NODE_TEXT_AREA_ON_EDIT_CHANGE](../../application-dev/reference/apis-arkui/_ark_u_i___native_module.md) event to receive notifications when the text box editing state changes. + +The following example demonstrates how to listen for text box events and parse data based on the [Integrating with ArkTS Pages](../ui/ndk-access-the-arkts-page.md) section. + +- Registering Events + + Events are registered through a unified API. For details, see [registerNodeEvent](../../application-dev/reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#registernodeevent). For details about the event types supported by the text box, see the [ArkUI_NodeEventType](../../application-dev/reference/apis-arkui/_ark_u_i___native_module.md) section, searching for **NODE_TEXT_AREA_**. + + ```c++ + // Create two text components to display the information received in events. + ArkUI_NodeHandle text = nodeApi->createNode(ARKUI_NODE_TEXT); + ArkUI_NumberValue textWidth[] = {{.f32 = 300}}; + ArkUI_AttributeItem textWidthItem = {.value = textWidth, .size = 1}; + nodeApi->setAttribute(text, NODE_WIDTH, &textWidthItem); + + ArkUI_NodeHandle selectionText = nodeApi->createNode(ARKUI_NODE_TEXT); + ArkUI_NumberValue selectionTextWidth[] = {{.f32 = 300}}; + ArkUI_AttributeItem selectionTextWidthItem = {.value = selectionTextWidth, .size = 1}; + nodeApi->setAttribute(selectionText, NODE_WIDTH, &selectionTextWidthItem); + + const ArkUI_AttributeItem *attributeItem = nodeApi->getAttribute(textArea, NODE_UNIQUE_ID); + // Use the component ID as the target ID to distinguish events from different components. + auto id = attributeItem->value[0].i32; + // Register the text change event. + nodeApi->registerNodeEvent(textArea, NODE_TEXT_AREA_ON_CHANGE, id, text); + // Register the paste event. + nodeApi->registerNodeEvent(textArea, NODE_TEXT_AREA_ON_PASTE, id, text); + // Register the text selection event. + nodeApi->registerNodeEvent(textArea, NODE_TEXT_AREA_ON_TEXT_SELECTION_CHANGE, id, selectionText); + ``` + +- Registering Event Callbacks + + Event callbacks are registered through a unified API. For details, see [registerNodeEventReceiver](../../application-dev/reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#registernodeeventreceiver). + + ```c++ + nodeApi->registerNodeEventReceiver([](ArkUI_NodeEvent *event) { + ArkUI_NodeEventType eventType = OH_ArkUI_NodeEvent_GetEventType(event); + ArkUI_AttributeItem content; + // Text content change event and paste event + if (eventType == NODE_TEXT_AREA_ON_CHANGE || eventType == NODE_TEXT_AREA_ON_PASTE) { + // Obtain the text content. + ArkUI_StringAsyncEvent *stringEvent = OH_ArkUI_NodeEvent_GetStringAsyncEvent(event); + content = {.string = stringEvent->pStr }; + } else if (eventType == NODE_TEXT_AREA_ON_TEXT_SELECTION_CHANGE) { + //Obtain the indices of the selected text (start and end indices) to obtain the selected text. + ArkUI_NodeComponentEvent *componentEvent = OH_ArkUI_NodeEvent_GetNodeComponentEvent(event); + std::stringstream selectContent; + selectContent << "start: " << componentEvent->data[0].i32 << " , end: " << componentEvent->data[1].i32; + content = {.string = selectContent.str().c_str() }; + } else { + return; + } + ArkUI_NodeHandle textNode = reinterpret_cast(OH_ArkUI_NodeEvent_GetUserData(event)); + if (textNode) { + // Display the text information on the Text component. + ArkUI_NativeNodeAPI_1 *nodeApi = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); + nodeApi->setAttribute(textNode, NODE_TEXT_CONTENT, &content); + } + }); + ``` +- Sample + ```c++ + void NodeManager::CreateTextAreaNode() { + ArkUI_NativeNodeAPI_1 *nodeApi = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); + if (nodeApi == nullptr) { + return; + } + ArkUI_NodeHandle column = nodeApi->createNode(ARKUI_NODE_COLUMN); + ArkUI_NumberValue colWidth[] = {{.f32 = 300}}; + ArkUI_AttributeItem widthItem = {.value = colWidth, .size = 1}; + nodeApi->setAttribute(column, NODE_WIDTH, &widthItem); + + ArkUI_NodeHandle text = nodeApi->createNode(ARKUI_NODE_TEXT); + ArkUI_NumberValue textWidth[] = {{.f32 = 300}}; + ArkUI_AttributeItem textWidthItem = {.value = textWidth, .size = 1}; + nodeApi->setAttribute(text, NODE_WIDTH, &textWidthItem); + nodeApi->addChild(column, text); + + ArkUI_NodeHandle selectionText = nodeApi->createNode(ARKUI_NODE_TEXT); + ArkUI_NumberValue selectionTextWidth[] = {{.f32 = 300}}; + ArkUI_AttributeItem selectionTextWidthItem = {.value = selectionTextWidth, .size = 1}; + nodeApi->setAttribute(selectionText, NODE_WIDTH, &selectionTextWidthItem); + nodeApi->addChild(column, selectionText); + + ArkUI_NodeHandle textArea = nodeApi->createNode(ARKUI_NODE_TEXT_AREA); + ArkUI_NumberValue textAreaWidth[] = {{.f32 = 300}}; + ArkUI_AttributeItem textAreaWidthItem = {.value = textAreaWidth, .size = 1}; + nodeApi->setAttribute(textArea, NODE_WIDTH, &textAreaWidthItem); + + ArkUI_NumberValue borderWidth[] = {{.f32 = 1}}; + ArkUI_AttributeItem borderWidthItem = {.value = borderWidth, .size = 1}; + nodeApi->setAttribute(textArea, NODE_BORDER_WIDTH, &borderWidthItem); + + const ArkUI_AttributeItem *attributeItem = nodeApi->getAttribute(textArea, NODE_UNIQUE_ID); + auto id = attributeItem->value[0].i32; + nodeApi->registerNodeEvent(textArea, NODE_TEXT_AREA_ON_CHANGE, id, text); + nodeApi->registerNodeEvent(textArea, NODE_TEXT_AREA_ON_PASTE, id, text); + nodeApi->registerNodeEvent(textArea, NODE_TEXT_AREA_ON_TEXT_SELECTION_CHANGE, id, selectionText); + nodeApi->registerNodeEventReceiver([](ArkUI_NodeEvent *event) { + ArkUI_NodeEventType eventType = OH_ArkUI_NodeEvent_GetEventType(event); + ArkUI_AttributeItem content; + if (eventType == NODE_TEXT_AREA_ON_CHANGE || eventType == NODE_TEXT_AREA_ON_PASTE) { + ArkUI_StringAsyncEvent *stringEvent = OH_ArkUI_NodeEvent_GetStringAsyncEvent(event); + content = {.string = stringEvent->pStr }; + } else if (eventType == NODE_TEXT_AREA_ON_TEXT_SELECTION_CHANGE) { + ArkUI_NodeComponentEvent *componentEvent = OH_ArkUI_NodeEvent_GetNodeComponentEvent(event); + std::stringstream selectContent; + selectContent << "start: " << componentEvent->data[0].i32 << " , end: " << componentEvent->data[1].i32; + content = {.string = selectContent.str().c_str() }; + } else { + return; + } + ArkUI_NodeHandle textNode = reinterpret_cast(OH_ArkUI_NodeEvent_GetUserData(event)); + if (textNode) { + ArkUI_NativeNodeAPI_1 *nodeApi = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); + nodeApi->setAttribute(textNode, NODE_TEXT_CONTENT, &content); + } + }); + nodeApi->addChild(column, textArea); + OH_NativeXComponent_AttachNativeRootNode(xComponent, column); + } + ``` + + diff --git a/en/application-dev/ui/ndk-waterflow.md b/en/application-dev/ui/ndk-waterflow.md new file mode 100644 index 0000000000000000000000000000000000000000..41d25cfc3a28ea710c1f558f011448884f9191ae --- /dev/null +++ b/en/application-dev/ui/ndk-waterflow.md @@ -0,0 +1,368 @@ +# Implementing a Waterfall Flow Layout + +The ArkUI framework provides a waterfall flow container component through NDK APIs. This component arranges items of different sizes in a waterfall-like manner from top to bottom. + +## Integrating with ArkTS Pages +To use the NDK APIs for building UIs, follow the instructions in [Integrating with ArkTS Pages](../ui/ndk-access-the-arkts-page.md). This involves creating a placeholder component on the ArkTS page for mounting the native page and implementing the **NativeNode** module APIs on the ArkTS side. + +## Implementing Lazy Loading +### NodeAdapter Overview +The NDK provides the **NodeAdapter** object as an alternative to the **LazyForEach** functionality in ArkTS for on-demand generation of child components. For details, see [NodeAdapter Overview](../ui/ndk-loading-long-list.md#nodeadapter-overview). + +### Lazy Loading Adapter Implementation + +Use the **FlowItemAdapter** class to manage the lazy loading adapter. Create a **NodeAdapter** object in the class constructor with event listeners, and destroy it in the class destructor. + +```c++ +// FlowItemAdapter.h +// Lazy loading implementation + +#ifndef MYAPPLICATION_FLOWITEMADAPTER_H +#define MYAPPLICATION_FLOWITEMADAPTER_H + +#include +#include +#include +#include +#include + +namespace NativeModule { + +class FlowItemAdapter { +public: + FlowItemAdapter(){ + + // Initialize the function pointer structure. + OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, nodeApi_); + // Create a NodeAdapter object. + adapter_ = OH_ArkUI_NodeAdapter_Create(); + + // Initialize lazy loading data. + for (int32_t i = 0; i < 100; i++) { + data_.emplace_back(std::to_string(i)); + } + // Set the total number of items for lazy loading. + OH_ArkUI_NodeAdapter_SetTotalNodeCount(adapter_, data_.size()); + // Set the event listener. + OH_ArkUI_NodeAdapter_RegisterEventReceiver(adapter_, this, OnStaticAdapterEvent); + } + + ~FlowItemAdapter() { + // Release created components. + while (!cachedItems_.empty()) { + cachedItems_.pop(); + } + // Release adapter resources. + OH_ArkUI_NodeAdapter_UnregisterEventReceiver(adapter_); + OH_ArkUI_NodeAdapter_Dispose(adapter_); + } + + ArkUI_NodeAdapterHandle GetAdapter() const { return adapter_; } + + void RemoveItem(int32_t index) { + // Remove the item at the specified index. + data_.erase(data_.begin() + index); + // If the index change affects the visibility of items in the visible area, the NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER event will be triggered to remove the element. + // If items are added, the NODE_ADAPTER_EVENT_ON_GET_NODE_ID and NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER events will be triggered accordingly. + OH_ArkUI_NodeAdapter_RemoveItem(adapter_, index, 1); + // Update the total count. + OH_ArkUI_NodeAdapter_SetTotalNodeCount(adapter_, data_.size()); + } + + void InsertItem(int32_t index, const std::string &value) { + data_.insert(data_.begin() + index, value); + // If the index change affects the visibility of elements in the visible area, the NODE_ADAPTER_EVENT_ON_GET_NODE_ID and NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER events will be triggered. + // If items are removed, the NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER event will be triggered accordingly. + OH_ArkUI_NodeAdapter_InsertItem(adapter_, index, 1); + // Update the total count. + OH_ArkUI_NodeAdapter_SetTotalNodeCount(adapter_, data_.size()); + } + + void MoveItem(int32_t oldIndex, int32_t newIndex) { + auto temp = data_[oldIndex]; + data_.insert(data_.begin() + newIndex, temp); + data_.erase(data_.begin() + oldIndex); + // If the move changes the visibility of items within the visible area, the corresponding events will be triggered. + OH_ArkUI_NodeAdapter_MoveItem(adapter_, oldIndex, newIndex); + } + + void ReloadItem(int32_t index, const std::string &value) { + data_[index] = value; + // If the index is within the visible area, first trigger the NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER event to remove the old item, + // then trigger the NODE_ADAPTER_EVENT_ON_GET_NODE_ID and NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER events. + OH_ArkUI_NodeAdapter_ReloadItem(adapter_, index, 1); + } + + void ReloadAllItem() { + std::reverse(data_.begin(), data_.end()); + // In the scenario where all items are reloaded, the NODE_ADAPTER_EVENT_ON_GET_NODE_ID event will be triggered to obtain new component IDs, + // compare the new component IDs, and reuse those whose IDs have not changed; + // for items with new IDs, trigger the NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER event to create new components, + // then identify any unused IDs from the old data and call NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER to remove the old items. + OH_ArkUI_NodeAdapter_ReloadAllItems(adapter_); + } + +private: + static void OnStaticAdapterEvent(ArkUI_NodeAdapterEvent *event) { + // Obtain the instance object and invoke the instance event callback. + auto itemAdapter = reinterpret_cast(OH_ArkUI_NodeAdapterEvent_GetUserData(event)); + itemAdapter->OnAdapterEvent(event); + } + + void OnAdapterEvent(ArkUI_NodeAdapterEvent *event) { + auto type = OH_ArkUI_NodeAdapterEvent_GetType(event); + switch (type) { + case NODE_ADAPTER_EVENT_ON_GET_NODE_ID: + OnGetChildId(event); + break; + case NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER: + OnCreateNewChild(event); + break; + case NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER: + OnDisposeChild(event); + break; + default: + break; + } + } + + void OnGetChildId(ArkUI_NodeAdapterEvent *event) { + auto index = OH_ArkUI_NodeAdapterEvent_GetItemIndex(event); + // Set the unique identifier for the generated component. + auto hash = std::hash(); + OH_ArkUI_NodeAdapterEvent_SetNodeId(event, hash(data_[index])); + } + + void OnCreateNewChild(ArkUI_NodeAdapterEvent *event) { + auto index = OH_ArkUI_NodeAdapterEvent_GetItemIndex(event); + ArkUI_NodeHandle flowItem = nullptr; + if (!cachedItems_.empty()) { + // Reuse cached items. + flowItem = cachedItems_.top(); + cachedItems_.pop(); + // Update data. + auto *text = nodeApi_->getFirstChild(flowItem); + ArkUI_AttributeItem item{nullptr, 0, data_[index].c_str()}; + nodeApi_->setAttribute(text, NODE_TEXT_CONTENT, &item); + } else { + // Create an item. + auto *text = nodeApi_->createNode(ARKUI_NODE_TEXT); + ArkUI_AttributeItem item{nullptr, 0, data_[index].c_str()}; + nodeApi_->setAttribute(text, NODE_TEXT_CONTENT, &item); + flowItem = nodeApi_->createNode(ARKUI_NODE_FLOW_ITEM); + ArkUI_NumberValue value[] = {100}; + ArkUI_AttributeItem height{value, 1}; + nodeApi_->setAttribute(flowItem, NODE_HEIGHT, &height); + value[0] = {1}; + ArkUI_AttributeItem width{value, 1}; + nodeApi_->setAttribute(flowItem, NODE_WIDTH_PERCENT, &width); + value[0] = {.u32 = 0xFFFF0000}; + ArkUI_AttributeItem backgroundColor{value, 1}; + + nodeApi_->setAttribute(flowItem, NODE_BACKGROUND_COLOR, &backgroundColor); + nodeApi_->addChild(flowItem, text); + } + OH_ArkUI_NodeAdapterEvent_SetItem(event, flowItem); + } + + void OnDisposeChild(ArkUI_NodeAdapterEvent *event) { + auto *node = OH_ArkUI_NodeAdapterEvent_GetRemovedNode(event); + // Cache the node. + cachedItems_.emplace(node); + } + + std::vector data_; + ArkUI_NativeNodeAPI_1 *nodeApi_ = nullptr; + ArkUI_NodeAdapterHandle adapter_ = nullptr; + + // Manage the component reuse pool. + std::stack cachedItems_; +}; + +} // namespace NativeModule + +#endif //MYAPPLICATION_FLOWITEMADAPTER_H + +``` +## Creating a Section +Implement the **WaterflowSection** class to manage grouping within WaterFlow components, where **SectionOption** describes the configuration parameters for each section. In the class constructor, create an **ArkUI_WaterFlowSectionOption** object, which is destroyed in the destructor. + +```c++ +//WaterflowSection.h + +#ifndef MYAPPLICATION_WATERFLOWSECTION_H +#define MYAPPLICATION_WATERFLOWSECTION_H + +#include +#include + +namespace NativeModule { + +struct SectionOption { + int32_t itemsCount = 0; + int32_t crossCount; + float columnsGap; + float rowsGap; + // top right bottom left + ArkUI_Margin margin{0, 0, 0, 0}; + float (*onGetItemMainSizeByIndex)(int32_t itemIndex); + void *userData; +}; + +class WaterflowSection { +public: + WaterflowSection() : sectionOptions_(OH_ArkUI_WaterFlowSectionOption_Create()){}; + + ~WaterflowSection(){ + OH_ArkUI_WaterFlowSectionOption_Dispose(sectionOptions_); + } + + void SetSection(ArkUI_WaterFlowSectionOption *sectionOptions, int32_t index, SectionOption section) { + OH_ArkUI_WaterFlowSectionOption_SetItemCount(sectionOptions, index, section.itemsCount); + OH_ArkUI_WaterFlowSectionOption_SetCrossCount(sectionOptions, index, section.crossCount); + OH_ArkUI_WaterFlowSectionOption_SetColumnGap(sectionOptions, index, section.columnsGap); + OH_ArkUI_WaterFlowSectionOption_SetRowGap(sectionOptions, index, section.rowsGap); + OH_ArkUI_WaterFlowSectionOption_SetMargin(sectionOptions, index, section.margin.top, section.margin.right, + section.margin.bottom, section.margin.left); + OH_ArkUI_WaterFlowSectionOption_RegisterGetItemMainSizeCallbackByIndex(sectionOptions, index, + section.onGetItemMainSizeByIndex); + } + + ArkUI_WaterFlowSectionOption *GetSectionOptions() const { + return sectionOptions_; + } + + void PrintSectionOptions() { + int32_t sectionCnt = OH_ArkUI_WaterFlowSectionOption_GetSize(sectionOptions_); + for (int32_t i = 0; i < sectionCnt; i++) { + ArkUI_Margin margin = OH_ArkUI_WaterFlowSectionOption_GetMargin(sectionOptions_, i); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "CreateWaterflowExample", + "Section[%{public}d].margin:{%{public}f, %{public}f, %{public}f, %{public}f}", i, margin.top, + margin.right, margin.bottom, margin.left); + } + } + +private: + ArkUI_WaterFlowSectionOption *sectionOptions_ = nullptr; +}; +} // namespace NativeModule + +#endif // MYAPPLICATION_WATERFLOWSECTION_H + +``` + +## Creating a WaterFlow Component +Implement the **ArkUIWaterflowNode** class to manage **WaterFlow** components. This class supports configuration through **SetLazyAdapter** for assigning a **FlowItemAdapter** and **SetSection** for defining sections. + +```c++ +//Waterflow.h + +#ifndef MYAPPLICATION_WATERFLOWE_H +#define MYAPPLICATION_WATERFLOWE_H + +#include "FlowItemAdapter.h" +#include "WaterflowSection.h" + +namespace NativeModule { +class ArkUIWaterflowNode { +public: + + ArkUIWaterflowNode() { + + OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, nodeApi_); + // Create a Waterflow component. + waterflow_ = nodeApi_->createNode(ARKUI_NODE_WATER_FLOW); + + } + + ~ArkUIWaterflowNode() { + nodeApi_->disposeNode(waterflow_); + + // Destroy the adapter. + adapter_.reset(); + + // Destroy sections. + section_.reset(); + } + + void SetWidth(float width) { + ArkUI_NumberValue value[] = {{.f32 = width}}; + ArkUI_AttributeItem item = {value, 1}; + nodeApi_->setAttribute(waterflow_, NODE_WIDTH, &item); + } + + void SetHeight(float height) { + ArkUI_NumberValue value[] = {{.f32 = height}}; + ArkUI_AttributeItem item = {value, 1}; + nodeApi_->setAttribute(waterflow_, NODE_HEIGHT, &item); + } + + void SetLazyAdapter(const std::shared_ptr &adapter) { + ArkUI_AttributeItem item{nullptr,0, nullptr, adapter->GetAdapter()}; + nodeApi_->setAttribute(waterflow_, NODE_WATER_FLOW_NODE_ADAPTER, &item); + adapter_ = adapter; + } + + void SetSection(const std::shared_ptr §ion) { + ArkUI_NumberValue start[] = {{.i32 = 0}}; + ArkUI_AttributeItem optionsItem = {start, 1, nullptr, section->GetSectionOptions()}; + if(!section->GetSectionOptions()){ + return; + } + nodeApi_->setAttribute(waterflow_, NODE_WATER_FLOW_SECTION_OPTION, &optionsItem); + section_ = section; + } + + ArkUI_NodeHandle GetWaterflow() { return waterflow_; } + + std::shared_ptr GetWaterflowSection() { return section_; } + +public: + ArkUI_NativeNodeAPI_1 *nodeApi_ = nullptr; + ArkUI_NodeHandle waterflow_ = nullptr; + + std::shared_ptr section_ = nullptr; + + std::shared_ptr adapter_; +}; +}// namespace NativeModule + +#endif // MYAPPLICATION_WATERFLOWE_H +``` + +## Implementing a WaterFlow Component +Create an instance of the **ArkUIWaterflowNode** class, set its width and height, and bind the **NodeAdapter** and sections. + +```c++ +// CreateWaterflowExample.h + +#ifndef MYAPPLICATION_CREATEWATERFLOWEXAMPLE_H +#define MYAPPLICATION_CREATEWATERFLOWEXAMPLE_H +#include "waterflow.h" + +namespace NativeModule { +std::shared_ptr CreateWaterflowExample() { + // Create a WaterFlow component. + auto waterflow = std::make_shared(); + waterflow->SetHeight(600); + waterflow->SetWidth(400); + + // Configure the adapter. + waterflow->SetLazyAdapter(std::make_shared()); + + // Set sections. + auto sections = std::make_shared(); + SectionOption MARGIN_GAP_SECTION_1 = {10, 2, 10, 10, margin : {20, 30, 40, 50}, nullptr, nullptr}; + SectionOption MARGIN_GAP_SECTION_2 = {10, 4, 10, 10, margin : {20, 30, 40, 50}, nullptr, nullptr}; + for (int i = 0; i < 10; i++) { + sections->SetSection(sections->GetSectionOptions(), i, i % 2 ? MARGIN_GAP_SECTION_1 : MARGIN_GAP_SECTION_2); + } + waterflow->SetSection(sections); + + return waterflow; +} +} // namespace NativeModule + +#endif // MYAPPLICATION_CREATEWATERFLOWEXAMPLE_H + +``` diff --git a/en/application-dev/ui/state-management/arkts-extend-components-overview.md b/en/application-dev/ui/state-management/arkts-extend-components-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..f0cff9d382ea090c60fcdd98c3bd178cfe80db4b --- /dev/null +++ b/en/application-dev/ui/state-management/arkts-extend-components-overview.md @@ -0,0 +1,23 @@ +# Component Extension Overview + +ArkUI provides a streamlined code solution through the @Builder decorator. This decorator not only simplifies UI development through modular encapsulation, but also extends to include @BuilderParam decorator, @LocalBuilder decorator, and wrapBuilder, forming a comprehensive system for reusable UI structures. + +> **NOTE** +> +> The @Builder decorator serves as the foundation for @BuilderParam, @LocalBuilder, and wrapBuilder. + +## @Builder Decorator + +The [@Builder decorator](./arkts-builder.md) is specifically designed for creating modular, reusable UI structures. It prohibits the definition of state variables and invocation of component lifecycle methods within its scope, supporting only data interaction with callers through parameters. + +## @BuilderParam Decorator + +When multiple scenarios share the same @Builder function but require scenario-specific extensions (similar to slot placeholder mechanisms), the [@BuilderParam decorator](./arkts-builderparam.md) can be used to receive and encapsulate @Builder functions. + +## @LocalBuilder Decorator + +When using @Builder for inter-component data transfer, note that component hierarchy relationships may conflict with state management parent-child relationships. To address this specific issue, the framework provides the [@LocalBuilder decorator](./arkts-localBuilder.md). + +## wrapBuilder + +When pages contain multiple global @Builder functions with different UI structures, you may face significant maintenance challenges. The framework provides the [wrapBuilder](./arkts-wrapBuilder.md) mechanism to simplify code maintenance in such scenarios.