提交 b5f2a8df 编写于 作者: E ester.zhou

Update docs (21527)

Signed-off-by: Nester.zhou <ester.zhou@huawei.com>
上级 1122a9b9
# Using Animations in the Widget
To make your ArkTS widget more engaging, you can apply animations to it, including [explicit animation](../reference/arkui-ts/ts-explicit-animation.md), [attribute animation](../reference/arkui-ts/ts-animatorproperty.md), and [component transition](../reference/arkui-ts/ts-transition-animation-component.md). Just note the following restrictions when using the animations in ArkTS widgets.
To make your ArkTS widget more engaging, you can apply animations to it, including [explicit animation](../reference/arkui-ts/ts-explicit-animation.md), [property animation](../reference/arkui-ts/ts-animatorproperty.md), and [component transition](../reference/arkui-ts/ts-transition-animation-component.md). Just note the following restrictions when using the animations in ArkTS widgets.
**Table 1** Restrictions on animation parameters
......
......@@ -35,7 +35,7 @@ As a quick entry to applications, ArkTS widgets outperform JS widgets in the fol
![WidgetProject](figures/WidgetProject.png)
- More widget features
- Animation: ArkTS widgets support the [attribute animation](../reference/arkui-ts/ts-animatorproperty.md) and [explicit animation](../reference/arkui-ts/ts-explicit-animation.md) capabilities, which can be leveraged to deliver a more engaging experience.
- Animation: ArkTS widgets support the [property animation](../reference/arkui-ts/ts-animatorproperty.md) and [explicit animation](../reference/arkui-ts/ts-explicit-animation.md) capabilities, which can be leveraged to deliver a more engaging experience.
- Custom drawing: ArkTS widgets allow you to draw graphics with the [\<Canvas>](../reference/arkui-ts/ts-components-canvas-canvas.md) component to present information more vividly.
- Logic code execution: The capability to run logic code in widgets means that service logic can be self-closed in widgets, expanding the use cases of widgets.
......
......@@ -2,7 +2,7 @@
- Getting Started
- [Before You Start](start-overview.md)
- [Getting Started with ArkTS in Stage Model](start-with-ets-stage.md)
- [Building the First ArkTS Application in Stage Model](start-with-ets-stage.md)
- Development Fundamentals
- Application Package Fundamentals
- [Application Package Overview](application-package-overview.md)
......@@ -55,6 +55,7 @@
- [\@Styles Decorator: Definition of Resusable Styles](arkts-style.md)
- [\@Extend Decorator: Extension of Built-in Components](arkts-extend.md)
- [stateStyles Decorator: Polymorphic Style](arkts-statestyles.md)
- [\@AnimatableExtend Decorator: Definition of Animatable Attributes](arkts-animatable-extend.md)
- State Management
- [State Management Overview](arkts-state-management-overview.md)
- Component State Management
......
......@@ -93,7 +93,6 @@ As shown above, the **module.json5** file contains several tags.
| [dependencies](#dependencies)| List of shared libraries on which the current module depends during running.| Object array| Yes (initial value: left empty) |
| targetModuleName | Target module of the bundle. The value is a string with a maximum of 31 bytes. It must be unique in the entire application.|String|Yes (if the initial value is used, the target module is not a module with the overlay feature)|
| targetPriority | Priority of the module. When **targetModuleName** is set, the module is a module with the overlay feature. The value ranges from 1 to 100.|Number|Yes (initial value: **1**)|
| [proxyDatas<sup>(deprecated)</sup>](#proxydatasdeprecated) | This API is deprecated since API version 10. You are advised to use **proxydata** instead. List of data proxies provided by the module.| Object array| Yes (initial value: left empty)|
| [proxyData](#proxydata) | List of data proxies provided by the module.| Object array| Yes (initial value: left empty)|
| isolationMode | Multi-process configuration of the module. The options are as follows:<br>- **nonisolationFirst**: The module preferentially runs in a non-independent process.<br>- **isolationFirst**: The module preferentially runs in an independent process.<br>- **isolationOnly**: The module runs only in an independent process.<br>- **nonisolationOnly**: The module runs only in non-independent processes.|String|Yes (initial value: **nonisolationFirst**)|
| generateBuildHash |Whether the hash value of the HAP or HSP file is generated by the packaging tool. The hash value (if any) is used to determine whether the application needs to be updated when the system is updated in OTA mode but the **versionCode** value of the application remains unchanged.<br>This tag is enabled only when the **generateBuildHash** tag in the [app.json5](./app-configuration-file.md) file is **false**.**<br>**NOTE**<br>This tag applies only to system applications.**|Boolean|Yes (initial value: **false**)|
......@@ -421,7 +420,7 @@ Example of the **extensionAbilities** structure:
## requestPermissions
The **requestPermissions** tag represents a set of permissions that the application needs to request from the system for running correctly.
The **requestPermissions** tag represents a set of permissions that the application needs to request from the system for running correctly. For details about how to request permissions, see [Applying for Permissions](../security/accesstoken-guidelines.md).
> **NOTE**
>
......@@ -738,40 +737,6 @@ Example of the **dependencies** structure:
}
```
## proxyDatas<sup>(deprecated)</sup>
>This API is supported since API version 10 and deprecated since API version 10. You are advised to use [proxyData](#proxydata) instead.
The **proxyDatas** tag provides the list of data proxies provided by the module. It can be configured only for entry and feature modules.
**Table 21** proxyDatas
| Name | Description | Data Type| Initial Value Allowed|
| ----------- | ------------------------------ | -------- | ---------- |
| uri | URI of the data proxy. The URIs configured for different data proxies must be unique and must be in the *datashareproxy://Current application package name/xxx* format. | String | No|
| requiredReadPermission | Permission required for reading data from the data proxy. For non-system applications, this field is mandatory, and the permission level must be system_basic or system_core. For system applications, this field is optional, and the permission level is not limited. For details about the permission level, see [Application Permission List](../security/permission-list.md).| String | Yes (initial value: left empty)|
| requiredWritePermission | Permission required for writing data to the data proxy. For non-system applications, this field is mandatory, and the permission level must be system_basic or system_core. For system applications, this field is optional, and the permission level is not limited. For details about the permission level, see [Application Permission List](../security/permission-list.md).| String | Yes (initial value: left empty)|
| [metadata](#metadata)| Metadata of the data proxy. Only the **name** and **resource** fields can be configured.| Object| Yes (initial value: left empty)|
Example of the **proxyDatas** structure:
```json
{
"module": {
"proxyDatas": [
{
"uri":"datashareproxy://com.ohos.datashare/event/Meeting",
"requiredReadPermission": "ohos.permission.GET_BUNDLE_INFO",
"requiredWritePermission": "ohos.permission.GET_BUNDLE_INFO",
"metadata": {
"name": "datashare_metadata",
"resource": "$profile:datashare"
}
}
]
}
}
```
## proxyData
The **proxyDatas** tag provides the list of data proxies provided by the module. It can be configured only for entry and feature modules.
......@@ -780,8 +745,8 @@ The **proxyDatas** tag provides the list of data proxies provided by the module.
| Name | Description | Data Type| Initial Value Allowed|
| ----------- | ------------------------------ | -------- | ---------- |
| uri | URI of the data proxy. The URIs configured for different data proxies must be unique and must be in the *datashareproxy://Current application package name/xxx* format. | String | No|
| requiredReadPermission | Permission required for reading data from the data proxy. For non-system applications, this field is mandatory, and the permission level must be system_basic or system_core. For system applications, this field is optional, and the permission level is not limited. For details about the permission level, see [Application Permission List](../security/permission-list.md).| String | Yes (initial value: left empty)|
| requiredWritePermission | Permission required for writing data to the data proxy. For non-system applications, this field is mandatory, and the permission level must be system_basic or system_core. For system applications, this field is optional, and the permission level is not limited. For details about the permission level, see [Application Permission List](../security/permission-list.md).| String | Yes (initial value: left empty)|
| requiredReadPermission | Permission required for reading data from the data proxy. If it is not specified, other applications will not be able to use the data proxy. For non-system applications, the level of the set permission must be system_basic or system_core. For system applications, the permission level is not limited. For details about the permission level, see [Application Permission List](../security/permission-list.md).| String | Yes (initial value: left empty)|
| requiredWritePermission | Permission required for writing data to the data proxy. If it is not specified, other applications will not be able to use the data proxy. For non-system applications, the level of the set permission must be system_basic or system_core. For system applications, the permission level is not limited. For details about the permission level, see [Application Permission List](../security/permission-list.md).| String | Yes (initial value: left empty)|
| [metadata](#metadata)| Metadata of the data proxy. Only the **name** and **resource** fields can be configured.| Object| Yes (initial value: left empty)|
Example of the **proxyData** structure:
......
......@@ -44,4 +44,4 @@ To help you better understand the preceding basic concepts and application devel
2. Install DevEco Studio and configure the development environment. For details, see [Setting Up the Development Environment](https://developer.harmonyos.com/en/docs/documentation/doc-guides-V3/environment_config-0000001052902427-V3).
When you are done, follow the instructions in [Getting Started with ArkTS in Stage Model](start-with-ets-stage.md).
When you are done, you can set out to [build your first ArkTS application in the stage model](start-with-ets-stage.md).
# Getting Started with ArkTS in Stage Model
# Building the First ArkTS Application in Stage Model
> **NOTE**
......
......@@ -164,8 +164,8 @@
- Advanced Components
- [@ohos.multimedia.avCastPicker (AVCastPicker)](ohos-multimedia-avcastpicker.md)
- Animation
- [AnimatorProperty](ts-animatorproperty.md)
- [Explicit Animatio](ts-explicit-animation.md)
- [Property Animation](ts-animatorproperty.md)
- [Explicit Animation](ts-explicit-animation.md)
- Transition Animation
- [Page Transition](ts-page-transition-animation.md)
- [Component Transition](ts-transition-animation-component.md)
......
# Property Animator
# Property Animation
You can create a property animator to animate certain universal attributes of a component, including **width**, **height**, **backgroundColor**, **opacity**, **scale**, **rotate**, and **translate**.
You can animate certain properties of a component, including **width**, **height**, **backgroundColor**, **opacity**, **scale**, **rotate**, and **translate**.
> **NOTE**
>
> This event is supported since API version 7. Updates will be marked with a superscript to indicate their earliest API version.
animation(value: {duration?: number, tempo?: number, curve?: string | Curve | ICurve, delay?:number, iterations: number, playMode?: PlayMode, onFinish?: () => void})
animation(value: {duration?: number, tempo?: number, curve?: string | Curve | ICurve, delay?:number, iterations?: number, playMode?: PlayMode, onFinish?: () => void})
Since API version 9, this API is supported in ArkTS widgets.
......
......@@ -44,16 +44,16 @@ Since API version 9, this API is supported in ArkTS widgets.
In addition to the [universal attributes](ts-universal-attributes-size.md), the following attributes are supported.
| Name | Type| Mandatory| Description|
| ------------- | ------- | ---- | -------- |
| closeEffect | boolean | Yes| Whether to disable the rotation and shadow effects for the component.<br>Default value: **false**<br>**NOTE**<br> This attribute enables or disables the shadow effect only when **trackShadow** is not set.<br> The shadow effect enabled through this attribute is in the default style.|
| valueColors<sup>10+</sup> | Array<[ResourceColor](ts-types.md#resourcecolor) \| [LinearGradient](#lineargradient10)> | Yes| Array of data segment colors. A value of the **ResourceColor** type indicates a solid color, and A value of the **LinearGradient** type indicates a color gradient.|
| trackBackgroundColor<sup>10+</sup> | [ResourceColor](ts-types.md#resourcecolor) | Yes| Background color.<br>The value is in hexadecimal ARGB notation. The first two digits indicate opacity.<br>Default value: **'#08182431'**|
| strokeWidth<sup>10+</sup> | [Length](ts-types.md#Length) | Yes| Stroke width of the border.<br>Default value: **24**<br>Unit: vp<br>**NOTE**<br>A value less than 0 evaluates to the default value.<br>This attribute does not take effect when the data panel type is **DataPanelType.Line**.|
| trackShadow<sup>10+</sup> | [DataPanelShadowOption](#datapanelshadowoption10) | Yes| Shadow style.<br>**NOTE**<br>If this attribute is set to **null**, the shadow effect is disabled.|
| Name | Type| Description|
| ------------- | ------- | -------- |
| closeEffect | boolean | Whether to disable the rotation and shadow effects for the component.<br>Default value: **false**<br>**NOTE**<br> This attribute enables or disables the shadow effect only when **trackShadow** is not set.<br> The shadow effect enabled through this attribute is in the default style.|
| valueColors<sup>10+</sup> | Array<[ResourceColor](ts-types.md#resourcecolor) \| [LinearGradient](#lineargradient10)> | Array of data segment colors. A value of the **ResourceColor** type indicates a solid color, and A value of the **LinearGradient** type indicates a color gradient.|
| trackBackgroundColor<sup>10+</sup> | [ResourceColor](ts-types.md#resourcecolor) | Background color.<br>The value is in hexadecimal ARGB notation. The first two digits indicate opacity.<br>Default value: **'#08182431'**|
| strokeWidth<sup>10+</sup> | [Length](ts-types.md#Length) | Stroke width of the border.<br>Default value: **24**<br>Unit: vp<br>**NOTE**<br>A value less than 0 evaluates to the default value.<br>This attribute does not take effect when the data panel type is **DataPanelType.Line**.|
| trackShadow<sup>10+</sup> | [DataPanelShadowOptions](#datapanelshadowoptions10) | Shadow style.<br>**NOTE**<br>If this attribute is set to **null**, the shadow effect is disabled.|
## DataPanelShadowOption<sup>10+</sup>
## DataPanelShadowOptions<sup>10+</sup>
| Name | Type| Mandatory| Description|
| ------------- | ------- | ---- | -------- |
| radius | number \| [Resource](ts-types.md#resource)| No| Shadow blur radius.<br>Default value: **5**<br>Unit: vp<br>**NOTE**<br>A value less than or equal to 0 evaluates to the default value.|
......
......@@ -25,11 +25,11 @@ ImageSpan(value: ResourceStr | PixelMap)
## Attributes
Among all the [universal events](ts-universal-attributes-size.md), only **width**, **height**, and **size** are supported.
The [universal attribute](ts-universal-attributes-size.md) methods can be used to set the size, background, and border.
| Name| Type| Description|
| -------- | -------- | -------- |
| verticalAlign | [ImageSpanAlignment](#imagespanalignment) | Alignment mode of the image with the text.|
| verticalAlign | [ImageSpanAlignment](#imagespanalignment) | Alignment mode of the image with the text.<br>Default value: **ImageSpanAlignment.BOTTOM**|
| objectFit | [ImageFit](ts-appendix-enums.md#imagefit) | Image scale type.<br>Default value: **ImageFit.Cover**|
## ImageSpanAlignment
......@@ -57,7 +57,7 @@ struct SpanExample {
Text() {
Span('This is the Span and ImageSpan component').fontSize(25).textCase(TextCase.Normal)
.decoration({ type: TextDecorationType.None, color: Color.Pink })
}.width('100%')
}.width('100%').textAlign(TextAlign.Center)
Text() {
ImageSpan($r('app.media.icon'))
.width('200px')
......@@ -85,7 +85,6 @@ struct SpanExample {
.decoration({ type: TextDecorationType.Underline, color: Color.Red }).fontSize(50)
}
.width('100%')
.backgroundColor(Color.Orange)
.textIndent(50)
}.width('100%').height('100%').padding({ left: 0, right: 0, top: 0 })
}
......
......@@ -30,7 +30,7 @@ Since API version 9, this API is supported in ArkTS widgets.
| src | string | Yes| Text to scroll.|
## Attributes
In addition to the universal text attributes **fontColor**, **fontSize**, **fontWeight**, and **fontFamily**, the following attributes are supported.
| Name | Type| Description |
| ---------- | -------- | ------------------------------------------------------------ |
| allowScale | boolean | Whether to allow text to scale.<br>This attribute is not supported currently.<br>Default value: **false** |
......
# RichEditor
The \<RichEditor> is a component that supports interactive text editing and mixture of text and imagery.
The **\<RichEditor>** is a component that supports interactive text editing and mixture of text and imagery.
> **NOTE**
>
......@@ -114,7 +114,7 @@ Provides the image span style information returned by the backend.
| ------ | -------- | ---- | -------------------------------------- |
| size | [number, number] | Yes| Width and height of the image.|
| verticalAlign | [ImageSpanAlignment](ts-basic-components-imagespan.md#imagespanalignment) | Yes | Vertical alignment mode of the image.|
| objectFit | [ImageFit]((ts-basic-components-imagespan.md#imagefit)) | Yes| Scale mode of the image.|
| objectFit | [ImageFit](ts-basic-components-imagespan.md#imagefit) | Yes| Scale mode of the image.|
## RichEditorOptions
......@@ -158,7 +158,7 @@ Sets the cursor position.
| Name| Type| Mandatory| Description |
| ------ | -------- | ---- | -------------------------------------- |
| offset | number | Yes| Offset of the cursor.|
| offset | number | Yes| Offset of the cursor. If the value is out of the text range, the setting fails.|
**Return value**
......@@ -265,8 +265,8 @@ Defines the text span style options.
| Name| Type| Mandatory| Description |
| ------ | -------- | ---- | -------------------------------------- |
| start | number | No| Start position of the text span whose style needs to be updated. If this parameter is omitted, the value **0** will be used.|
| end | number | No| End position of the text span whose style needs to be updated. If this parameter is omitted, it indicates the end of the text span.|
| start | number | No| Start position of the text span whose style needs to be updated. If this parameter is omitted or set to a negative value, the value **0** will be used.|
| end | number | No| End position of the text span whose style needs to be updated. If this parameter is omitted or set to a value beyond the text range, it indicates the end of the text span.|
| textStyle | [RichEditorTextStyle](#richeditortextstyle) | Yes| Text style.|
......@@ -276,8 +276,8 @@ Defines the image span style options.
| Name| Type| Mandatory| Description |
| ------ | -------- | ---- | -------------------------------------- |
| start | number | No| Start position of the image span whose style needs to be updated. If this parameter is omitted, the value **0** will be used.|
| end | number | No| End position of the image span whose style needs to be updated. If this parameter is omitted, it indicates the end of the image span.|
| start | number | No| Start position of the image span whose style needs to be updated. If this parameter is omitted or set to a negative value, the value **0** will be used.|
| end | number | No| End position of the image span whose style needs to be updated. If this parameter is omitted or set to a value beyond the text range, it indicates the end of the image span.|
| imageStyle | [RichEditorImageSpanStyle](#richeditorimagespanstyle) | Yes| Image style.|
......@@ -296,12 +296,12 @@ Provides the text style information.
| Name| Type| Mandatory| Description |
| ------ | -------- | ---- | -------------------------------------- |
| fontColor | [ResourceColor](ts-types.md#resourcecolor) | No| Font color.|
| fontSize | [Length](ts-types.md#length) \| number | No| Font size.|
| fontStyle | [FontStyle](ts-appendix-enums.md#fontstyle) | No| Font style.|
| fontWeight | [FontWeight](ts-appendix-enums.md#fontweight) \| number \| string | No| Font weight.|
| fontFamily | [ResourceStr](ts-types.md#resourcestr) \| number \| string | No| Font family. Default value: **'HarmonyOS Sans'**.<br>Currently, only the default font is supported.|
| decoration | {<br>type: [TextDecorationType](ts-appendix-enums.md#textdecorationtype),<br>color?: [ResourceColor](ts-types.md#resourcecolor)<br>} \| number \| string | No| Style and color of the text decorative line.|
| fontColor | [ResourceColor](ts-types.md#resourcecolor) | No| Font color.<br> Default value: **Color.Black**|
| fontSize | [Length](ts-types.md#length) \| number | No| Font size.<br>Default value: **16fp**|
| fontStyle | [FontStyle](ts-appendix-enums.md#fontstyle) | No| Font style.<br>Default value: **FontStyle.Normal**|
| fontWeight | [FontWeight](ts-appendix-enums.md#fontweight) \| number \| string | No| Font weight.<br>Default value: **FontWeight.Normal**|
| fontFamily | [ResourceStr](ts-types.md#resourcestr) \| number \| string | No| Font family. Default value: **'HarmonyOS Sans'**.<br>Currently, only the default font is supported.<br>Default font: **'HarmonyOS Sans'**|
| decoration | {<br>type: [TextDecorationType](ts-appendix-enums.md#textdecorationtype),<br>color?: [ResourceColor](ts-types.md#resourcecolor)<br>} | No| Style and color of the text decorative line.<br>Default value: {<br>type: TextDecorationType.None,<br>color: Color.Black<br>}|
## RichEditorImageSpanOptions
......@@ -320,8 +320,8 @@ Provides the image span style information.
| Name| Type| Mandatory| Description |
| ------ | -------- | ---- | -------------------------------------- |
| size | [Dimension, Dimension] | No| Width and height of the image.|
| verticalAlign | [ImageSpanAlignment](ts-basic-components-imagespan.md#imagespanalignment) | No | Vertical alignment mode of the image.|
| objectFit | [ImageFit]((ts-basic-components-imagespan.md#imagefit)) | No| Scale mode of the image.|
| verticalAlign | [ImageSpanAlignment](ts-basic-components-imagespan.md#imagespanalignment) | No | Vertical alignment mode of the image.<br>Default value: **ImageSpanAlignment.BASELINE**|
| objectFit | [ImageFit](ts-appendix-enums.md#imagefit) | No| Scale mode of the image.<br> Default value: **ImageFit.Cover**|
## RichEditorRange
......@@ -329,8 +329,8 @@ Provides the span range information.
| Name| Type| Mandatory| Description |
| ------ | -------- | ---- | -------------------------------------- |
| start | number | No| Start position. If this parameter is omitted, the value **0** will be used.|
| end | number | No| End position. If this parameter is omitted, it indicates the very end.|
| start | number | No| Start position. If this parameter is omitted or set to a negative value, the value **0** will be used.|
| end | number | No| End position of the image span whose style needs to be updated. If this parameter is omitted or set to a value beyond the text range, it indicates the very end.|
## Example
......
......@@ -52,6 +52,19 @@ Among the [universal attributes](ts-universal-attributes-size.md), only the **wi
| style | Defines the inline style of an element and is placed inside the tag. Use quotation marks (') to separate the styling text and use semicolons (;) to separate styles, for example, **style='width: 500px;height: 500px;border: 1px solid;margin: 0 auto;'**.| \<h1 style='color:blue;text-align:center'>This is a heading\</h1>\<p style='color:green'>This is text\</p> |
| \<script>\</script> | Embeds or references a client-side script, such as JavaScript.| \<script>document.write("Hello World!")\</script> |
## Precautions
The underlying layer of the **\<RichText>** component uses the **\<Web>** component to provide basic capabilities, including but not limited to HTML page parsing and rendering. However, the **\<Web>** component is resources consuming. In scenarios where the **\<RichText>** component is repeatedly used, for example, when it is repeatedly used in a list, frame freezing or slow response may occur.
The **\<RichText>** component complies with the constraints of the **\<Web>** component. A typical scenario is as follows:
The default viewport size of a mobile device is 980 px. This default value ensures that most web pages can be browsed properly on the mobile device. If the width of the **\<RichText>** component is less than this value, the HTML content specified by **content** may generate a scrollable page that is wrapped by the **\<RichText>** component. If you want to replace the default value, add the following tags to **content**:
```html
<meta name="viewport" content="width=device-width">
```
## Example
You can preview how this component looks on a real device. The preview is not yet available in the DevEco Studio Previewer.
......@@ -83,7 +96,7 @@ struct RichTextExample {
console.info('RichText onComplete');
})
.width(500)
.height(400)
.height(500)
.backgroundColor(0XBDDB69)
RichText('layoutWeight(1)')
.onStart(() => {
......@@ -111,7 +124,3 @@ struct RichTextExample {
```
![richText](figures/richText.png)
## Precautions
The underlying layer of the **\<RichText>** component reuses the **\<Web>** component to provide basic capabilities, including but not limited to HTML page parsing and rendering. However, the **\<Web>** component is resources consuming. In scenarios where the **\<RichText>** component is repeatedly used, for example, when it is repeatedly used in a list, frame freezing or slow response may occur.
......@@ -103,4 +103,4 @@ struct PanelExample {
}
```
![en-us_image_0000001256978381](figures/en-us_image_0000001256978381.gif)
![en-us_image_0000001174422896](figures/en-us_image_0000001174422896.gif)
......@@ -33,7 +33,7 @@ Since API version 9, this API is supported in ArkTS widgets.
| [lineCap](#linecap) | CanvasLineCap | Style of the line endpoints. The options are as follows:<br>- **butt**: The endpoints of the line are squared off.<br>- **round**: The endpoints of the line are rounded.<br>- **square**: The endpoints of the line are squared off, and each endpoint has added a rectangle whose length is the same as the line thickness and whose width is half of the line thickness.<br>- Default value: **'butt'**<br>Since API version 9, this API is supported in ArkTS widgets.|
| [lineJoin](#linejoin) | CanvasLineJoin | Style of the shape used to join line segments. The options are as follows:<br>- **round**: The intersection is a sector, whose radius at the rounded corner is equal to the line width.<br>- **bevel**: The intersection is a triangle. The rectangular corner of each line is independent.<br>- **miter**: The intersection has a miter corner by extending the outside edges of the lines until they meet. You can view the effect of this attribute in **miterLimit**.<br>- Default value: **'miter'**<br>Since API version 9, this API is supported in ArkTS widgets.|
| [miterLimit](#miterlimit) | number | Maximum miter length. The miter length is the distance between the inner corner and the outer corner where two lines meet.<br>- Default value: **10**<br>Since API version 9, this API is supported in ArkTS widgets.|
| [font](#font) | string | Font style.<br>Syntax: ctx.font='font-size font-family'<br>- (Optional) **font-size**: font size and row height. The unit can only be pixels.<br>(Optional) **font-family**: font family.<br>Syntax: ctx.font='font-style font-weight font-size font-family'<br>- (Optional) **font-style**: font style. Available values are **normal** and **italic**.<br>- (Optional) **font-weight**: font weight. Available values are as follows: **normal**, **bold**, **bolder**, **lighter**, **100**, **200**, **300**, **400**, **500**, **600**, **700**, **800**, **900**.<br>- (Optional) **font-size**: font size and line height. The unit must be specified and can only be px or vp.<br>- (Optional) **font-family**: font family. Available values are **sans-serif**, **serif**, and **monospace**.<br>Default value: **'normal normal 14px sans-serif'**<br>Since API version 9, this API is supported in ArkTS widgets.|
| [font](#font) | string | Font style.<br>Syntax: ctx.font='font-size font-family'<br>- (Optional) **font-size**: font size and line height. The unit can only be pixels.<br>(Optional) **font-family**: font family.<br>Syntax: ctx.font='font-style font-weight font-size font-family'<br>- (Optional) **font-style**: font style. Available values are **normal** and **italic**.<br>- (Optional) **font-weight**: font weight. Available values are as follows: **normal**, **bold**, **bolder**, **lighter**, **100**, **200**, **300**, **400**, **500**, **600**, **700**, **800**, **900**.<br>- (Optional) **font-size**: font size and line height. The unit can be px or vp and must be specified.<br>- (Optional) **font-family**: font family. Available values are **sans-serif**, **serif**, and **monospace**.<br>Default value: **'normal normal 14px sans-serif'**<br>Since API version 9, this API is supported in ArkTS widgets.|
| [textAlign](#textalign) | CanvasTextAlign | Text alignment mode. Available values are as follows:<br>- **left**: The text is left-aligned.<br>- **right**: The text is right-aligned.<br>- **center**: The text is center-aligned.<br>- **start**: The text is aligned with the start bound.<br>- **end**: The text is aligned with the end bound.<br>**NOTE**<br><br>In the **ltr** layout mode, the value **'start'** equals **'left'**. In the **rtl** layout mode, the value **'start'** equals **'right'**.<br>- Default value: **'left'**<br>Since API version 9, this API is supported in ArkTS widgets.|
| [textBaseline](#textbaseline) | CanvasTextBaseline | Horizontal alignment mode of text. Available values are as follows:<br>- **alphabetic**: The text baseline is the normal alphabetic baseline.<br>- **top**: The text baseline is on the top of the text bounding box.<br>- **hanging**: The text baseline is a hanging baseline over the text.<br>- **middle**: The text baseline is in the middle of the text bounding box.<br>**'ideographic'**: The text baseline is the ideographic baseline. If a character exceeds the alphabetic baseline, the ideographic baseline is located at the bottom of the excess character.<br>- **bottom**: The text baseline is at the bottom of the text bounding box. Its difference from the ideographic baseline is that the ideographic baseline does not consider letters in the next line.<br>- Default value: **'alphabetic'**<br>Since API version 9, this API is supported in ArkTS widgets.|
| [globalAlpha](#globalalpha) | number | Opacity.<br>**0.0**: completely transparent.<br>**1.0**: completely opaque. |
......@@ -61,7 +61,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct FillStyleExample {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -70,9 +70,41 @@ struct FillStyleExample {
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.fillStyle = '#0000ff'
this.offContext.fillRect(20, 20, 150, 100)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.fillStyle = '#0000ff'
offContext.fillRect(20, 20, 150, 100)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
.width('100%')
.height('100%')
}
}
```
```ts
// xxx.ets
@Entry
@Component
struct FillStyleExample {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.fillStyle = 0x0000FF
offContext.fillRect(20, 20, 150, 100)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -94,7 +126,7 @@ struct FillStyleExample {
struct LineWidthExample {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -103,9 +135,10 @@ struct LineWidthExample {
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.lineWidth = 5
this.offContext.strokeRect(25, 25, 85, 105)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.lineWidth = 5
offContext.strokeRect(25, 25, 85, 105)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -127,7 +160,7 @@ struct LineWidthExample {
struct StrokeStyleExample {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -136,10 +169,43 @@ struct StrokeStyleExample {
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.lineWidth = 10
this.offContext.strokeStyle = '#0000ff'
this.offContext.strokeRect(25, 25, 155, 105)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.lineWidth = 10
offContext.strokeStyle = '#0000ff'
offContext.strokeRect(25, 25, 155, 105)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
.width('100%')
.height('100%')
}
}
```
```ts
// xxx.ets
@Entry
@Component
struct StrokeStyleExample {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.lineWidth = 10
offContext.strokeStyle = 0x0000ff
offContext.strokeRect(25, 25, 155, 105)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -161,7 +227,7 @@ struct StrokeStyleExample {
struct LineCapExample {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -170,13 +236,14 @@ struct LineCapExample {
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.lineWidth = 8
this.offContext.beginPath()
this.offContext.lineCap = 'round'
this.offContext.moveTo(30, 50)
this.offContext.lineTo(220, 50)
this.offContext.stroke()
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.lineWidth = 8
offContext.beginPath()
offContext.lineCap = 'round'
offContext.moveTo(30, 50)
offContext.lineTo(220, 50)
offContext.stroke()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -198,7 +265,7 @@ struct LineCapExample {
struct LineJoinExample {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -207,14 +274,15 @@ struct LineJoinExample {
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.beginPath()
this.offContext.lineWidth = 8
this.offContext.lineJoin = 'miter'
this.offContext.moveTo(30, 30)
this.offContext.lineTo(120, 60)
this.offContext.lineTo(30, 110)
this.offContext.stroke()
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.beginPath()
offContext.lineWidth = 8
offContext.lineJoin = 'miter'
offContext.moveTo(30, 30)
offContext.lineTo(120, 60)
offContext.lineTo(30, 110)
offContext.stroke()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -236,7 +304,7 @@ struct LineJoinExample {
struct MiterLimit {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -245,14 +313,15 @@ struct MiterLimit {
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.lineWidth = 8
this.offContext.lineJoin = 'miter'
this.offContext.miterLimit = 3
this.offContext.moveTo(30, 30)
this.offContext.lineTo(60, 35)
this.offContext.lineTo(30, 37)
this.offContext.stroke()
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.lineWidth = 8
offContext.lineJoin = 'miter'
offContext.miterLimit = 3
offContext.moveTo(30, 30)
offContext.lineTo(60, 35)
offContext.lineTo(30, 37)
offContext.stroke()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -274,7 +343,7 @@ struct MiterLimit {
struct Fonts {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -283,9 +352,10 @@ struct Fonts {
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.font = '30px sans-serif'
this.offContext.fillText("Hello World", 20, 60)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.font = '30px sans-serif'
offContext.fillText("Hello World", 20, 60)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -307,7 +377,7 @@ struct Fonts {
struct CanvasExample {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -316,24 +386,25 @@ struct CanvasExample {
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.strokeStyle = '#0000ff'
this.offContext.moveTo(140, 10)
this.offContext.lineTo(140, 160)
this.offContext.stroke()
this.offContext.font = '18px sans-serif'
this.offContext.textAlign = 'start'
this.offContext.fillText('textAlign=start', 140, 60)
this.offContext.textAlign = 'end'
this.offContext.fillText('textAlign=end', 140, 80)
this.offContext.textAlign = 'left'
this.offContext.fillText('textAlign=left', 140, 100)
this.offContext.textAlign = 'center'
this.offContext.fillText('textAlign=center',140, 120)
this.offContext.textAlign = 'right'
this.offContext.fillText('textAlign=right',140, 140)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.strokeStyle = '#0000ff'
offContext.moveTo(140, 10)
offContext.lineTo(140, 160)
offContext.stroke()
offContext.font = '18px sans-serif'
offContext.textAlign = 'start'
offContext.fillText('textAlign=start', 140, 60)
offContext.textAlign = 'end'
offContext.fillText('textAlign=end', 140, 80)
offContext.textAlign = 'left'
offContext.fillText('textAlign=left', 140, 100)
offContext.textAlign = 'center'
offContext.fillText('textAlign=center',140, 120)
offContext.textAlign = 'right'
offContext.fillText('textAlign=right',140, 140)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -355,7 +426,7 @@ struct CanvasExample {
struct TextBaseline {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -364,24 +435,25 @@ struct TextBaseline {
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.strokeStyle = '#0000ff'
this.offContext.moveTo(0, 120)
this.offContext.lineTo(400, 120)
this.offContext.stroke()
this.offContext.font = '20px sans-serif'
this.offContext.textBaseline = 'top'
this.offContext.fillText('Top', 10, 120)
this.offContext.textBaseline = 'bottom'
this.offContext.fillText('Bottom', 55, 120)
this.offContext.textBaseline = 'middle'
this.offContext.fillText('Middle', 125, 120)
this.offContext.textBaseline = 'alphabetic'
this.offContext.fillText('Alphabetic', 195, 120)
this.offContext.textBaseline = 'hanging'
this.offContext.fillText('Hanging', 295, 120)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.strokeStyle = '#0000ff'
offContext.moveTo(0, 120)
offContext.lineTo(400, 120)
offContext.stroke()
offContext.font = '20px sans-serif'
offContext.textBaseline = 'top'
offContext.fillText('Top', 10, 120)
offContext.textBaseline = 'bottom'
offContext.fillText('Bottom', 55, 120)
offContext.textBaseline = 'middle'
offContext.fillText('Middle', 125, 120)
offContext.textBaseline = 'alphabetic'
offContext.fillText('Alphabetic', 195, 120)
offContext.textBaseline = 'hanging'
offContext.fillText('Hanging', 295, 120)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -403,7 +475,7 @@ struct TextBaseline {
struct GlobalAlpha {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -412,12 +484,13 @@ struct GlobalAlpha {
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.fillStyle = 'rgb(0,0,255)'
this.offContext.fillRect(0, 0, 50, 50)
this.offContext.globalAlpha = 0.4
this.offContext.fillStyle = 'rgb(0,0,255)'
this.offContext.fillRect(50, 50, 50, 50)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.fillStyle = 'rgb(0,0,255)'
offContext.fillRect(0, 0, 50, 50)
offContext.globalAlpha = 0.4
offContext.fillStyle = 'rgb(0,0,255)'
offContext.fillRect(50, 50, 50, 50)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -439,7 +512,7 @@ struct GlobalAlpha {
struct LineDashOffset {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -448,11 +521,12 @@ struct LineDashOffset {
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.arc(100, 75, 50, 0, 6.28)
this.offContext.setLineDash([10,20])
this.offContext.lineDashOffset = 10.0
this.offContext.stroke()
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.arc(100, 75, 50, 0, 6.28)
offContext.setLineDash([10,20])
offContext.lineDashOffset = 10.0
offContext.stroke()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -488,7 +562,7 @@ struct LineDashOffset {
struct GlobalCompositeOperation {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -497,17 +571,18 @@ struct GlobalCompositeOperation {
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.fillStyle = 'rgb(255,0,0)'
this.offContext.fillRect(20, 20, 50, 50)
this.offContext.globalCompositeOperation = 'source-over'
this.offContext.fillStyle = 'rgb(0,0,255)'
this.offContext.fillRect(50, 50, 50, 50)
this.offContext.fillStyle = 'rgb(255,0,0)'
this.offContext.fillRect(120, 20, 50, 50)
this.offContext.globalCompositeOperation = 'destination-over'
this.offContext.fillStyle = 'rgb(0,0,255)'
this.offContext.fillRect(150, 50, 50, 50)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.fillStyle = 'rgb(255,0,0)'
offContext.fillRect(20, 20, 50, 50)
offContext.globalCompositeOperation = 'source-over'
offContext.fillStyle = 'rgb(0,0,255)'
offContext.fillRect(50, 50, 50, 50)
offContext.fillStyle = 'rgb(255,0,0)'
offContext.fillRect(120, 20, 50, 50)
offContext.globalCompositeOperation = 'destination-over'
offContext.fillStyle = 'rgb(0,0,255)'
offContext.fillRect(150, 50, 50, 50)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -529,7 +604,7 @@ struct GlobalCompositeOperation {
struct ShadowBlur {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -538,11 +613,12 @@ struct ShadowBlur {
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.shadowBlur = 30
this.offContext.shadowColor = 'rgb(0,0,0)'
this.offContext.fillStyle = 'rgb(255,0,0)'
this.offContext.fillRect(20, 20, 100, 80)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.shadowBlur = 30
offContext.shadowColor = 'rgb(0,0,0)'
offContext.fillStyle = 'rgb(255,0,0)'
offContext.fillRect(20, 20, 100, 80)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -564,7 +640,7 @@ struct ShadowBlur {
struct ShadowColor {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -573,11 +649,12 @@ struct ShadowColor {
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.shadowBlur = 30
this.offContext.shadowColor = 'rgb(0,0,255)'
this.offContext.fillStyle = 'rgb(255,0,0)'
this.offContext.fillRect(30, 30, 100, 100)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.shadowBlur = 30
offContext.shadowColor = 'rgb(0,0,255)'
offContext.fillStyle = 'rgb(255,0,0)'
offContext.fillRect(30, 30, 100, 100)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -599,7 +676,7 @@ struct ShadowColor {
struct ShadowOffsetX {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -608,12 +685,13 @@ struct ShadowOffsetX {
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.shadowBlur = 10
this.offContext.shadowOffsetX = 20
this.offContext.shadowColor = 'rgb(0,0,0)'
this.offContext.fillStyle = 'rgb(255,0,0)'
this.offContext.fillRect(20, 20, 100, 80)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.shadowBlur = 10
offContext.shadowOffsetX = 20
offContext.shadowColor = 'rgb(0,0,0)'
offContext.fillStyle = 'rgb(255,0,0)'
offContext.fillRect(20, 20, 100, 80)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -635,7 +713,7 @@ struct ShadowOffsetX {
struct ShadowOffsetY {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -644,12 +722,13 @@ struct ShadowOffsetY {
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.shadowBlur = 10
this.offContext.shadowOffsetY = 20
this.offContext.shadowColor = 'rgb(0,0,0)'
this.offContext.fillStyle = 'rgb(255,0,0)'
this.offContext.fillRect(30, 30, 100, 100)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.shadowBlur = 10
offContext.shadowOffsetY = 20
offContext.shadowColor = 'rgb(0,0,0)'
offContext.fillStyle = 'rgb(255,0,0)'
offContext.fillRect(30, 30, 100, 100)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -672,7 +751,7 @@ struct ImageSmoothingEnabled {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private img:ImageBitmap = new ImageBitmap("common/images/icon.jpg")
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -681,9 +760,10 @@ struct ImageSmoothingEnabled {
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.imageSmoothingEnabled = false
this.offContext.drawImage( this.img,0,0,400,200)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.imageSmoothingEnabled = false
offContext.drawImage(this.img,0,0,400,200)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -725,7 +805,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct FillRect {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -734,8 +814,9 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.fillRect(30,30,100,100)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.fillRect(30,30,100,100)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -774,7 +855,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct StrokeRect {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -783,8 +864,9 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.strokeRect(30, 30, 200, 150)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.strokeRect(30, 30, 200, 150)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -823,7 +905,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct ClearRect {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -832,10 +914,11 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.fillStyle = 'rgb(0,0,255)'
this.offContext.fillRect(20,20,200,200)
this.offContext.clearRect(30,30,150,100)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.fillStyle = 'rgb(0,0,255)'
offContext.fillRect(20,20,200,200)
offContext.clearRect(30,30,150,100)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -874,7 +957,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct FillText {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -883,9 +966,10 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.font = '30px sans-serif'
this.offContext.fillText("Hello World!", 20, 100)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.font = '30px sans-serif'
offContext.fillText("Hello World!", 20, 100)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -924,7 +1008,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct StrokeText {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -933,9 +1017,10 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.font = '55px sans-serif'
this.offContext.strokeText("Hello World!", 20, 60)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.font = '55px sans-serif'
offContext.strokeText("Hello World!", 20, 60)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -995,7 +1080,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct MeasureText {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -1004,10 +1089,11 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.font = '50px sans-serif'
this.offContext.fillText("Hello World!", 20, 100)
this.offContext.fillText("width:" + this.context.measureText("Hello World!").width, 20, 200)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.font = '50px sans-serif'
offContext.fillText("Hello World!", 20, 100)
offContext.fillText("width:" + this.context.measureText("Hello World!").width, 20, 200)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -1043,7 +1129,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct Stroke {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -1052,13 +1138,14 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.moveTo(25, 25)
this.offContext.lineTo(25, 105)
this.offContext.lineTo(75, 105)
this.offContext.lineTo(75, 25)
this.offContext.strokeStyle = 'rgb(0,0,255)'
this.offContext.stroke()
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.moveTo(25, 25)
offContext.lineTo(25, 105)
offContext.lineTo(75, 105)
offContext.lineTo(75, 25)
offContext.strokeStyle = 'rgb(0,0,255)'
offContext.stroke()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -1088,7 +1175,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct BeginPath {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -1097,13 +1184,14 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.beginPath()
this.offContext.lineWidth = 6
this.offContext.strokeStyle = '#0000ff'
this.offContext.moveTo(15, 80)
this.offContext.lineTo(280, 160)
this.offContext.stroke()
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.beginPath()
offContext.lineWidth = 6
offContext.strokeStyle = '#0000ff'
offContext.moveTo(15, 80)
offContext.lineTo(280, 160)
offContext.stroke()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -1140,7 +1228,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct MoveTo {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -1149,11 +1237,12 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.beginPath()
this.offContext.moveTo(10, 10)
this.offContext.lineTo(280, 160)
this.offContext.stroke()
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.beginPath()
offContext.moveTo(10, 10)
offContext.lineTo(280, 160)
offContext.stroke()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -1190,7 +1279,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct LineTo {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -1199,11 +1288,12 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.beginPath()
this.offContext.moveTo(10, 10)
this.offContext.lineTo(280, 160)
this.offContext.stroke()
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.beginPath()
offContext.moveTo(10, 10)
offContext.lineTo(280, 160)
offContext.stroke()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -1233,7 +1323,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct ClosePath {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -1242,13 +1332,14 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.beginPath()
this.offContext.moveTo(30, 30)
this.offContext.lineTo(110, 30)
this.offContext.lineTo(70, 90)
this.offContext.closePath()
this.offContext.stroke()
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.beginPath()
offContext.moveTo(30, 30)
offContext.lineTo(110, 30)
offContext.lineTo(70, 90)
offContext.closePath()
offContext.stroke()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -1292,7 +1383,7 @@ Since API version 9, this API is supported in ArkTS widgets.
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private img:ImageBitmap = new ImageBitmap("common/images/icon.jpg")
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -1301,10 +1392,11 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
var pattern = this.offContext.createPattern(this.img, 'repeat')
this.offContext.fillStyle = pattern
this.offContext.fillRect(0, 0, 200, 200)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
var pattern = offContext.createPattern(this.img, 'repeat')
offContext.fillStyle = pattern
offContext.fillRect(0, 0, 200, 200)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -1345,7 +1437,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct BezierCurveTo {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -1354,11 +1446,12 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.beginPath()
this.offContext.moveTo(10, 10)
this.offContext.bezierCurveTo(20, 100, 200, 100, 200, 20)
this.offContext.stroke()
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.beginPath()
offContext.moveTo(10, 10)
offContext.bezierCurveTo(20, 100, 200, 100, 200, 20)
offContext.stroke()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -1397,7 +1490,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct QuadraticCurveTo {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -1406,11 +1499,12 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.beginPath()
this.offContext.moveTo(20, 20)
this.offContext.quadraticCurveTo(100, 100, 200, 20)
this.offContext.stroke()
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.beginPath()
offContext.moveTo(20, 20)
offContext.quadraticCurveTo(100, 100, 200, 20)
offContext.stroke()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -1451,7 +1545,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct Arc {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -1460,10 +1554,11 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.beginPath()
this.offContext.arc(100, 75, 50, 0, 6.28)
this.offContext.stroke()
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.beginPath()
offContext.arc(100, 75, 50, 0, 6.28)
offContext.stroke()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -1503,7 +1598,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct ArcTo {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -1512,10 +1607,11 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.moveTo(100, 20)
this.offContext.arcTo(150, 20, 150, 70, 50)
this.offContext.stroke()
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.moveTo(100, 20)
offContext.arcTo(150, 20, 150, 70, 50)
offContext.stroke()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -1558,7 +1654,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct CanvasExample {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Canvas(this.context)
......@@ -1566,10 +1662,11 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.beginPath()
this.offContext.ellipse(200, 200, 50, 100, Math.PI * 0.25, Math.PI * 0.5, Math.PI * 2)
this.offContext.stroke()
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.beginPath()
offContext.ellipse(200, 200, 50, 100, Math.PI * 0.25, Math.PI * 0.5, Math.PI * 2)
offContext.stroke()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -1608,7 +1705,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct CanvasExample {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -1617,9 +1714,10 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.rect(20, 20, 100, 100) // Create a 100*100 rectangle at (20, 20)
this.offContext.stroke()
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.rect(20, 20, 100, 100) // Create a 100*100 rectangle at (20, 20)
offContext.stroke()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -1653,7 +1751,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct Fill {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -1662,9 +1760,11 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.rect(20, 20, 100, 100) // Create a 100*100 rectangle at (20, 20)
this.offContext.fill()
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.fillStyle = '#ffffff'
offContext.rect(20, 20, 100, 100) // Create a 100*100 rectangle at (20, 20)
offContext.fill()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -1700,7 +1800,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct Fill {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -1709,6 +1809,7 @@ struct Fill {
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
var offContext = this.offCanvas.getContext("2d", this.settings)
let region = new Path2D()
region.moveTo(30, 90)
region.lineTo(110, 20)
......@@ -1718,9 +1819,9 @@ struct Fill {
region.lineTo(270, 90)
region.closePath()
// Fill path
this.offContext.fillStyle = '#00ff00'
this.offContext.fill(region, "evenodd")
var image = this.offContext.transferToImageBitmap()
offContext.fillStyle = '#00ff00'
offContext.fill(region, "evenodd")
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -1757,7 +1858,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct Clip {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -1766,12 +1867,13 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.rect(0, 0, 100, 200)
this.offContext.stroke()
this.offContext.clip()
this.offContext.fillStyle = "rgb(255,0,0)"
this.offContext.fillRect(0, 0, 200, 200)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.rect(0, 0, 100, 200)
offContext.stroke()
offContext.clip()
offContext.fillStyle = "rgb(255,0,0)"
offContext.fillRect(0, 0, 200, 200)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -1806,7 +1908,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct Clip {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -1815,6 +1917,7 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
var offContext = this.offCanvas.getContext("2d", this.settings)
let region = new Path2D()
region.moveTo(30, 90)
region.lineTo(110, 20)
......@@ -1823,10 +1926,10 @@ Since API version 9, this API is supported in ArkTS widgets.
region.lineTo(190, 20)
region.lineTo(270, 90)
region.closePath()
this.offContext.clip(region,"evenodd")
this.offContext.fillStyle = "rgb(0,255,0)"
this.offContext.fillRect(0, 0, 600, 600)
var image = this.offContext.transferToImageBitmap()
offContext.clip(region,"evenodd")
offContext.fillStyle = "rgb(0,255,0)"
offContext.fillRect(0, 0, 600, 600)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -1862,7 +1965,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct FilterDemoOff {
private settings: RenderingContextSettings = new RenderingContextSettings(true);
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
private img:ImageBitmap = new ImageBitmap("common/images/example.jpg");
build() {
......@@ -1872,7 +1975,8 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
let offctx = this.offContext
var offContext = this.offCanvas.getContext("2d", this.settings)
let offctx = offContext
let img = this.img
offctx.drawImage(img, 0, 0, 100, 100);
......@@ -1904,7 +2008,7 @@ Since API version 9, this API is supported in ArkTS widgets.
offctx.filter = 'blur(5px)';
offctx.drawImage(img, 0, 300, 100, 100);
var image = offctx.transferToImageBitmap()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -1917,20 +2021,6 @@ Since API version 9, this API is supported in ArkTS widgets.
![filterDemo](figures/filterDemo.jpeg)
### getTransform
getTransform(): Matrix2D
Obtains the current transformation matrix being applied to the context. This API is a void API.
Since API version 9, this API is supported in ArkTS widgets.
**Return value**
| Type | Description |
| ---------------------------------------- | ----- |
| [Matrix2D](ts-components-canvas-matrix2d.md#Matrix2D) | Matrix object.|
### resetTransform
resetTransform(): void
......@@ -1956,7 +2046,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct DirectionDemoOff {
private settings: RenderingContextSettings = new RenderingContextSettings(true);
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -1965,7 +2055,8 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
let offctx = this.offContext
var offContext = this.offCanvas.getContext("2d", this.settings)
let offctx = offContext
offctx.font = '48px serif';
offctx.textAlign = 'start'
offctx.fillText("Hi ltr!", 200, 50);
......@@ -2010,7 +2101,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct Rotate {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -2019,9 +2110,10 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.rotate(45 * Math.PI / 180)
this.offContext.fillRect(70, 20, 50, 50)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.rotate(45 * Math.PI / 180)
offContext.fillRect(70, 20, 50, 50)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -2058,7 +2150,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct Scale {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -2067,11 +2159,12 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.lineWidth = 3
this.offContext.strokeRect(30, 30, 50, 50)
this.offContext.scale(2, 2) // Scale to 200%
this.offContext.strokeRect(30, 30, 50, 50)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.lineWidth = 3
offContext.strokeRect(30, 30, 50, 50)
offContext.scale(2, 2) // Scale to 200%
offContext.strokeRect(30, 30, 50, 50)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -2119,7 +2212,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct Transform {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -2128,15 +2221,16 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.fillStyle = 'rgb(0,0,0)'
this.offContext.fillRect(0, 0, 100, 100)
this.offContext.transform(1, 0.5, -0.5, 1, 10, 10)
this.offContext.fillStyle = 'rgb(255,0,0)'
this.offContext.fillRect(0, 0, 100, 100)
this.offContext.transform(1, 0.5, -0.5, 1, 10, 10)
this.offContext.fillStyle = 'rgb(0,0,255)'
this.offContext.fillRect(0, 0, 100, 100)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.fillStyle = 'rgb(0,0,0)'
offContext.fillRect(0, 0, 100, 100)
offContext.transform(1, 0.5, -0.5, 1, 10, 10)
offContext.fillStyle = 'rgb(255,0,0)'
offContext.fillRect(0, 0, 100, 100)
offContext.transform(1, 0.5, -0.5, 1, 10, 10)
offContext.fillStyle = 'rgb(0,0,255)'
offContext.fillRect(0, 0, 100, 100)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -2177,7 +2271,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct SetTransform {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -2186,12 +2280,13 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.fillStyle = 'rgb(255,0,0)'
this.offContext.fillRect(0, 0, 100, 100)
this.offContext.setTransform(1,0.5, -0.5, 1, 10, 10)
this.offContext.fillStyle = 'rgb(0,0,255)'
this.offContext.fillRect(0, 0, 100, 100)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.fillStyle = 'rgb(255,0,0)'
offContext.fillRect(0, 0, 100, 100)
offContext.setTransform(1,0.5, -0.5, 1, 10, 10)
offContext.fillStyle = 'rgb(0,0,255)'
offContext.fillRect(0, 0, 100, 100)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -2204,6 +2299,86 @@ Since API version 9, this API is supported in ArkTS widgets.
![en-us_image_0000001193872526](figures/en-us_image_0000001193872526.png)
### setTransform
setTransform(transform?: Matrix2D): void
Resets the current transformation and creates a new transformation matrix based on the specified **Matrix2D** object.
Since API version 9, this API is supported in ArkTS widgets.
**Parameters**
| Name | Type | Mandatory | Default Value | Description |
| --------- | ---------------------------------------- | ---- | ---- | ----- |
| transform | [Matrix2D](ts-components-canvas-matrix2d.md#Matrix2D) | No | null | Matrix object. |
### getTransform
getTransform(): Matrix2D
Obtains the current transformation matrix being applied to the context.
Since API version 9, this API is supported in ArkTS widgets.
**Return value**
| Type | Description |
| ---------------------------------------- | ----- |
| [Matrix2D](ts-components-canvas-matrix2d.md#Matrix2D) | Matrix object.|
**Example**
```ts
// xxx.ets
@Entry
@Component
struct TransFormDemo {
private settings: RenderingContextSettings = new RenderingContextSettings(true);
private context1: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
private offcontext1: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 100, this.settings);
private context2: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
private offcontext2: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 100, this.settings);
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text('context1');
Canvas(this.context1)
.width('230vp')
.height('120vp')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offcontext1.fillRect(50, 50, 50, 50);
this.offcontext1.setTransform(1.2, Math.PI/8, Math.PI/6, 0.5, 30, -25);
this.offcontext1.fillRect(50, 50, 50, 50);
var image = this.offcontext1.transferToImageBitmap();
this.context1.transferFromImageBitmap(image);
})
Text('context2');
Canvas(this.context2)
.width('230vp')
.height('120vp')
.backgroundColor('#0ffff0')
.onReady(() =>{
this.offcontext2.fillRect(50, 50, 50, 50);
let storedTransform = this.offcontext1.getTransform();
console.log("Matrix [scaleX = " + storedTransform.scaleX + ", scaleY = " + storedTransform.scaleY +
", rotateX = " + storedTransform.rotateX + ", rotateY = " + storedTransform.rotateY +
", translateX = " + storedTransform.translateX + ", translateY = " + storedTransform.translateY + "]")
this.offcontext2.setTransform(storedTransform);
this.offcontext2.fillRect(50,50,50,50);
var image = this.offcontext2.transferToImageBitmap();
this.context2.transferFromImageBitmap(image);
})
}
.width('100%')
.height('100%')
}
}
```
![en-us_image_0000001219982726.png](figures/en-us_image_0000001219982726.png)
### translate
translate(x: number, y: number): void
......@@ -2228,7 +2403,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct Translate {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -2237,10 +2412,11 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.fillRect(10, 10, 50, 50)
this.offContext.translate(70, 70)
this.offContext.fillRect(10, 10, 50, 50)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.fillRect(10, 10, 50, 50)
offContext.translate(70, 70)
offContext.fillRect(10, 10, 50, 50)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -2290,7 +2466,7 @@ Since API version 9, this API is supported in ArkTS widgets, except that **Pixel
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private img:ImageBitmap = new ImageBitmap("common/images/icon.jpg")
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Canvas(this.context)
......@@ -2298,8 +2474,9 @@ Since API version 9, this API is supported in ArkTS widgets, except that **Pixel
.height('100%')
.backgroundColor('#ffff00')
.onReady(() => {
this.offContext.drawImage( this.img,0,0,400,200)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.drawImage( this.img,0,0,400,200)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -2422,7 +2599,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct GetImageData {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
private img:ImageBitmap = new ImageBitmap("/common/images/1234.png")
build() {
......@@ -2432,10 +2609,11 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.drawImage(this.img,0,0,130,130)
var imagedata = this.offContext.getImageData(50,50,130,130)
this.offContext.putImageData(imagedata,150,150)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.drawImage(this.img,0,0,130,130)
var imagedata = offContext.getImageData(50,50,130,130)
offContext.putImageData(imagedata,150,150)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -2479,7 +2657,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct PutImageData {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Canvas(this.context)
......@@ -2487,15 +2665,16 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
var imageData = this.offContext.createImageData(100, 100)
var offContext = this.offCanvas.getContext("2d", this.settings)
var imageData = offContext.createImageData(100, 100)
for (var i = 0; i < imageData.data.length; i += 4) {
imageData.data[i + 0] = 255
imageData.data[i + 1] = 0
imageData.data[i + 2] = 255
imageData.data[i + 3] = 255
}
this.offContext.putImageData(imageData, 10, 10)
var image = this.offContext.transferToImageBitmap()
offContext.putImageData(imageData, 10, 10)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -2529,7 +2708,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct SetLineDash {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -2538,10 +2717,11 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.arc(100, 75, 50, 0, 6.28)
this.offContext.setLineDash([10,20])
this.offContext.stroke()
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.arc(100, 75, 50, 0, 6.28)
offContext.setLineDash([10,20])
offContext.stroke()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -2577,7 +2757,7 @@ Since API version 9, this API is supported in ArkTS widgets.
@State message: string = 'Hello World'
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Row() {
Column() {
......@@ -2586,7 +2766,8 @@ Since API version 9, this API is supported in ArkTS widgets.
.fontWeight(FontWeight.Bold)
.onClick(()=>{
console.error('before getlinedash clicked')
let res = this.offContext.getLineDash()
var offContext = this.offCanvas.getContext("2d", this.settings)
let res = offContext.getLineDash()
console.error(JSON.stringify(res))
})
Canvas(this.context)
......@@ -2594,11 +2775,12 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() => {
this.offContext.arc(100, 75, 50, 0, 6.28)
this.offContext.setLineDash([10,20])
this.offContext.stroke()
let res = this.offContext.getLineDash()
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.arc(100, 75, 50, 0, 6.28)
offContext.setLineDash([10,20])
offContext.stroke()
let res = offContext.getLineDash()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -2642,7 +2824,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct ToDataURL {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -2651,7 +2833,8 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
var dataURL = this.offContext.toDataURL()
var offContext = this.offCanvas.getContext("2d", this.settings)
var dataURL = offContext.toDataURL()
})
}
.width('100%')
......@@ -2683,7 +2866,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct ImageSmoothingQualityDemoOff {
private settings: RenderingContextSettings = new RenderingContextSettings(true);
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
private img:ImageBitmap = new ImageBitmap("common/images/example.jpg");
build() {
......@@ -2693,12 +2876,13 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
let offctx = this.offContext
var offContext = this.offCanvas.getContext("2d", this.settings)
let offctx = offContext
offctx.imageSmoothingEnabled = true
offctx.imageSmoothingQuality = 'high'
offctx.drawImage(this.img, 0, 0, 400, 200)
var image = offctx.transferToImageBitmap()
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -2732,7 +2916,7 @@ Creates an **ImageBitmap** object on the most recently rendered image of the **O
struct PutImageData {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -2741,15 +2925,16 @@ Creates an **ImageBitmap** object on the most recently rendered image of the **O
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
var imageData = this.offContext.createImageData(100, 100)
var offContext = this.offCanvas.getContext("2d", this.settings)
var imageData = offContext.createImageData(100, 100)
for (var i = 0; i < imageData.data.length; i += 4) {
imageData.data[i + 0] = 255
imageData.data[i + 1] = 0
imageData.data[i + 2] = 255
imageData.data[i + 3] = 255
}
this.offContext.putImageData(imageData, 10, 10)
var image = this.offContext.transferToImageBitmap()
offContext.putImageData(imageData, 10, 10)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -2777,7 +2962,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct CanvasExample {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -2786,12 +2971,13 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.save() // save the default state
this.offContext.fillStyle = "#00ff00"
this.offContext.fillRect(20, 20, 100, 100)
this.offContext.restore() // restore to the default state
this.offContext.fillRect(150, 75, 100, 100)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.save() // save the default state
offContext.fillStyle = "#00ff00"
offContext.fillRect(20, 20, 100, 100)
offContext.restore() // restore to the default state
offContext.fillRect(150, 75, 100, 100)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -2820,7 +3006,7 @@ Since API version 9, this API is supported in ArkTS widgets.
struct CanvasExample {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -2829,12 +3015,13 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
this.offContext.save() // save the default state
this.offContext.fillStyle = "#00ff00"
this.offContext.fillRect(20, 20, 100, 100)
this.offContext.restore() // restore to the default state
this.offContext.fillRect(150, 75, 100, 100)
var image = this.offContext.transferToImageBitmap()
var offContext = this.offCanvas.getContext("2d", this.settings)
offContext.save() // save the default state
offContext.fillStyle = "#00ff00"
offContext.fillRect(20, 20, 100, 100)
offContext.restore() // restore to the default state
offContext.fillRect(150, 75, 100, 100)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -2872,8 +3059,8 @@ Since API version 9, this API is supported in ArkTS widgets.
struct CreateLinearGradient {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Canvas(this.context)
......@@ -2881,13 +3068,14 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
var grad = this.offContext.createLinearGradient(50,0, 300,100)
var offContext = this.offCanvas.getContext("2d", this.settings)
var grad = offContext.createLinearGradient(50,0, 300,100)
grad.addColorStop(0.0, '#ff0000')
grad.addColorStop(0.5, '#ffffff')
grad.addColorStop(1.0, '#00ff00')
this.offContext.fillStyle = grad
this.offContext.fillRect(0, 0, 400, 400)
var image = this.offContext.transferToImageBitmap()
offContext.fillStyle = grad
offContext.fillRect(0, 0, 400, 400)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -2928,8 +3116,8 @@ Since API version 9, this API is supported in ArkTS widgets.
struct CreateRadialGradient {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Canvas(this.context)
......@@ -2937,13 +3125,14 @@ Since API version 9, this API is supported in ArkTS widgets.
.height('100%')
.backgroundColor('#ffff00')
.onReady(() =>{
var grad = this.offContext.createRadialGradient(200,200,50, 200,200,200)
var offContext = this.offCanvas.getContext("2d", this.settings)
var grad = offContext.createRadialGradient(200,200,50, 200,200,200)
grad.addColorStop(0.0, '#ff0000')
grad.addColorStop(0.5, '#ffffff')
grad.addColorStop(1.0, '#00ff00')
this.offContext.fillStyle = grad
this.offContext.fillRect(0, 0, 440, 440)
var image = this.offContext.transferToImageBitmap()
offContext.fillStyle = grad
offContext.fillRect(0, 0, 440, 440)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......@@ -2978,8 +3167,7 @@ Creates a conic gradient.
struct OffscreenCanvasConicGradientPage {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -2988,13 +3176,14 @@ struct OffscreenCanvasConicGradientPage {
.height('100%')
.backgroundColor('#ffffff')
.onReady(() =>{
var grad = this.offContext.createConicGradient(0, 50, 80)
var offContext = this.offCanvas.getContext("2d", this.settings)
var grad = offContext.createConicGradient(0, 50, 80)
grad.addColorStop(0.0, '#ff0000')
grad.addColorStop(0.5, '#ffffff')
grad.addColorStop(1.0, '#00ff00')
this.offContext.fillStyle = grad
this.offContext.fillRect(0, 30, 100, 100)
var image = this.offContext.transferToImageBitmap()
offContext.fillStyle = grad
offContext.fillRect(0, 30, 100, 100)
var image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
......
......@@ -10,8 +10,8 @@ You can customize the page entrance and exit animations in the **pageTransition*
| Name | Parameter | Mandatory| Description |
| ------------------- | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ |
| PageTransitionEnter | {<br>type?: RouteType,<br>duration?: number,<br>curve?: [Curve](ts-appendix-enums.md#curve) \| string,<br>delay?: number<br>} | No | Page entrance animation.<br>- **type**: route type for the page transition effect to take effect.<br>Default value: **RouteType.None**<br>- **duration**: animation duration.<br>Unit: ms<br>Default value: **1000**<br>- **curve**: animation curve. The value of the string type can be any of the following: "ease", "ease-in", "ease-out", "ease-in-out", "extreme-deceleration", "fast-out-linear-in", "fast-out-slow-in", "friction", "linear", "linear-out-slow-in", "rhythm", "sharp", "smooth".<br>Default value: **Curve.Linear**<br>- **delay**: animation delay.<br>Unit: ms<br>Default value: **0**<br>**NOTE**<br>If no match is found, the default page transition effect is used (which may vary according to the device). To disable the default page transition effect, set **duration** to **0**.|
| PageTransitionExit | {<br>type?: RouteType,<br>duration?: number,<br>curve?: [Curve](ts-appendix-enums.md#curve) \| string,<br>delay?: number<br>} | No | Page exit animation.<br>- **type**: route type for the page transition effect to take effect.<br>Default value: **RouteType.None**<br>- **duration**: animation duration.<br>Unit: ms<br>Default value: **1000**<br>- **curve**: animation curve. The value range of the string type is the same as that of **PageTransitionEnter**.<br>Default value: **Curve.Linear**<br>- **delay**: animation delay.<br>Unit: ms<br>Default value: **0**<br>**NOTE**<br>If no match is found, the default page transition effect is used (which may vary according to the device). To disable the default page transition effect, set **duration** to **0**.|
| PageTransitionEnter | {<br>type?: RouteType,<br>duration?: number,<br>curve?: [Curve](ts-appendix-enums.md#curve) \| string \| [ICurve](../apis/js-apis-curve.md#icurve)<sup>10+</sup>,<br>delay?: number<br>} | No | Page entrance animation.<br>- **type**: route type for the page transition effect to take effect.<br>Default value: **RouteType.None**<br>- **duration**: animation duration.<br>Unit: ms<br>Default value: **1000**<br>- **curve**: animation curve. The value of the string type can be any of the following: "ease", "ease-in", "ease-out", "ease-in-out", "extreme-deceleration", "fast-out-linear-in", "fast-out-slow-in", "friction", "linear", "linear-out-slow-in", "rhythm", "sharp", "smooth".<br>Default value: **Curve.Linear**<br>- **delay**: animation delay.<br>Unit: ms<br>Default value: **0**<br>**NOTE**<br>If no match is found, the default page transition effect is used (which may vary according to the device). To disable the default page transition effect, set **duration** to **0**.|
| PageTransitionExit | {<br>type?: RouteType,<br>duration?: number,<br>curve?: [Curve](ts-appendix-enums.md#curve) \| string \| [ICurve](../apis/js-apis-curve.md#icurve)<sup>10+</sup>,<br>delay?: number<br>} | No | Page exit animation.<br>- **type**: route type for the page transition effect to take effect.<br>Default value: **RouteType.None**<br>- **duration**: animation duration.<br>Unit: ms<br>Default value: **1000**<br>- **curve**: animation curve. The value range of the string type is the same as that of **PageTransitionEnter**.<br>Default value: **Curve.Linear**<br>- **delay**: animation delay.<br>Unit: ms<br>Default value: **0**<br>**NOTE**<br>If no match is found, the default page transition effect is used (which may vary according to the device). To disable the default page transition effect, set **duration** to **0**.|
## RouteType
......
......@@ -12,7 +12,7 @@ A shared element transition is a transition animation applied to a component tha
| Name | Parameter | Description |
| ---------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| sharedTransition | id: string,<br>{<br> duration?: number,<br> curve?: Curve \| string,<br> delay?: number,<br> motionPath?: <br>{<br> path: string,<br> form?: number,<br> to?: number,<br> rotatable?: boolean<br>},<br>zIndex?: number,<br>type?: [SharedTransitionEffectType](ts-appendix-enums.md#sharedtransitioneffecttype)<br>} | Transition of the shared element. If the same **id** value is configured for a component on the two pages, this component is considered as a shared element of the pages. If the **id** value is an empty string, no transition will be applied to the component.<br>- **id**: component ID.<br>- **duration**: animation duration.<br>Default value: **1000**<br>Unit: ms<br>Value range: [0, +∞)<br>The value **0** indicates that no animation is applied. A value less than 0 evaluates to the default value **1000**.<br>- **curve**: animation curve. The default curve is **Linear**. For details about the valid values, see [Curve](ts-animatorproperty.md).<br>- **delay**: animation delay.<br>Default value: **0**<br>Unit: ms<br>Value range: [0, +∞)<br>A value less than 0 evaluates to the value **0**.<br>- **motionPath**: motion path information. For details, see [Motion Path Animation](ts-motion-path-animation.md).<br>- **path**: path.<br>- **from**: start value.<br>- **to**: end value.<br>- **rotatable**: whether to rotate.<br>- **zIndex**: z-axis.<br>- **type**: animation type.|
| sharedTransition | id: string,<br>{<br> duration?: number,<br> curve?: [Curve](ts-appendix-enums.md#curve) \| string \| [ICurve](../apis/js-apis-curve.md#icurve)<sup>10+</sup>,<br> delay?: number,<br> motionPath?: <br>{<br> path: string,<br> form?: number,<br> to?: number,<br> rotatable?: boolean<br>},<br>zIndex?: number,<br>type?: [SharedTransitionEffectType](ts-appendix-enums.md#sharedtransitioneffecttype)<br>} | Transition of the shared element. If the same **id** value is configured for a component on the two pages, this component is considered as a shared element of the pages. If the **id** value is an empty string, no transition will be applied to the component.<br>- **id**: component ID.<br>- **duration**: animation duration.<br>Default value: **1000**<br>Unit: ms<br>Value range: [0, +∞)<br>The value **0** indicates that no animation is applied. A value less than 0 evaluates to the default value **1000**.<br>- **curve**: animation curve. The default curve is **Curve.Linear**.<br>- **delay**: animation delay.<br>Default value: **0**<br>Unit: ms<br>Value range: [0, +∞)<br>A value less than 0 evaluates to the value **0**.<br>- **motionPath**: motion path information. For details, see [Motion Path Animation](ts-motion-path-animation.md).<br>- **path**: path.<br>- **from**: start value.<br>- **to**: end value.<br>- **rotatable**: whether to rotate.<br>- **zIndex**: z-axis.<br>- **type**: animation type.|
## Example
......
......@@ -40,14 +40,26 @@
- [Drawing Geometric Shapes (Shape)](arkts-geometric-shape-drawing.md)
- [Drawing Custom Graphics on the Canvas (Canvas)](arkts-drawing-customization-on-canvas.md)
- Using Animation
- [Animation Overview](arkts-animation-overview.md)
- Animation Within a Page
- [Layout Update Animation](arkts-layout-update-animation.md)
- [Transition Animation Within a Component](arkts-transition-animation-within-component.md)
- [Spring Curve Animation](arkts-spring-animation.md)
- Animation Between Pages
- [Zoom Animation](arkts-zoom-animation.md)
- [Page Transition Animation](arkts-page-transition-animation.md)
- [Animation Overview](arkts-animation.md)
- Attribute Animation
- [Attribute Animation Overview](arkts-attribute-animation-overview.md)
- [Attribute Animation APIs](arkts-attribute-animation-apis.md)
- [Custom Attribute Animation](arkts-custom-attribute-animation.md)
- Transition Animation
- [Transition Animation Overview](arkts-transition-overview.md)
- [Enter/Exit Transition](arkts-enter-exit-transition.md)
- [Navigation Transition](arkts-navigation-transition.md)
- [Modal Transition](arkts-modal-transition.md)
- [Shared Element Transition](arkts-shared-element-transition.md)
- [Component Animation](arkts-component-animation.md)
- Animation Curve
- [Traditional Curve](arkts-traditional-curve.md)
- [Spring Curve](arkts-spring-curve.md)
- [Animation Smoothing](arkts-animation-smoothing.md)
- Animation Effects
- [Blur Effect](arkts-blur-effect.md)
- [Shadow Effect](arkts-shadow-effect.md)
- [Color Effect](arkts-color-effect.md)
- Using Interaction Events
- [Interaction Event Overview](arkts-event-overview.md)
- Universal Events
......
# Animation Smoothing
When running animations, the UI is also interacting with users in real time. It must respond immediately to changes in user behavior. For example, if the user swipes up to exit in the midst of an application launch process, the UI should immediately transit from the startup animation to the exit animation, rather than finishing the startup animation before exiting. In the scenario where the animation triggered when the user lifts their fingers off the screen, the initial velocity of the animation must inherit the gesture speed, so as to avoid pauses caused by speed disconnection. For the preceding and similar scenarios, OpenHarmony provides efficient APIs for smoothing between animations and between animations and gestures.
## Smoothing Between Animations
Assume that there is a running animation for an animatable attribute. If the end value of the attribute changes due to an operation on the UI, just change the attribute value in the **animateTo** closure or change the input parameter value of the **animation** API to create an animation. OpenHarmony then automatically connects the previous animation with the current animation – the created animation.
```ts
import curves from '@ohos.curves'
// Step 1: Declare the related state variable.
@state scaleToggle: boolean = true;
...
Column() {
Button()
// Step 2: Set the declared state variable to the related animatable attribute API.
.scale(this.scaleToggle ? 1 : 0.5)
// Step 3: Change the state variable value through the click event, which then changes the attribute value.
.onclick(() => {
this.scaleToggle = !this.scaleToggle;
})
// Step 4: Enable the implicit animation. When the end value of the animation changes, the system automatically adds the smoothing animation.
.animation({
curve: curves.springMotion()
})
}
...
```
A complete example is as follows: By clicking **click**, you change the **scale** attribute of the red square. When you click **click** repeatedly, the end value of the **scale** attribute changes continuously, and the current animation smoothly moves towards the new end value of the **scale** attribute.
```ts
import curves from '@ohos.curves';
@Entry
@Component
struct AnimationToAnimationDemo {
@State isAnimation: boolean = false;
build() {
Column() {
Text('ArkUI')
.fontWeight(FontWeight.Bold)
.fontSize(12)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.borderRadius(10)
.backgroundColor(0xf56c6c)
.width(100)
.height(100)
.scale({ x: this.isAnimation ? 2 : 1, y: this.isAnimation ? 2 : 1 })
.animation({ curve: curves.springMotion(0.4, 0.8) })
Button('Click')
.margin({ top: 200 })
.onClick(() => {
this.isAnimation = !this.isAnimation;
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
```
![en-us_image_0000001599971890](figures/en-us_image_0000001599971890.gif)
## Smoothing Between Gestures and Animations
In scenarios where gestures are used, an attribute change is generally triggered when the user places or moves their finger (or fingers) on the screen, and continues after the user lifts their finger (or fingers) off the screen until the end value of the attributes is reached.
The initial velocity of the attribute change after the user lifts their finger (or fingers) should be consistent with the velocity of the attribute change at the moment before the user lifts their finger (or fingers). If the former is **0**, it feels like a running car stops suddenly, an unusual abrupt change not welcomed by users.
In cases where smoothing between gestures and animations is required, for example, when scrolling a list, you can apply a responsive spring curve for the attribute animation running when the user places or moves their finger (or fingers) on the screen; and apply a spring curve for the attribute animation running after the user lifts their finger (or fingers) off the screen. For the animation that uses the [springMotion](../reference/apis/js-apis-curve.md#curvesspringmotion9) curve, the attribute animation running when the user places or moves their finger (or fingers) on the screen automatically inherits the previous velocity and starts from where the previous animation leaves off.
```ts
import curves from '@ohos.curves'
// Step 1: Declare related state variables.
@state offsetX: number = 0;
@State offsetY: number = 0;
targetOffsetX: number = 100;
targetOffsetY: number = 100;
...
Column()
// Step 2: Set the declared state variables to the related animatable attribute APIs.
.translate({ x: this.offsetX, y: this.offsetY})
.gesture(
PanGesture({})
.onActionUpdate((event: GestureEvent) => {
// Step 3: Change the state variable value for the time when the user places or moves their finger (or fingers) on the screen and use reponsiveSpringMotion for movement toward the new value.
animateTo({
curve: curves.responsiveSpringMotion()
}, () => {
this.offsetX = event.offsetX;
this.offsetY = event.offsetY;
})
})
.onActionEnd(() => {
// Step 4: Set the end value of the state variable for after the user lifts their finger (or fingers), and use springMotion for movement toward the new value. The springMotion animation inherits the previous velocity.
animateTo({
curve: curves.SpringMotion()
}, () => {
this.offsetX = targetOffsetX;
this.offsetY = targetOffsetY;
})
})
)
...
```
Below is the complete sample code and effect.
```ts
import curves from '@ohos.curves';
@Entry
@Component
struct SpringMotionDemo {
@State positionX: number = 100;
@State positionY: number = 100;
diameter: number = 50;
build() {
Column() {
Row() {
Circle({ width: this.diameter, height: this.diameter })
.fill(Color.Blue)
.position({ x: this.positionX, y: this.positionY })
.onTouch((event: TouchEvent) => {
if (event.type === TouchType.Move) {
// When the user places or moves their finger on the screen, use the responsiveSpringMotion curve.
animateTo({ curve: curves.responsiveSpringMotion() }, () => {
// Subtract the radius so that the center of the ball moves to where the finger is placed.
this.positionX = event.touches[0].screenX - this.diameter / 2;
this.positionY = event.touches[0].screenY - this.diameter / 2;
console.info(`move, animateTo x:${this.positionX}, y:${this.positionY}`);
})
} else if (event.type === TouchType.Up) {
// After the user lifts their finger off the screen, use the springMotion curve.
animateTo({ curve: curves.springMotion() }, () => {
this.positionX = 100;
this.positionY = 100;
console.info(`touchUp, animateTo x:100, y:100`);
})
}
})
}
.width("100%").height("80%")
.clip(true) // If the ball moves beyond the parent component, it is invisible.
.backgroundColor(Color.Orange)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Start, justifyContent: FlexAlign.Center }) {
Text("Drag the ball").fontSize(16)
}
.width("100%")
Row() {
Text('Click position: [x: ' + Math.round(this.positionX) + ', y:' + Math.round(this.positionY) + ']').fontSize(16)
}
.padding(10)
.width("100%")
}.height('100%').width('100%')
}
}
```
![en-us_image_0000001647027001](figures/en-us_image_0000001647027001.gif)
# Animation Overview
The UI contains various components (such as time and wallpaper) that users can see when interacting with their devices. Attributes are APIs used to control the behavior of components. For example, you can adjust the location of a component on the screen through the location attribute.
In general cases, if the value of an attribute is changed, the UI will be updated accordingly. Animation can add smooth transition effects when the UI is updated. Let's look at an example. When the user touches an application icon on the home screen, the application window opens and replaces the home screen as the primary display area. In this application launch process, if no animation is added, the related attributes change immediately, and the application window directly replaces the home screen, resulting in a sense of visual discontinuity. By adding animation, we enable attribute changes to take place over time, thereby creating an illusion of visual continuity.
ArkUI provides a wide range of animation APIs (such as attribute animation and transition animation), which you can leverage to cause attributes to gradually change from the start value to the end value based on the specified settings. Although the attribute values are not absolutely continuous during the change, but rather discrete to some extent, what you finally see is a continuous animation, since human eyes retain persistence of vision. A change of the UI is called an animation frame, which corresponds to a screen refresh. An important indicator that determines the animation smoothness is the frame rate (FPS), that is, the number of animation frames per second. The higher the frame rate, the smoother the animation. In ArkUI, animation parameters include animation duration, animation curve, and more. As the main factor of the animation, the animation curve determines the law of attribute value changes. For example, with a linear animation curve, the attribute changes from the start value to the end value at a constant speed over the given duration. If the attribute changes too fast or too slow, the visual experience may suffer. Therefore, animation parameters, especially animation curves, must be well designed and adjusted to be tailored to use cases.
Animation APIs drive attribute values to continuously transit from one state to another according to the rule determined by the animation parameters, and thereby generate a continuous visual effect on the UI. This walkthrough demonstrates the steps and precautions to follow, for creating a fascinating animation experience for users. It is organized as follows.
![en-us_image_0000001595763076](figures/en-us_image_0000001595763076.png)
- Attribute animation: It is the most basic animation type. It drives attribute changes frame by frame based on animation parameters to create an animation on a frame-by-frame basis.
- Transition animation: animation for transitioning when components appear and disappear. To maintain animation consistency, some animation curves have been built in and cannot be customized.
- Whenever possible, avoid ability redirection in the animation. An ability is a task in effect and is individually displayed on the recent tasks screen. Redirection between abilities is redirection between tasks. In the typical scenario of viewing large images in an application, if you call the gallery ability from the application to open large images, then the gallery ability will appear on the recent tasks screen. This is not recommended. A more recommended practice is as follows: Build a large image component in the application and invoke that component through modal transition. In this way, the entire animation can be completed in one ability.
- To implement navigation, use the **\<Navigation>** component, instead of the page routing mode. The page routing mode causes page separation, which is inconvenient for implementing linked transition effects. In addition, it does not allow for one-time development for multi-device deployment.
- Component animation: Components provide default animations (such as the slide animation of the **\<List>** component). Some of them even support custom animations.
- Animation curve: You can use traditional and spring curves to control how the attribute values change, to create an engaging animation effect.
- Animation connection: Make the transition between animations and between gestures and animations as natural as possible.
- Advanced animation effect: You can up your animation game with advanced effects such as blur, shadow, color gradient, and the like.
# Attribute Animation APIs
ArkUI provides two types of APIs, namely, [animateTo](../reference/arkui-ts/ts-explicit-animation.md) and [animation](../reference/arkui-ts/ts-animatorproperty.md), to implement an attribute animation – a visual illusion of continuity created by driving component attributes to change over time based on animation parameters such as the animation curve.
| API| Scope| Principle| Description|
| -------- | -------- | -------- | -------- |
| animateTo | GUI changes caused by attribute changes in closures.<br>Transition for appearance and disappearance.| As a general function, animates the differences between the UIs before and after the state variable in the closure is changed.<br>This API can be called multiple times and can be nested.| Applicable when a single set of animation parameters is used to animate multiple attributes.<br>Applicable when animations need to be nested.|
| animation | GUI changes caused by attribute changes bound to components through attribute APIs.| Identifies the change of the animatable attributes of a component and automatically adds an animation.<br>As the API call sequence of the component is from bottom to top, this API applies only to the attributes above it.<br>In a component, you can set individual **animation** for attributes based on the call sequence.| Applicable when different sets of animation parameters are used to animate different attributes.|
## Using animateTo
```
animateTo(value: AnimateParam, event: () => void): void
```
Among the parameters of [animateTo](../reference/arkui-ts/ts-explicit-animation.md), **value** indicates the [animation parameters](../reference/arkui-ts/ts-explicit-animation.md#animateparam) (including duration and [curve](../reference/apis/js-apis-curve.md#curve); **event** indicates the closure of the animation. Attribute animations generated by variable changes within the closure follow the same animation parameters.
```ts
import curves from '@ohos.curves'
@Entry
@Component
struct AnimateToDemo {
@State animate: boolean = false;
// Step 1: Declare related state variables.
@State rotateValue: number = 0; // Rotation angle of component 1.
@State translateY: number = 0; // Offset of component 2
@State opacityValue: number = 1; // Opacity of component 2.
//Step 2: Set the declared state variables to the related animatable attribute APIs.
build() {
Column() {
// Component 1
Column() {
Text('ArkUI')
.fontWeight(FontWeight.Bold)
.fontSize(20)
.fontColor(Color.White)
}
.justifyContent(FlexAlign.Center)
.width(150)
.height(150)
.borderRadius(10)
.rotate({ angle: this.rotateValue })
.backgroundColor(0xf56c6c)
// Component 2
Column() {
Text('ArkUI')
.fontWeight(FontWeight.Bold)
.fontSize(20)
.fontColor(Color.White)
}
.justifyContent(FlexAlign.Center)
.width(150)
.height(150)
.backgroundColor(0x67C23A)
.borderRadius(10)
.opacity(this.opacityValue)
.translate({ y: this.translateY })
Button('Click')
.margin({ top: 120 })
.onClick(() => {
this.animate = !this.animate;
// Step 3: Enable the implicit animation.
animateTo({ curve: curves.springMotion() }, () => {
// Step 4: Change the state variables in the closure to update the UI.
// You can write any logic that can change the UI, such as array adding and visibility control. The system detects the differences between the new UI and the previous UI and adds animations for the differences.
// The rotate attribute of component 1 is changed. Therefore, a rotate animation is added to component 1.
this.rotateValue = this.animate ? 90 : 0;
// The scale attribute of component 2 is changed. Therefore, a scale animation is added to component 2.
this.opacityValue = this.animate ? 0.6 : 1;
// The offset attribute of component 2 is changed. Therefore, an offset animation is added to component 2.
this.translateY = this.animate ? 100 : 0;
})
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
```
![en-us_image_0000001599958466](figures/en-us_image_0000001599958466.gif)
## Using animation
Compared with the **animateTo** API, the [animation](../reference/arkui-ts/ts-animatorproperty.md) API does not need to use a closure. Just add it to the end of the target animatable attribute. Then the API automatically adds an attribute animation as long as it detects that the bound attribute is changed.
```ts
import curves from '@ohos.curves';
@Entry
@Component
struct AnimationDemo {
@State animate: boolean = false;
// Step 1: Declare related state variables.
@State rotateValue: number = 0; // Rotation angle of component 1.
@State translateY: number = 0; // Offset of component 2
@State color: Color = Color.White; // Font color of component 2.
@State opacityValue: number = 1; // Opacity of the parent component.
//Step 2: Set the declared state variables to the related animatable attribute APIs.
build() {
Column() {
Column() {
// Component 1
Text('ArkUI')
.fontWeight(FontWeight.Bold)
.fontSize(20)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.borderRadius(10)
.backgroundColor(0xf56c6c)
.rotate({ angle: this.rotateValue })
// Step 3: Enable the implicit animation. As the API call sequence of the component is from bottom to top, the API takes effect on the rotate attribute.
.animation({ curve: curves.springMotion(0.3, 1.0) })
.width(150)
.height(150)
// Component 2
Text('ArkUI')
.fontWeight(FontWeight.Bold)
.fontSize(20)
.fontColor(this.color)
// Step 3: Enable the implicit animation. As the API call sequence of the component is from bottom to top, the API takes effect on the fontColor attribute.
.animation({ curve: curves.springMotion(0.6, 1.2) })
.textAlign(TextAlign.Center)
.borderRadius(10)
.backgroundColor(0x67C23A)
.width(150)
.height(150)
.translate({ y: this.translateY })
// Step 3: Enable the implicit animation. As the API call sequence of the component is from bottom to top, the API takes effect on the translate attribute.
.animation({ curve: curves.springMotion(0.3, 0.6) })
}
.justifyContent(FlexAlign.Center)
.opacity(this.opacityValue)
// The animation API takes effect on the opacity attribute. This results in an opacity change of the parent component <Column>, which in turn results in an opacity change of its child components. Therefore, animations are added to the opacity attributes of <Column> and its child components.
.animation({ curve: curves.springMotion() })
// Step 4: Change the state variable to update the UI. The system detects the differences between the new UI and the previous UI and adds animations for the differences.
Button('Click')
.margin({ top: 120 })
.onClick(() => {
this.animate = !this.animate;
// The rotate attribute of component 1 is changed. Therefore, a rotate animation is added to component 1.
this.rotateValue = this.animate ? 90 : 0;
// The translate attribute of component 2 is changed. Therefore, a translate animation is added to component 2.
this.translateY = this.animate ? 100 : 0;
// The fontColor attribute of component 2 is changed. Therefore, a fontColor animation is added to component 2.
this.color = this.animate ? Color.Black : Color.White;
// The opacity attribute of the parent component <Column> is changed, which results in an opacity change of its child components. Therefore, opacity animations are added to <Column> and its child components.
this.opacityValue = this.animate ? 0.6 : 1;
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
```
![en-us_image_0000001649279705](figures/en-us_image_0000001649279705.gif)
> **NOTE**
> - When an animation is applied to the position or size change of a component, as layout measurement is involved, performance overheads are high. To reduce performance overheads, use the [scale](../reference/arkui-ts/ts-universal-attributes-transformation.md) instead, whose value change does not involve layout measurement. This practice is applicable where the component location and size change continuously, for example, where the component size changes as a response to gestures.
>
> - Attribute animations should be applied to the components that are always present. For the components that may appear or disappear, use the [transition animation](arkts-transition-overview.md).
>
> - Avoid using callbacks invoked when an animation ends. Implicit animations are applied to states that have occurred. You do not need to process the end logic. If such callbacks are needed, be sure to handle the data management of continuous operations correctly.
# Attribute Animation Overview
An attribute API (attribute for short) defines a multitude of attributes, such as size, layout, and location, for controlling behavior of the owning component. Changes to some attributes (such as location) on the UI will cause UI re-render. You can animate the value change of an attribute from the start point to the end point. Attributes can be classified as animatable or non-animatable, depending on whether an animation can be applied to their value changes. Specifically, an animatable attribute meets the following requirements:
1. Its value changes can cause UI re-render. For example, the [enabled](../reference/arkui-ts/ts-universal-attributes-enable.md) attribute is used to control whether a component can respond to events such as clicks and touches. However, as its value change does not cause UI re-render, it does not qualify as an animatable attribute.
2. An animation can be applied to the transition between value changes. For example, the [focusable](../reference/arkui-ts/ts-universal-attributes-focus.md) attribute determines whether the current component can obtain focus. If the value of this attribute changes, the component should immediately switch to the end state to respond to user behavior, and no animation is appropriate here. Therefore, the attribute does not qualify as an animatable attribute.
**Attribute classification:**
- Animatable attributes:
- Built-in animatable attributes
| Category | Example |
| -------- | ---------------------------------------------- |
| Layout| Position, size, padding, margin, alignment, and weight.|
| Affine transformation| Translation, rotation, scaling, and anchor. |
| Background | Background color and blur. |
| Content | Font size, font color, image alignment, and blur. |
| Foreground | Foreground color. |
| Overlay | Overlay. |
| Appearance | Opacity, rounded corner, border, and shadow. |
| ... | ... |
- Custom animatable attributes: animatable attributes abstracted through the custom attribute animation mechanism.
- Non-animatable attributes: **zIndex** and **focusable**, among others.
Generally, an animatable attribute accepts only continuous parameters, which allows for using interpolation to fill in gaps between data points, so as to create a visual illusion of continuity. That said, whether the parameter type of an attribute can be interpolated is not a key factor that determines whether an animation can be applied to the attribute. For example, with regard to the [direction](../reference/arkui-ts/ts-universal-attributes-location.md) attribute, which sets the horizontal layout of an element, as it is animatable, ArkUI allows you to apply an animation to the transition between its value changes, though its parameter type is enum.
Animatable attributes include both built-in and custom attributes.
- Built-in animatable attributes: system-provided component attributes for changing the UI, for example, position, zoom, and blur attributes.
- [Custom animatable attributes](../quick-start/arkts-animatable-extend.md): attributes made animatable with the use of the [@AnimatableExtend](../quick-start/arkts-animatable-extend.md) decorator. You can abstract animatable attributes from the custom drawing content to control the drawing content of each frame, for example, customizing the volume icon. By defining custom animatable attributes, you can apply animations to some attributes that otherwise do not support animations in ArkUI.
# Blur Effect
Animation effects can add detail to your animations and create a sense of realism. For example, blur and shadow effects can lend a 3D look to objects and deliver a more engaging animation experience. ArkUI provides a diverse array of efficient APIs for you to develop exquisite and personalized effects. This topic covers the common blur, shadow, and color effects.
Blur effects add a sense of depth and allow for distinction of hierarchical relationship between elements.
| API | Description |
| ---------------------------------------- | ---------------------- |
| [backdropBlur](../reference/arkui-ts/ts-universal-attributes-image-effect.md) | Applies a background blur effect to the component. The input parameter is the blur radius.|
| [blur](../reference/arkui-ts/ts-universal-attributes-image-effect.md) | Applies a foreground blur effect to the component. The input parameter is the blur radius.|
| [backgroundBlurStyle](../reference/arkui-ts/ts-universal-attributes-background.md) | Applies a background blur effect to the component. The input parameter is the blur style.|
| [foregroundBlurStyle](../reference/arkui-ts/ts-universal-attributes-foreground-blur-style.md) | Applies a foreground blur effect to the component. The input parameter is the blur style.|
## Applying Background Blur with backdropBlur
```ts
@Entry
@Component
struct BlurEffectsExample {
build() {
Column({ space: 10 }) {
Text('backdropblur')
.width('90%')
.height('90%')
.fontSize(20)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.backdropBlur(10) // Apply background blur.
.backgroundImage($r('app.media.share'))
.backgroundImageSize({ width: 400, height: 300 })
}
.width('100%')
.height('50%')
.margin({ top: 20 })
}
}
```
![en-us_image_0000001599812870](figures/en-us_image_0000001599812870.png)
## Applying Foreground Blur with blur
```ts
@Entry
@Component
struct Index {
@State radius: number = 0;
@State text: string = '';
@State y: string = 'Finger not on the screen';
aboutToAppear() {
this.text = "Press a finger on the screen and slide up and down\n" + "Current finger position on the y-axis: " + this.y +
"\n" + "Blur radius:" + this.radius;
}
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween }) {
Text(this.text)
.height(200)
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontFamily("cursive")
.fontStyle(FontStyle.Italic)
Image($r("app.media.wall"))
.blur(this.radius) // Apply foreground blur.
.height('100%')
.width("100%")
.objectFit(ImageFit.Cover)
}.height('100%')
.width("100%")
.onTouch((event: TouchEvent) => {
if (event.type === TouchType.Move) {
this.y = parseInt(event.touches[0].y.toString()).toString();
this.radius = parseInt(this.y) / 10; // Modify the blur radius based on the sliding distance.
}
if (event.type === TouchType.Up) {
this.radius = 0;
this.y = 'Finger off the screen';
}
this.text = "Press a finger on the screen and slide up and down\n" + "Current finger position on the y-axis: " + this.y +
"\n" + "Blur radius:" + this.radius;
})
}
}
```
![en-us_image_0000001599813588](figures/en-us_image_0000001599813588.gif)
## Applying Background Blur with backgroundBlurStyle
```ts
@Entry
@Component
struct BackDropBlurStyleDemo {
build() {
Grid() {
GridItem() {
Column() {
Column() {
Text ('Original')
.fontSize(20)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
}
.height(100)
.aspectRatio(1)
.borderRadius(10)
.backgroundImage($r('app.media.share'))
Text ('Original')
.fontSize(12)
.fontColor(Color.Black)
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.width(200)
.height(200)
GridItem() {
Column() {
Column() {
Text('Thin')
.fontSize(20)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
}
.height(100)
.aspectRatio(1)
.borderRadius(10)
.backgroundImage($r('app.media.share'))
// BlurStyle.Thin: Thin blur is applied.
// ThemeColorMode.LIGHT: The light color mode is used.
// AdaptiveColor.DEFAULT: Adaptive color mode is not used. The default color is used as the mask color.
// scale: blurredness of the background material. The default value is 1.
.backgroundBlurStyle(BlurStyle.Thin, {
colorMode: ThemeColorMode.LIGHT,
adaptiveColor: AdaptiveColor.DEFAULT,
scale: 0.1
})
Text('Thin')
.fontSize(12)
.fontColor(Color.Black)
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.width(200)
.height(200)
GridItem() {
Column() {
Column() {
Text('Regular')
.fontSize(20)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
}
.height(100)
.aspectRatio(1)
.borderRadius(10)
.backgroundImage($r('app.media.share'))
.backgroundBlurStyle(BlurStyle.Regular, {
colorMode: ThemeColorMode.LIGHT,
adaptiveColor: AdaptiveColor.DEFAULT,
scale: 0.1
})
Text('Regular')
.fontSize(12)
.fontColor(Color.Black)
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.width(200)
.height(200)
GridItem() {
Column() {
Column() {
Text('Thick')
.fontSize(20)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
}
.height(100)
.aspectRatio(1)
.borderRadius(10)
.backgroundImage($r('app.media.share'))
.backgroundBlurStyle(BlurStyle.Thick, {
colorMode: ThemeColorMode.LIGHT,
adaptiveColor: AdaptiveColor.DEFAULT,
scale: 0.1
})
Text('Thick')
.fontSize(12)
.fontColor(Color.Black)
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.width(200)
.height(200)
GridItem() {
Column() {
Column() {
Text('BACKGROUND_THIN')
.fontSize(12)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
}
.height(100)
.aspectRatio(1)
.borderRadius(10)
.backgroundImage($r('app.media.share'))
.backgroundBlurStyle(BlurStyle.BACKGROUND_THIN, {
colorMode: ThemeColorMode.LIGHT,
adaptiveColor: AdaptiveColor.DEFAULT,
scale: 0.1
})
Text('BACKGROUND_THIN')
.fontSize(12)
.fontColor(Color.Black)
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.width(200)
.height(200)
GridItem() {
Column() {
Column() {
Text('BACKGROUND_REGULAR')
.fontSize(12)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
}
.height(100)
.aspectRatio(1)
.borderRadius(10)
.backgroundImage($r('app.media.share'))
.backgroundBlurStyle(BlurStyle.BACKGROUND_REGULAR, {
colorMode: ThemeColorMode.LIGHT,
adaptiveColor: AdaptiveColor.DEFAULT,
scale: 0.1
})
Text('BACKGROUND_REGULAR')
.fontSize(12)
.fontColor(Color.Black)
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.width(200)
.height(200)
GridItem() {
Column() {
Column() {
Text('BACKGROUND_THICK')
.fontSize(12)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
}
.height(100)
.aspectRatio(1)
.borderRadius(10)
.backgroundImage($r('app.media.share'))
.backgroundBlurStyle(BlurStyle.BACKGROUND_THICK, {
colorMode: ThemeColorMode.LIGHT,
adaptiveColor: AdaptiveColor.DEFAULT,
scale: 0.1
})
Text('BACKGROUND_THICK')
.fontSize(12)
.fontColor(Color.Black)
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.width(200)
.height(200)
GridItem() {
Column() {
Column() {
Text('BACKGROUND_ULTRA_THICK')
.fontSize(12)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
}
.height(100)
.aspectRatio(1)
.borderRadius(10)
.backgroundImage($r('app.media.share'))
.backgroundBlurStyle(BlurStyle.BACKGROUND_ULTRA_THICK, {
colorMode: ThemeColorMode.LIGHT,
adaptiveColor: AdaptiveColor.DEFAULT,
scale: 0.1
})
Text('BACKGROUND_ULTRA_THICK')
.fontSize(12)
.fontColor(Color.Black)
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.width(200)
.height(200)
}
.columnsTemplate('1fr 1fr')
.rowsTemplate('1fr 1fr 1fr 1fr')
.width('100%')
.height('100%')
.margin({ top: 40 })
}
}
```
![en-us_image_0000001649455517](figures/en-us_image_0000001649455517.png)
## Applying Foreground Blur with foregroundBlurStyle
```ts
@Entry
@Component
struct ForegroundBlurStyleDemo {
build() {
Grid() {
GridItem() {
Column() {
Column() {
Text ('Original')
.fontSize(20)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
}
.height(100)
.aspectRatio(1)
.borderRadius(10)
.backgroundImage($r('app.media.share'))
Text ('Original')
.fontSize(12)
.fontColor(Color.Black)
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.width(200)
.height(200)
GridItem() {
Column() {
Column() {
Text('Thin')
.fontSize(20)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
}
.height(100)
.aspectRatio(1)
.borderRadius(10)
.backgroundImage($r('app.media.share'))
// BlurStyle.Thin: Thin blur is applied.
// ThemeColorMode.LIGHT: The light color mode is used.
// AdaptiveColor.DEFAULT: Adaptive color mode is not used. The default color is used as the mask color.
// scale: blurredness of the background material. The default value is 1.
.foregroundBlurStyle(BlurStyle.Thin, {
colorMode: ThemeColorMode.LIGHT,
adaptiveColor: AdaptiveColor.DEFAULT,
scale: 0.1
})
Text('Thin')
.fontSize(12)
.fontColor(Color.Black)
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.width(200)
.height(200)
GridItem() {
Column() {
Column() {
Text('Regular')
.fontSize(20)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
}
.height(100)
.aspectRatio(1)
.borderRadius(10)
.backgroundImage($r('app.media.share'))
.foregroundBlurStyle(BlurStyle.Regular, {
colorMode: ThemeColorMode.LIGHT,
adaptiveColor: AdaptiveColor.DEFAULT,
scale: 0.1
})
Text('Regular')
.fontSize(12)
.fontColor(Color.Black)
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.width(200)
.height(200)
GridItem() {
Column() {
Column() {
Text('Thick')
.fontSize(20)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
}
.height(100)
.aspectRatio(1)
.borderRadius(10)
.backgroundImage($r('app.media.share'))
.foregroundBlurStyle(BlurStyle.Thick, {
colorMode: ThemeColorMode.LIGHT,
adaptiveColor: AdaptiveColor.DEFAULT,
scale: 0.1
})
Text('Thick')
.fontSize(12)
.fontColor(Color.Black)
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.width(200)
.height(200)
GridItem() {
Column() {
Column() {
Text('BACKGROUND_THIN')
.fontSize(12)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
}
.height(100)
.aspectRatio(1)
.borderRadius(10)
.backgroundImage($r('app.media.share'))
.foregroundBlurStyle(BlurStyle.BACKGROUND_THIN, {
colorMode: ThemeColorMode.LIGHT,
adaptiveColor: AdaptiveColor.DEFAULT,
scale: 0.1
})
Text('BACKGROUND_THIN')
.fontSize(12)
.fontColor(Color.Black)
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.width(200)
.height(200)
GridItem() {
Column() {
Column() {
Text('BACKGROUND_REGULAR')
.fontSize(12)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
}
.height(100)
.aspectRatio(1)
.borderRadius(10)
.backgroundImage($r('app.media.share'))
.foregroundBlurStyle(BlurStyle.BACKGROUND_REGULAR, {
colorMode: ThemeColorMode.LIGHT,
adaptiveColor: AdaptiveColor.DEFAULT,
scale: 0.1
})
Text('BACKGROUND_REGULAR')
.fontSize(12)
.fontColor(Color.Black)
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.width(200)
.height(200)
GridItem() {
Column() {
Column() {
Text('BACKGROUND_THICK')
.fontSize(12)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
}
.height(100)
.aspectRatio(1)
.borderRadius(10)
.backgroundImage($r('app.media.share'))
.foregroundBlurStyle(BlurStyle.BACKGROUND_THICK, {
colorMode: ThemeColorMode.LIGHT,
adaptiveColor: AdaptiveColor.DEFAULT,
scale: 0.1
})
Text('BACKGROUND_THICK')
.fontSize(12)
.fontColor(Color.Black)
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.width(200)
.height(200)
GridItem() {
Column() {
Column() {
Text('BACKGROUND_ULTRA_THICK')
.fontSize(12)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
}
.height(100)
.aspectRatio(1)
.borderRadius(10)
.backgroundImage($r('app.media.share'))
.foregroundBlurStyle(BlurStyle.BACKGROUND_ULTRA_THICK, {
colorMode: ThemeColorMode.LIGHT,
adaptiveColor: AdaptiveColor.DEFAULT,
scale: 0.1
})
Text('BACKGROUND_ULTRA_THICK')
.fontSize(12)
.fontColor(Color.Black)
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.width(200)
.height(200)
}
.columnsTemplate('1fr 1fr')
.rowsTemplate('1fr 1fr 1fr 1fr')
.width('100%')
.height('100%')
.margin({ top: 40 })
}
}
```
![en-us_image_0000001599658168](figures/en-us_image_0000001599658168.png)
# Color Effect
## APIs
You can use the color gradient APIs to apply a background color gradient effect to a component.
| API| Description|
| -------- | -------- |
| [linearGradient](../reference/arkui-ts/ts-universal-attributes-gradient-color.md) | Applies a linear gradient to the component.|
| [sweepGradient](../reference/arkui-ts/ts-universal-attributes-gradient-color.md) | Applies a sweep gradient effect to the component.|
| [radialGradient](../reference/arkui-ts/ts-universal-attributes-gradient-color.md) | Applies a radial gradient effect to the component.|
## Applying Linear Gradient Effect
```ts
@Entry
@Component
struct LinearGradientDemo {
build() {
Grid() {
GridItem() {
Column() {
Text('angle: 180')
.fontSize(15)
}
.width(100)
.height(100)
.justifyContent(FlexAlign.Center)
.borderRadius(10)
.linearGradient({
// A positive value indicates a clockwise rotation from the origin, (0, 0). The default value of the linear gradient start angle is 180°.
colors: [
[0xf56c6c, 0.0], // Color and weight of color stop 1, corresponding to the start position of the component in the 180° direction.
[0xffffff, 1.0], // Color and weight of color stop 2, corresponding to the end position of the component in the 180° direction.
]
})
}
GridItem() {
Column() {
Text('angle: 45')
.fontSize(15)
}
.width(100)
.height(100)
.justifyContent(FlexAlign.Center)
.borderRadius(10)
.linearGradient({
angle: 45, // Set the linear gradient start angle to 45°.
colors: [
[0xf56c6c, 0.0],
[0xffffff, 1.0],
]
})
}
GridItem() {
Column() {
Text('repeat: true')
.fontSize(15)
}
.width(100)
.height(100)
.justifyContent(FlexAlign.Center)
.borderRadius(10)
.linearGradient({
repeating: true, // Repeat the gradients of the area from 0 to 0.3 in the area from 0.3 to 1.0.
colors: [
[0xf56c6c, 0.0],
[0xE6A23C, .3],
]
})
}
GridItem() {
Column() {
Text('repeat: fasle')
.fontSize(15)
}
.width(100)
.height(100)
.justifyContent(FlexAlign.Center)
.borderRadius(10)
.linearGradient({
colors: [
[0xf56c6c, 0.0], // As repeating is not specified, the default value false is used. In this case, only the area from 0 to 0.3 in the component have the color gradient effect.
[0xE6A23C, .3],
]
})
}
}
.columnsGap(10)
.rowsGap(10)
.columnsTemplate('1fr 1fr')
.rowsTemplate('1fr 1fr 1fr')
.width('100%')
.height('100%')
}
}
```
![en-us_image_0000001641176829](figures/en-us_image_0000001641176829.png)
## Applying Sweep Gradient Effect
```ts
@Entry
@Component
struct SweepGradientDemo {
build() {
Grid() {
GridItem() {
Column() {
Text('center: 50')
.fontSize(15)
}
.width(100)
.height(100)
.justifyContent(FlexAlign.Center)
.borderRadius(10)
.sweepGradient({
center: [50, 50], // Center point of the sweep gradient.
start: 0, // Start point of the sweep gradient.
end: 360, // End point of the sweep gradient.
repeating: true, // The gradients are repeated.
colors: [
// Based on the center point, start point, and end point settings,
// the color changes from color stop 1 to color stop 2 in the area within angles from 0 to 0.125;
// the color changes from color stop 2 to color stop 3 in the area within angles from 0.125 to 0.25;
// the color gradients of the area within angles from 0 to 0.25 are repeated in the area within angles from 0.25 to 1.
[0xf56c6c, 0], // Color and weight of color stop 1. The corresponding angle is 0° (0 x 360°), and the corner is the center point.
[0xffffff, 0.125], // Color and weight of color stop 2.
[0x409EFF, 0.25] // Color and weight of color stop 3.
]
})
}
GridItem() {
Column() {
Text('center: 0')
.fontSize(15)
}
.width(100)
.height(100)
.justifyContent(FlexAlign.Center)
.borderRadius(10)
.sweepGradient({
center: [0, 0], // Center point of the sweep gradient, which is the coordinate of the upper left corner of the component in this example.
start: 0,
end: 360,
repeating: true,
colors: [
// In the current component, the sweep gradient center is the upper left corner of the component. Therefore, the angle range from color stop 1 to color stop 3 can cover the entire component.
[0xf56c6c, 0], // Color and weight of color stop 1. The corresponding angle is 0° (0 x 360°)
[0xffffff, 0.125], // Color and weight of color stop 2. The corresponding angle is 45° (0.125 x 360°).
[0x409EFF, 0.25] // Color and weight of color stop 3. The corresponding angle is 90° (0.25 x 360°).
]
})
}
GridItem() {
Column() {
Text('repeat: true')
.fontSize(15)
}
.width(100)
.height(100)
.justifyContent(FlexAlign.Center)
.borderRadius(10)
.sweepGradient({
center: [50, 50],
start: 0,
end: 360,
repeating: true,
colors: [
[0xf56c6c, 0],
[0xffffff, 0.125],
[0x409EFF, 0.25]
]
})
}
GridItem() {
Column() {
Text('repeat: false')
.fontSize(15)
}
.width(100)
.height(100)
.justifyContent(FlexAlign.Center)
.borderRadius(10)
.sweepGradient({
center: [50, 50],
start: 0,
end: 360,
repeating: false, // The color gradient effect is generated only within the coverage of the color stop angles.
colors: [
[0xf56c6c, 0],
[0xffffff, 0.125],
[0x409EFF, 0.25]
]
})
}
}
.columnsGap(10)
.rowsGap(10)
.columnsTemplate('1fr 1fr')
.rowsTemplate('1fr 1fr 1fr')
.width('100%')
.height(437)
}
}
```
![en-us_image_0000001641177073](figures/en-us_image_0000001641177073.png)
## Applying Radial Gradient Effect
```ts
@Entry
@Component
struct radialGradientDemo {
build() {
Grid() {
GridItem() {
Column() {
Text('center: 50')
.fontSize(15)
}
.width(100)
.height(100)
.justifyContent(FlexAlign.Center)
.borderRadius(10)
.radialGradient({
center: [50, 50], // Center point of the radial gradient.
radius: 100, // Radius of the radial gradient.
repeating: true, // The gradients are repeated outside the specified range to fill the entire component.
colors: [
// With [50, 50] as the center point, the gradient changes from color stop 1 to color stop 2 within the range of radius 0 to 12.5;
// the gradient changes from color stop 2 to color stop 3 within the range of radius 12.5 to 25;
// the gradients in the range of radius 0 to 25 are repeated to fill the entire component.
[0xf56c6c, 0], // Color and weight of color stop 1. The corresponding radius is 0 (0 x 100).
[0xffffff, 0.125], // Color and weight of color stop 2. The corresponding radius is 12.5 (0.125 x 100).
[0x409EFF, 0.25] // Color and weight of color stop 3. The corresponding radius is 25 (0.25 x 100).
]
})
}
GridItem() {
Column() {
Text('center: 0')
.fontSize(15)
}
.width(100)
.height(100)
.justifyContent(FlexAlign.Center)
.borderRadius(10)
.radialGradient({
center: [0, 0], // Center point of the radial gradient, which is the coordinate of the upper left corner of the component in this example.
radius: 100,
repeating: true,
colors: [
[0xf56c6c, 0],
[0xffffff, 0.125],
[0x409EFF, 0.25]
]
})
}
GridItem() {
Column() {
Text('repeat: true')
.fontSize(15)
}
.width(100)
.height(100)
.justifyContent(FlexAlign.Center)
.borderRadius(10)
.radialGradient({
center: [50, 50],
radius: 100,
repeating: true,
colors: [
[0xf56c6c, 0],
[0xffffff, 0.125],
[0x409EFF, 0.25]
]
})
}
GridItem() {
Column() {
Text('repeat: false')
.fontSize(15)
}
.width(100)
.height(100)
.justifyContent(FlexAlign.Center)
.borderRadius(10)
.radialGradient({
center: [50, 50],
radius: 100,
repeating: false, // The gradients are not repeated.
colors: [
[0xf56c6c, 0],
[0xffffff, 0.125],
[0x409EFF, 0.25]
]
})
}
}
.columnsGap(10)
.rowsGap(10)
.columnsTemplate('1fr 1fr')
.rowsTemplate('1fr 1fr 1fr')
.width('100%')
.height('100%')
}
}
```
![en-us_image_0000001592904050](figures/en-us_image_0000001592904050.png)
# Component Animation
In addition to universal attribute animation and transition animation APIs, ArkUI provides default animation effects for certain components, for example, the swipe effect for the [\<List>](../reference/arkui-ts/ts-container-list.md) component and the click effect of the [\<Button>](../reference/arkui-ts/ts-basic-components-button.md#button) component. Based on these default animation effects, you can apply custom animations to the child components through the attribute animation and transition animation APIs.
## Using Default Component Animation
The default animation of a component exhibits the following features:
- Indicate the current state of the component. For example, after the user clicks a **\<Button>** component, the component turns gray, indicating that it is selected.
- Make UI interactions more intuitive and pleasurable.
- Reduce development workload, as the APIs are readily available.
For more effects, see [Component Overview](../reference/arkui-ts/ts-components-summary.md).
Below is the sample code and effect:
```ts
@Entry
@Component
struct ComponentDemo {
build() {
Row() {
Checkbox({ name: 'checkbox1', group: 'checkboxGroup' })
.select(true)
.selectedColor(0xed6f21)
.size({ width: 50, height: 50 })
Checkbox({ name: 'checkbox2', group: 'checkboxGroup' })
.select(false)
.selectedColor(0x39a2db)
.size({ width: 50, height: 50 })
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
```
![en-us_image_0000001649338585](figures/en-us_image_0000001649338585.gif)
## Customizing Component Animation
Some components allow for animation customization for their child components through the [attribute animation](arkts-attribute-animation-overview.md) and [transition animation](arkts-transition-overview.md) APIs. For example, in the [\<Scroll>](../reference/arkui-ts/ts-container-scroll.md) component, you can customize the animation effect for when scrolling through its child components.
- For a scroll or click gesture, you can implement various effects by changing affine attributes of the child component.
- To customize the animation for a scroll , you can add a listener to listen for scroll distance in the **onScroll** callback and calculate the affine attribute of each component. You can also define gestures, monitor positions through the gestures, and manually call **ScrollTo** to change the scrolled-to position.
- Fine-tune the final scrolled-to position in the **onScrollStop** callback or gesture end callback.
Below is the sample code and effect for customizing the scroll effect of the child components of the **\<Scroll>** component:
```ts
import curves from '@ohos.curves';
import window from '@ohos.window';
import display from '@ohos.display';
import mediaquery from '@ohos.mediaquery';
/**
* Encapsulates the WindowManager class.
*/
export class WindowManager {
private static instance: WindowManager = null;
private displayInfo: display.Display = null;
private orientationListener = mediaquery.matchMediaSync('(orientation: landscape)');
private portraitFunc = null;
constructor() {
this.portraitFunc = this.onPortrait.bind(this);
this.orientationListener.on('change', this.portraitFunc)
this.loadDisplayInfo()
}
/**
* Sets the main window.
* @param win Indicates the current application window.
*/
setMainWin(win: window.Window) {
if (win == null) {
return
}
globalThis.mainWin = win;
win.on("windowSizeChange", (data: window.Size) => {
if (globalThis.mainWindowSize == undefined || globalThis.mainWindowSize == null) {
globalThis.mainWindowSize = data;
} else {
if (globalThis.mainWindowSize.width == data.width && globalThis.mainWindowSize.height == data.height) {
return
}
globalThis.mainWindowSize = data;
}
let winWidth = this.getMainWindowWidth();
AppStorage.SetOrCreate<number>('mainWinWidth', winWidth)
let winHeight = this.getMainWindowHeight();
AppStorage.SetOrCreate<number>('mainWinHeight', winHeight)
globalThis.context.eventHub.emit("windowSizeChange", winWidth, winHeight)
})
}
static getInstance(): WindowManager {
if (this.instance == null) {
this.instance = new WindowManager();
}
return this.instance
}
private onPortrait(mediaQueryResult: mediaquery.MediaQueryResult) {
if (mediaQueryResult.matches == AppStorage.Get<boolean>('isLandscape')) {
return
}
AppStorage.SetOrCreate<boolean>('isLandscape', mediaQueryResult.matches)
this.loadDisplayInfo()
}
/**
* Changes the screen orientation.
* @param ori Indicates the orientation.
*/
changeOrientation(ori: window.Orientation) {
if (globalThis.mainWin != null) {
globalThis.mainWin.setPreferredOrientation(ori)
}
}
private loadDisplayInfo() {
this.displayInfo = display.getDefaultDisplaySync()
AppStorage.SetOrCreate<number>('displayWidth', this.getDisplayWidth())
AppStorage.SetOrCreate<number>('displayHeight', this.getDisplayHeight())
}
/**
* Obtains the width of the main window, in vp.
*/
getMainWindowWidth(): number {
return globalThis.mainWindowSize != null ? px2vp(globalThis.mainWindowSize.width) : 0
}
/**
* Obtains the height of the main window, in vp.
*/
getMainWindowHeight(): number {
return globalThis.mainWindowSize != null ? px2vp(globalThis.mainWindowSize.height) : 0
}
/**
* Obtains the screen width, in vp.
*/
getDisplayWidth(): number {
return this.displayInfo != null ? px2vp(this.displayInfo.width) : 0
}
/**
* Obtains the screen height, in vp.
*/
getDisplayHeight(): number {
return this.displayInfo != null ? px2vp(this.displayInfo.height) : 0
}
/**
* Releases resources.
*/
release() {
if (this.orientationListener) {
this.orientationListener.off('change', this.portraitFunc)
}
if (globalThis.mainWin != null) {
globalThis.mainWin.off('windowSizeChange')
}
WindowManager.instance = null;
}
}
/**
* Encapsulates the TaskData class.
*/
export class TaskData {
bgColor: Color | string | Resource = Color.White;
index: number = 0;
taskInfo: string = 'music';
constructor(bgColor: Color | string | Resource, index: number, taskInfo: string) {
this.bgColor = bgColor;
this.index = index;
this.taskInfo = taskInfo;
}
}
export const taskDataArr: Array<TaskData> =
[
new TaskData(0xFA8072, 0, 'music'),
new TaskData(0xF4A460, 1, 'mall'),
new TaskData(0xFFFACD, 2, 'photos'),
new TaskData(0x98FB98, 3, 'setting'),
new TaskData(0x7FFFD4, 4, 'call'),
new TaskData(0x87CEFA, 5, 'music'),
new TaskData(0x7B68EE, 6, 'mall'),
new TaskData(0x909399, 7, 'photos'),
new TaskData(0x888888, 8, 'setting'),
new TaskData(0xFFC0CB, 9, 'call'),
new TaskData(0xFFC0CB, 10, 'music'),
new TaskData(0x888888, 11, 'mall'),
new TaskData(0x909399, 12, 'photos'),
new TaskData(0x7B68EE, 13, 'setting'),
new TaskData(0x87CEFA, 14, 'call'),
new TaskData(0x7FFFD4, 15, 'music'),
new TaskData(0x98FB98, 16, 'mall'),
new TaskData(0xFFFACD, 17, 'photos'),
new TaskData(0xF4A460, 18, 'setting'),
new TaskData(0xFA8072, 19, 'call'),
];
@Entry
@Component
export struct TaskSwitchMainPage {
displayWidth: number = WindowManager.getInstance().getDisplayWidth();
scroller: Scroller = new Scroller();
bgImage: Resource = $r('app.media.share');
cardSpace: number = 0; // Widget spacing
cardWidth: number = this.displayWidth / 2 - this.cardSpace / 2; // Widget width
cardHeight: number = 400; // Widget height
cardPosition: Array<number> = []; // Initial position of the widget
clickIndex: boolean = false;
@State taskViewOffsetX: number = 0;
@State cardOffset: number = this.displayWidth / 4;
lastCardOffset: number = this.cardOffset;
startTime: number
// Initial position of each widget
aboutToAppear() {
for (let i = 0; i < taskDataArr.length; i++) {
this.cardPosition[i] = i * (this.cardWidth + this.cardSpace);
}
}
// Position of each widget
getProgress(index: number): number {
let progress = (this.cardOffset + this.cardPosition[index] - this.taskViewOffsetX + this.cardWidth / 2) / this.displayWidth;
return progress
}
build() {
Stack({ alignContent: Alignment.Bottom }) {
// Background
Column()
.width('100%')
.height('100%')
.backgroundColor(0xF0F0F0)
// <Scroll> component
Scroll(this.scroller) {
Row({ space: this.cardSpace }) {
ForEach(taskDataArr, (item, index) => {
Column()
.width(this.cardWidth)
.height(this.cardHeight)
.backgroundColor(item.bgColor)
.borderStyle(BorderStyle.Solid)
.borderWidth(1)
.borderColor(0xAFEEEE)
.borderRadius(15)
// Calculate the affine attributes of child components.
.scale((this.getProgress(index) >= 0.4 && this.getProgress(index) <= 0.6) ?
{
x: 1.1 - Math.abs(0.5 - this.getProgress(index)),
y: 1.1 - Math.abs(0.5 - this.getProgress(index))
} :
{ x: 1, y: 1 })
.animation({ curve: Curve.Smooth })
// Apply a pan animation.
.translate({ x: this.cardOffset })
.animation({ curve: curves.springMotion() })
.zIndex((this.getProgress(index) >= 0.4 && this.getProgress(index) <= 0.6) ? 2 : 1)
}, item => item)
}
.width((this.cardWidth + this.cardSpace) * (taskDataArr.length + 1))
.height('100%')
}
.gesture(
GestureGroup(GestureMode.Parallel,
PanGesture({ direction: PanDirection.Horizontal, distance: 5 })
.onActionStart((event: GestureEvent) => {
this.startTime = event.timestamp;
})
.onActionUpdate((event: GestureEvent) => {
this.cardOffset = this.lastCardOffset + event.offsetX;
})
.onActionEnd((event: GestureEvent) => {
let time = event.timestamp - this.startTime;
let speed = event.offsetX / (time / 1000000000);
let moveX = Math.pow(speed, 2) / 7000 * (speed > 0 ? 1 : -1);
this.cardOffset += moveX;
// When panning left to a position beyond the rightmost position
let cardOffsetMax = -(taskDataArr.length - 1) * (this.displayWidth / 2);
if (this.cardOffset < cardOffsetMax) {
this.cardOffset = cardOffsetMax;
}
// When panning right to a position beyond the rightmost position
if (this.cardOffset > this.displayWidth / 4) {
this.cardOffset = this.displayWidth / 4;
}
// Processing when the pan distance is less than the minimum distance
let remainMargin = this.cardOffset % (this.displayWidth / 2);
if (remainMargin < 0) {
remainMargin = this.cardOffset % (this.displayWidth / 2) + this.displayWidth / 2;
}
if (remainMargin <= this.displayWidth / 4) {
this.cardOffset += this.displayWidth / 4 - remainMargin;
} else {
this.cardOffset -= this.displayWidth / 4 - (this.displayWidth / 2 - remainMargin);
}
// Record the pan offset.
this.lastCardOffset = this.cardOffset;
})
), GestureMask.IgnoreInternal)
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
// Move to the beginning and end positions.
Button('Move to first/last')
.backgroundColor(0x888888)
.margin({ bottom: 30 })
.onClick(() => {
this.clickIndex = !this.clickIndex;
if (this.clickIndex) {
this.cardOffset = this.displayWidth / 4;
} else {
this.cardOffset = this.displayWidth / 4 - (taskDataArr.length - 1) * this.displayWidth / 2;
}
this.lastCardOffset = this.cardOffset;
})
}
.width('100%')
.height('100%')
}
}
```
![en-us_image_0000001599808406](figures/en-us_image_0000001599808406.gif)
# Custom Attribute Animation
The attribute animation is an illusion of movement created on the UI when the value of an animatable attribute changes over time. It is implemented by setting continuous value changes of an attribute to the attribute API that can cause the UI re-render.
ArkUI provides the [@AnimatableExtend](../quick-start/arkts-animatable-extend.md) decorator for customizing animatable attribute APIs, which accepts only parameters of the number type or a custom type that implements [AnimtableArithmetic<T>](../quick-start/arkts-animatable-extend.md) to deliver continuous value changes. During execution of **animateTo** or **animation** with a custom animatable attribute API and the animatable data type, the frame-by-frame callback is used to change the value of a non-animatable attribute so that an animation effect can be applied to the attribute.
## Animating Font Size Changes with Number Data Type and \@AnimatableExtend Decorator
```ts
// Step 1: Use the @AnimatableExtend decorator to customize an animatable attribute API.
@AnimatableExtend(Text) function animatableFontSize(size: number) {
.fontSize(size) // Invoke the system attribute API.
}
@Entry
@Component
struct AnimatablePropertyExample {
@State fontSize: number = 20;
build() {
Column() {
Text("AnimatableProperty")
.animatableFontSize(this.fontSize) // Step 2: Set the custom animatable attribute API on the component.
.animation({ duration: 1000, curve: "ease" }) // Step 3: Bind an animation to the custom animatable attribute API.
Button("Play")
.onClick(() => {
this.fontSize = this.fontSize == 20 ? 36 : 20; // Step 4: Change the value of the custom animatable attribute to generate an animation.
})
}.width("100%")
.padding(10)
}
}
```
![en-us_image_0000001600119626](figures/en-us_image_0000001600119626.gif)
## Animating Polyline Changes with Custom Data Type and \@AnimatableExtend Decorator
```ts
declare type Point = [x: number, y: number];
// Define the parameter type of the animatable attribute API and implement the addition, subtraction, multiplication, and equivalence judgment functions in the AnimtableArithmetic<T> API.
class PointClass extends Array<number> {
constructor(value: Point) {
super(value[0], value[1])
}
add(rhs: PointClass): PointClass {
let result = new Array<number>() as Point;
for (let i = 0; i < 2; i++) {
result.push(rhs[i] + this[i])
}
return new PointClass(result);
}
subtract(rhs: PointClass): PointClass {
let result = new Array<number>() as Point;
for (let i = 0; i < 2; i++) {
result.push(this[i] - rhs[i]);
}
return new PointClass(result);
}
multiply(scale: number): PointClass {
let result = new Array<number>() as Point;
for (let i = 0; i < 2; i++) {
result.push(this[i] * scale)
}
return new PointClass(result);
}
}
// Define the parameter type of the animatable attribute API and implement the addition, subtraction, multiplication, and equivalence judgment functions in the AnimtableArithmetic<T> API.
// Template T supports nested implementation of the AnimtableArithmetic<T> type.
class PointVector extends Array<PointClass> implements AnimatableArithmetic<Array<Point>> {
constructor(initialValue: Array<Point>) {
super();
if (initialValue.length) {
initialValue.forEach(p => this.push(new PointClass(p)))
}
}
// implement the IAnimatableArithmetic interface
plus(rhs: PointVector): PointVector {
let result = new PointVector([]);
const len = Math.min(this.length, rhs.length)
for (let i = 0; i < len; i++) {
result.push(this[i].add(rhs[i]))
}
return result;
}
subtract(rhs: PointVector): PointVector {
let result = new PointVector([]);
const len = Math.min(this.length, rhs.length)
for (let i = 0; i < len; i++) {
result.push(this[i].subtract(rhs[i]))
}
return result;
}
multiply(scale: number): PointVector {
let result = new PointVector([]);
for (let i = 0; i < this.length; i++) {
result.push(this[i].multiply(scale))
}
return result;
}
equals(rhs: PointVector): boolean {
if (this.length !== rhs.length) {
return false;
}
for (let index = 0, size = this.length; index < size; ++index) {
if (this[index][0] !== rhs[index][0] || this[index][1] !== rhs[index][1]) {
return false;
}
}
return true;
}
}
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
// Define a custom animatable attribute API.
@AnimatableExtend(Polyline) function animatablePoints(points: PointVector) {
.points(points)
}
// Define a custom animatable attribute API.
@AnimatableExtend(Text) function animatableFontSize(size: number) {
.fontSize(size)
}
@Entry
@Component
struct AnimatedShape {
@State pointVec1: PointVector = new PointVector([
[50, randomInt(0, 200)],
[100, randomInt(0, 200)],
[150, randomInt(0, 200)],
[250, randomInt(0, 200)],
[350, randomInt(0, 200)]
]);
@State pointVec2: PointVector = new PointVector([
[70, randomInt(0, 200)],
[120, randomInt(0, 200)],
[180, randomInt(0, 200)],
[220, randomInt(0, 200)],
[320, randomInt(0, 200)]
]);
@State color: Color = Color.Green;
@State fontSize: number = 20.0;
@State polyline1Vec: PointVector = this.pointVec1;
@State polyline2Vec: PointVector = this.pointVec2;
build() {
Column() {
Text("AnimatableExtend test")
.width(400)
.height(30)
.margin(1)
.fontSize(25)
.textAlign(TextAlign.Center)
.backgroundColor("#ffee44")
.border({ width: '1vp', color: "#88ff00", radius: 20, style: BorderStyle.Solid })
Polyline()
.width(400)
.height(240)
.backgroundColor("#eeaacc")
.fill(this.color)
.stroke(Color.Red)
.animatablePoints(this.polyline1Vec)
.animation({ duration: 2000, delay: 0, curve: Curve.Ease })
Polyline()
.width(400)
.height(240)
.backgroundColor("#bbffcc")
.fill(this.color)
.stroke(Color.Red)
.animatablePoints(this.polyline2Vec)
.animation({ duration: 2000, delay: 0, curve: Curve.Ease })
Text("Animatable Fontsize")
.animatableFontSize(this.fontSize)
.animation({ duration: 2000, delay: 0, curve: Curve.Ease })
.width(400)
.height(150)
.margin(5)
.textAlign(TextAlign.Center)
.backgroundColor("#ffddcc")
.border({ width: '2vp', color: "#88ff00", radius: 20, style: BorderStyle.Solid })
.onClick(() => {
console.log("Text onClick()")
})
Row() {
Button("Polyline1 default")
.width(100).height(60)
.margin({ left: 5, right: 5 })
.onClick(() => {
if (this.polyline1Vec.equals(this.pointVec1)) {
this.polyline1Vec = this.pointVec2;
} else {
this.polyline1Vec = this.pointVec1;
}
})
Button("Polyline2 ANIM")
.width(100).height(60)
.onClick(() => {
if (this.polyline2Vec.equals(this.pointVec1)) {
this.polyline2Vec = this.pointVec2;
} else {
this.polyline2Vec = this.pointVec1;
}
})
Button("FontSize")
.width(100).height(60)
.margin({ left: 5, right: 5 })
.onClick(() => {
this.fontSize = (this.fontSize == 20.0) ? 40.0 : 20.0;
})
}
.alignItems(VerticalAlign.Center)
.margin(5)
}
.width('100%')
.alignItems(HorizontalAlign.Center)
}
}
```
![en-us_image_0000001592669598](figures/en-us_image_0000001592669598.gif)
......@@ -53,8 +53,8 @@ You can draw custom graphics on the canvas in any of the following ways:
// Configure the parameters of the CanvasRenderingContext2D and OffscreenCanvasRenderingContext2D objects, including whether to enable anti-aliasing. The value true indicates that anti-aliasing is enabled.
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
// Create an OffscreenCanvasRenderingContext2D object. width indicates the width of the offscreen canvas, and height indicates the height of the offscreen canvas.
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
// Create an OffscreenCanvas object. width indicates the width of the offscreen canvas, and height indicates the height of the offscreen canvas.
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
......@@ -63,10 +63,11 @@ You can draw custom graphics on the canvas in any of the following ways:
.height('100%')
.backgroundColor('#F5DC62')
.onReady(() =>{
var offContext = this.offCanvas.getContext("2d", this.settings)
// You can draw content here.
this.offContext.strokeRect(50, 50, 200, 150);
offContext.strokeRect(50, 50, 200, 150);
// Display the image rendered by the offscreen drawing value on the common canvas.
let image = this.offContext.transferToImageBitmap();
let image = this.offCanvas.transferToImageBitmap();
this.context.transferFromImageBitmap(image);
})
}
......@@ -154,7 +155,6 @@ Two modes are available for drawing with the **Canvas** component:
**OffscreenCanvasRenderingContext2D** and **CanvasRenderingContext2D** provide a large number of attributes and methods, which can be used to draw text and graphics and process pixels. They are the core of the **Canvas** component. Common APIs include [fill](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#fill), [clip](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#clip), and [stroke](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#stroke). In addition, [fillStyle](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#fillstyle), [globalAlpha](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#globalalpha), [strokeStyle](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#strokestyle), and more attributes are provided to spruce up the graphics. This topic describes typical usage of the canvas.
- Draw a basic shape.
You can draw a basic shape by calling APIs such as [arc](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#arc), [ellipse](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#ellipse), and [rect](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#rect).
```ts
......@@ -179,7 +179,7 @@ Two modes are available for drawing with the **Canvas** component:
```
![2023022794521(1)](figures/2023022794521(1).jpg)
![2023022794521(1)](figures/2023022794521(1).jpg)
- Draw text.
......@@ -212,7 +212,7 @@ Two modes are available for drawing with the **Canvas** component:
struct GetImageData {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
private img:ImageBitmap = new ImageBitmap("/common/images/1234.png")
build() {
......@@ -222,14 +222,15 @@ Two modes are available for drawing with the **Canvas** component:
.height('100%')
.backgroundColor('#F5DC62')
.onReady(() =>{
var offContext = this.offCanvas.getContext("2d", this.settings)
// Use the drawImage API to draw an image in the area with the width and height of 130 starting from (0, 0).
this.offContext.drawImage(this.img,0,0,130,130);
offContext.drawImage(this.img,0,0,130,130);
// Use the getImageData API to obtain the image data with the width and height of 130 starting from (50, 50).
let imagedata = this.offContext.getImageData(50,50,130,130);
let imagedata = offContext.getImageData(50,50,130,130);
// Use the putImageData API to draw the obtained image data in the area starting from (150, 150).
this.offContext.putImageData(imagedata,150,150);
offContext.putImageData(imagedata,150,150);
// Draw the offscreen drawing content to the canvas.
let image = this.offContext.transferToImageBitmap();
let image = this.offCanvas.transferToImageBitmap();
this.context.transferFromImageBitmap(image);
})
}
......
# Enter/Exit Transition
You can use [transition](../reference/arkui-ts/ts-transition-animation-component.md), a basic component transition API, to animate the appearance and disappearance of a component. You can even use it with [TransitionEffect](../reference/arkui-ts/ts-transition-animation-component.md#transitioneffect10) to up your animation game.
**Table 1** Transition effect APIs
| API | Description| Animation|
| -------- | -------- | -------- |
| IDENTITY | Disables the transition effect.| None.|
| OPACITY | Applies the default opacity transition effect.| The component appears by changing the opacity from 0 to 1 and disappears by changing the opacity from 1 to 0.|
| SLIDE | Applies a sliding transition effect.| The component appears by sliding in from the left edge of the window and disappears by sliding out from the right edge of the window.|
| translate | Applies a translation transition effect.| The component appears by moving from the position set by the **translate** API to the default position (value **0**), and disappears by moving from the default position (value **0**) to the position set by the **translate** API.|
| rotate | Applies a rotation transition effect.| The component appears by rotating from the position set by the **rotate** API to the default position (value **0**), and disappears by rotating from the default position (value **0**) to the position set by the **rotate** API.|
| opacity | Applies an opacity transition effect.| The component appears by changing the opacity from the set value to **1** (default value) and disappears by changing the opacity from **1** to the set value.|
| move | Applies a transition effect by specifying which edge the component slides in and out of through [TransitionEdge](../reference/arkui-ts/ts-appendix-enums.md#transitionedge10).| The component appears by sliding in from the edge specified by **TransitionEdge** and disappears by sliding out of the same edge.|
| asymmetric | Applies an asymmetric transition effect.<br>**appear**: transition effect for appearance.<br>**disappear**: transition effect for disappearance.| The component appears by applying the transition effect specified by **appear** and disappears by applying the transition effect specified by **disappear**.|
| combine | Combines with other transition effects.| The component appears and disappears by combing with other transition effects.|
| animation | Defines the animation settings for the transition effect.<br>- If animation settings are not specified here, the animation settings of **animateTo** will be used.<br>- Animation settings cannot be configured through the **animation** API of the component.<br>- The **onFinish** callback of the **animation** parameter in **TransitionEffect** does not take effect. | The API call sequence is from top to bottom. This means that the **animation** settings of **TransitionEffect** at the upper level also take effect on **TransitionEffect** at the lower level .|
1. Create a **TransitionEffect** object.
```ts
// The component appears by applying all transition effects for appearance and disappears by applying all transition effects for disappearance.
// Define the animation settings for each transition effect.
private effect: TransitionEffect =
TransitionEffect.OPACITY // Apply an opacity transition effect. As the animation API is not called here, the animation settings of animateTo are used.
// Apply a scaling transition effect and specify springMotion (0.6, 1.2) as the curve.
.combine(TransitionEffect.scale({ x: 0, y: 0 }).animation({curve: curves.springMotion(0.6, 1.2) }))
// Apply a rotation transition effect, whose animation settings follow TransitionEffect above, that is, springMotion (0.6, 1.2).
.combine(TransitionEffect.rotate({ angle: 90 }))
// Apply a translation transition effect, whose animation settings follow TransitionEffect above, that is, springMotion (0.6, 1.2).
.combine(TransitionEffect.translate({ x: 150, y: 150 })
// Apply a move transition effect and specify springMotion as the curve.
.combine(TransitionEffect.move(TransitionEdge.END)).animation({curve: curves.springMotion()}))
// Apply an asymmetric transition effect. As the animation API is not called here, the animation settings follow TransitionEffect above, that is, springMotion.
.combine(TransitionEffect.asymmetric(TransitionEffect.scale({ x: 0, y: 0 }), TransitionEffect.rotate({angle: 90})));
```
2. Set the transition effects to the component by calling [transition](../reference/arkui-ts/ts-transition-animation-component.md).
```ts
Text('test')
.transition(effect)
```
3. Add or delete the component to trigger transition.
```ts
@state isPresent: boolean = true;
...
if (isPresent) {
Text('test')
.transition(effect)
}
...
// Control the addition or deletion of the component.
// Method 1: Place the control variable in the animateTo closure. In this case, the transition effect for which the animation API is not call will follow the animation settings of animateTo.
animateTo({curve: curves.springMotion()}) {
this.isPresent = false;
}
// Method 2: Directly delete or add the component. In this case, the transition effects follow the animation settings specified by animation.
this.isPresent = false;
```
Below is the complete sample code and effect.
```ts
import curves from '@ohos.curves';
@Entry
@Component
struct TransitionEffectDemo {
@State isPresent: boolean = false;
// Step 1: Create a TransitionEffect object.
private effect: TransitionEffect =
// Apply the default opacity transition effect and specify springMotion (0.6, 0.8) as the curve.
TransitionEffect.OPACITY.animation({ curve: curves.springMotion(0.6, 0.8) })
// Combine with a scale transition effect, whose animation settings follow TransitionEffect above, that is, springMotion(0.6, 0.8).
.combine(TransitionEffect.scale({ x: 0, y: 0 }))
// Apply a rotation transition effect, whose animation settings follow TransitionEffect above, that is, springMotion(0.6, 0.8).
.combine(TransitionEffect.rotate({ angle: 90 }))
// Apply a translation transition effect, whose animation settings are specified by animation, which is springMotion().
.combine(TransitionEffect.translate({ y: 150 }).animation({ curve: curves.springMotion() }))
// Apply a movement transition effect, whose animation settings follow TransitionEffect above, that is, springMotion().
.combine(TransitionEffect.move(TransitionEdge.END))
build() {
Stack() {
if (this.isPresent) {
Column() {
Text('ArkUI')
.fontWeight(FontWeight.Bold)
.fontSize(20)
.fontColor(Color.White)
}
.justifyContent(FlexAlign.Center)
.width(150)
.height(150)
.borderRadius(10)
.backgroundColor(0xf56c6c)
// Step 2: Set the transition effects to the component through the transition API.
.transition(this.effect)
}
// Border
Column()
.width(155)
.height(155)
.border({
width: 5,
radius: 10,
color: Color.Black,
})
// Step 3: Add or delete the component to trigger transition. Control the addition or deletion of the component.
Button('Click')
.margin({ top: 320 })
.onClick(() => {
this.isPresent = !this.isPresent;
})
}
.width('100%')
.height('60%')
}
}
```
![en-us_image_0000001599818064](figures/en-us_image_0000001599818064.gif)
# Modal Transition
Modal transition is a type of transition achieved by a modal – a view that appears on top of the current view while the current view remains.
**Table 1** Modal transition APIs
| API| Description| Usage|
| -------- | -------- | -------- |
| [bindContentCover](../reference/arkui-ts/ts-universal-attributes-modal-transition.md) | Binds a modal to the component.| Use this API to display a custom modal. It can work with the transition animation and shared element animation to implement complex transition animation effects, for example, displaying an image in full in the modal upon the click of a thumbnail.|
| [bindSheet](../reference/arkui-ts/ts-universal-attributes-sheet-transition.md) | Binds a sheet to the component.| Use this API to display a custom sheet, for example, a sharing confirmation dialog box.|
| [bindMenu](../reference/arkui-ts/ts-universal-attributes-menu.md) | Binds a menu to the component, which is displayed when the component is clicked.| Use this API where a menu is required, for example, for the plus sign (+), a common menu indicator in applications.|
| [bindContextMenu](../reference/arkui-ts/ts-universal-attributes-menu.md) | Binds a context menu to the component, which is displayed when the user long-presses or right-clicks the component.| Use this API for components that bounce up when long-pressed, for example, home screen icons.|
| [bindPopup](../reference/arkui-ts/ts-universal-attributes-popup.md) | Binds a popup to the component.| Use this API to display a popup containing additional information about a component when the component is clicked.|
| if | Adds or deletes the component.| Use this API to display a temporary page in a certain state. In this mode, the return navigation needs to be implemented with a listener.|
## Creating Modal Transition with bindContentCover
You can bind a full-screen modal to a component through the [bindContentCover](../reference/arkui-ts/ts-universal-attributes-modal-transition.md) attribute. Better yet, with the **ModalTransition** parameter, you can apply a transition effect for when the component is inserted or deleted.
1. Define [bindContentCover](../reference/arkui-ts/ts-universal-attributes-modal-transition.md).
2. Define the modal view.
```ts
// Use @Builder to build a modal view.
@Builder MyBuilder() {
Column() {
Text('my model view')
}
// Use the transition API to implement the transition animation for component appearance and disappearance. The transition API must be added to the first component of the builder.
.transition(TransitionEffect.translate(y:300).animation({ curve: curves.springMotion(0.6, 0.8) }))
}
```
3. Call the modal API to display the modal. Implement an animation by using the animation or shared element transition APIs.
```ts
// Define the state variable to control the visibility of the modal.
@State isPresent: boolean = false;
Button('Click to present model view')
// Bind the modal to the component. ModalTransition indicates the transition mode of the modal. The value None means no transition animation for the modal.
.bindContentCover($$this.isPresent, this.MyBuilder, ModalTransition.None)
.onClick(() => {
// Change the state variable to display the modal.
this.isPresent = !this.isPresent;
})
```
Below is the complete sample code and effect.
```ts
import curves from '@ohos.curves';
@Entry
@Component
struct BindContentCoverDemo {
// Step 1: Define bindContentCover.
// Define the state variable to control the visibility of the modal.
@State isPresent: boolean = false;
// Step 2: Define the modal view.
// Use @Builder to build a modal view.
@Builder MyBuilder() {
Column() {
Column() {
Column() {
Text('back')
.fontSize(24)
.fontColor(Color.White)
}
.justifyContent(FlexAlign.Center)
.width(100)
.height(100)
.borderRadius(5)
.backgroundColor(0xf56c6c)
.onClick(() => {
this.isPresent = false;
})
}
.height('100%')
.width('100%')
.backgroundColor(0x909399)
.justifyContent(FlexAlign.Center)
.border({
radius: {
topLeft: 15,
topRight: 15,
}
})
}
.height('100%')
.justifyContent(FlexAlign.End)
// Use the transition API to implement the transition animation for component appearance and disappearance.
.transition(TransitionEffect.translate({ y: 1000 }).animation({ curve: curves.springMotion(0.6, 0.8) }))
}
build() {
Column() {
Column() {
Text('Click Me')
.fontSize(24)
.fontColor(Color.White)
}
// Step 3: Call the modal API to display the modal. Implement an animation by using the animation or shared element transition APIs.
.onClick(() => {
// Change the state variable to display the modal.
this.isPresent = !this.isPresent;
})
// Bind the modal to the component. ModalTransition indicates the transition mode of the modal. The value None means no transition animation for the modal.
.bindContentCover($$this.isPresent, this.MyBuilder(), ModalTransition.DEFAULT)
.justifyContent(FlexAlign.Center)
.backgroundColor(0XF56C6C)
.width(100)
.height(100)
.borderRadius(5)
}
.justifyContent(FlexAlign.Center)
.width('100%')
.height('100%')
}
}
```
![en-us_image_0000001646921957](figures/en-us_image_0000001646921957.gif)
## Creating Sheet Transition with bindSheet
You can bind a sheet to a component through the [bindSheet](../reference/arkui-ts/ts-universal-attributes-sheet-transition.md) attribute. You can also set the sheet to the preset or custom height for when the component is inserted. The process of creating a sheet transition is basically the same as that of creating a modal transition.
Below is the complete sample code and effect.
```ts
@Entry
@Component
struct BindSheetDemo {
// Define the state variable to control the sheet height.
@State sheetHeight: number = 300;
// Define the state variable to control the visibility of the drag bar.
@State showDragBar: boolean = true;
// Use @Builder to build a sheet view.
@Builder myBuilder() {
Column() {
Button("change height")
.margin(10)
.fontSize(20)
.onClick(() => {
this.sheetHeight = 500;
})
Button("Set Illegal height")
.margin(10)
.fontSize(20)
.onClick(() => {
this.sheetHeight = null;
})
Button("close dragbar")
.margin(10)
.fontSize(20)
.onClick(() => {
this.showDragBar = !this.showDragBar;
})
Button("close modal 1")
.margin(10)
.fontSize(20)
.onClick(() => {
this.isPresent = false;
})
}
.width('100%')
.height('100%')
}
// Define the state variable to control the visibility of the sheet.
@State isPresent: boolean = false;
build() {
Column() {
Button("Click to present sheet view")
.onClick(() => {
// Change the state variable to display the sheet.
this.isPresent = !this.isPresent;
})
.fontSize(20)
.margin(10)
// Bind the sheet to the component. You can specify the sheet height and whether to display the drag bar.
.bindSheet($$this.isPresent, this.myBuilder(), { height: this.sheetHeight, dragBar: this.showDragBar })
}
.justifyContent(FlexAlign.Center)
.width('100%')
.height('100%')
}
}
```
![en-us_image_0000001599977924](figures/en-us_image_0000001599977924.gif)
## Creating a Menu with bindMenu
You can bind a menu to component through the [bindMenu](../reference/arkui-ts/ts-universal-attributes-menu.md) attribute. The menu can then be triggered by clicking. Below is the complete sample code and effect.
```ts
@Entry
@Component
struct BindMenuDemo {
// Step 1: Define a data array to represent menu items.
private items = [
{
value:'Menu item 1',
action: () => {
console.info('handle Menu1 select')
}
},
{
value:'Menu item 2',
action: () => {
console.info('handle Menu2 select')
}
},
]
build() {
Column() {
Button('click')
.backgroundColor(0x409eff)
.borderRadius(5)
// Step 2: Bind the menu data to the component through bindMenu.
.bindMenu(this.items)
}
.justifyContent(FlexAlign.Center)
.width('100%')
.height(437)
}
}
```
![en-us_image_0000001599643478](figures/en-us_image_0000001599643478.gif)
## Creating a Context Menu with bindContextMenu
You can bind a context menu to component through the [bindContextMenu](../reference/arkui-ts/ts-universal-attributes-menu.md) attribute. The menu can then be triggered by long-pressing or right-clicking.
Below is the complete sample code and effect.
```ts
@Entry
@Component
struct BindContextMenuDemo {
private num: number[] = [1, 2, 3, 4];
private colors: Color[] = [0x67C23A, 0xE6A23C, 0xf56c6c, 0x909399];
// Use @Builder to build custom menu items.
@Builder MyMenu() {
Row() {
Column() {
ForEach(this.num, (item: number, index: number) => {
Row() {
Text(item.toString())
.fontSize(20)
.fontColor(Color.White)
}
.backgroundColor(this.colors[index])
.width('100%')
.aspectRatio(2)
.justifyContent(FlexAlign.Center)
})
}
.width('100%')
}
.width(150)
.justifyContent(FlexAlign.Center)
.padding(5)
}
build() {
Column() {
Column() {
Text('longPress')
.fontSize(20)
.fontColor(Color.White)
}
.justifyContent(FlexAlign.Center)
.width(170)
.height(50)
.bindContextMenu(this.MyMenu, ResponseType.LongPress)
.backgroundColor(0xf56c6c)
.borderRadius(5)
}
.justifyContent(FlexAlign.Center)
.width('100%')
.height(437)
}
}
```
![en-us_image_0000001600137920](figures/en-us_image_0000001600137920.gif)
## Creating a Popup with bindPopUp
You can bind a popup to a component through the [bindpopup](../reference/arkui-ts/ts-universal-attributes-popup.md) attribute, specifying its content, interaction logic, and display status.
Below is the complete sample code and effect.
```ts
@Entry
@Component
struct BindPopupDemo {
// Step 1: Define the state variable to control the visibility of the popup.
@State customPopup: boolean = false;
// Step 2: Use @Builder to build a custom popup.
@Builder popupBuilder() {
Column({ space: 2 }) {
Row().width(64)
.height(64)
.backgroundColor(0x409eff)
Text('Popup')
.fontSize(10)
.fontColor(Color.White)
}
.justifyContent(FlexAlign.SpaceAround)
.width(100)
.height(100)
.padding(5)
}
build() {
Column() {
Button('click')
// Step 4: Add a click event to control the visibility of the popup.
.onClick(() => {
this.customPopup = !this.customPopup;
})
.backgroundColor(0xf56c6c)
// Step 5: Bind the popup to the component through bindPopup.
.bindPopup(this.customPopup, {
builder: this.popupBuilder,
placement: Placement.Top,
maskColor: 0x33000000,
popupColor: 0xf56c6c,
enableArrow: true,
onStateChange: (e) => {
if (!e.isVisible) {
this.customPopup = false;
}
}
})
}
.justifyContent(FlexAlign.Center)
.width('100%')
.height(437)
}
}
```
![en-us_image_0000001649282285](figures/en-us_image_0000001649282285.gif)
## Creating Modal Transition with if
In addition to the preceding modal transition APIs, you can also use the **if** syntax to create a modal transition, eliminating the need for binding to the component and listening for state variable changes.
Below is the complete sample code and effect.
```ts
@Entry
@Component
struct ModalTransition1 {
// Step 1: Define a state variable to control page display.
@State isShow: boolean = false;
build() {
// Step 2: Define a stack layout to display the current view and modal view.
Stack() {
Column() {
Text('Page1')
.fontSize(40)
.fontColor(Color.White)
.fontWeight(FontWeight.Bolder)
Text('Click to transition')
.fontSize(15)
.fontColor(Color.White)
}
.justifyContent(FlexAlign.Center)
.width('100%')
.height('100%')
.linearGradient({
colors: [
[0xf56c6c, 0.0],
[0xffffff, 1.0]
]
})
// Step 3: Change the state variable to display the modal view.
.onClick(() => {
animateTo({ duration: 500 }, () => {
this.isShow = !this.isShow;
})
})
// Step 4: Define the modal view in if and display it at the top layer. Use if to control the appearance and disappearance of the modal view.
if (this.isShow) {
Column() {
Text('Page2')
.fontSize(40)
.fontColor(Color.Gray)
.fontWeight(FontWeight.Bolder)
Text('Click to transition')
.fontSize(15)
.fontColor(Color.Gray)
}
.justifyContent(FlexAlign.Start)
.width('100%')
.height('100%')
.linearGradient({
colors: [
[0xffffff, 0.0],
[0x409eff, 1.0]
]
})
// Step 5: Define the mode in which the modal view disappears.
.transition(TransitionEffect.OPACITY.combine(TransitionEffect.rotate({ angle: 90, y: 1 })))
.onClick(() => {
animateTo({ duration: 500 }, () => {
this.isShow = !this.isShow;
})
})
}
}
.width('100%')
.height('100%')
}
}
```
![en-us_image_0000001597792146](figures/en-us_image_0000001597792146.gif)
# Navigation Transition
Navigation transition is a transition animation that runs during the navigation from one view to another. The animation settings of the navigation transition are pre-defined and cannot be modified.
To implement the navigation transition, you are advised to use the [\<Navigation>](../reference/arkui-ts/ts-basic-components-navigation.md) component, complete with the [\<NavRouter>](../reference/arkui-ts/ts-basic-components-navrouter.md) and [\<NavDestination>](../reference/arkui-ts/ts-basic-components-navdestination.md) components.
Below is the complete sample code and effect.
```ts
@Entry
@Component
struct NavigationDemo {
private listArray: Array<number> = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
// Set the title bar menu, if a title bar is involved.
@Builder NavigationMenus() {
Column() {
Text('menu')
.fontColor('#182431')
.fontSize(14)
.lineHeight(19)
.opacity(0.4)
.margin({ top: 70 })
}
.alignItems(HorizontalAlign.Start)
}
build() {
Stack() {
Column() {
// Define the <Navigation> component, setting the display mode and title.
Navigation() {
// An <Input> component is defined here.
TextInput({ placeholder: 'search...' })
.width('90%')
.height(40)
.backgroundColor('#ededed')
.margin({ bottom: 10 })
// Define the level-1 navigation view through <List>.
List({ space: 12, initialIndex: 0 }) {
ForEach(this.listArray, (item) => {
ListItem() {
// Define the navigation transition through <NavRouter> and define the navigation destination through <NavDestination>. Parameters are transferred between views through state variables or regular variables between components.
// <NavRouter> must contain two child components. The first child component is the level-1 navigation view, and the second child component must be <NavDestination>, which specifies the navigation destination.
NavRouter() {
// First component: Level-1 navigation view.
Row() {
Row()
.width(40)
.height(40)
.backgroundColor('#a8a8a8')
.margin({ right: 12 })
.borderRadius(20)
Column() {
Text('Level-1 item')
.fontSize(16)
.lineHeight(21)
.fontWeight(FontWeight.Medium)
Text('Click to go to subitems')
.fontSize(13)
.lineHeight(21)
.fontColor('#a8a8a8')
}
.alignItems(HorizontalAlign.Start)
Blank()
Row()
.width(15)
.height(15)
.margin({ right: 12 })
.border({
width: { top: 2, right: 2 },
color: 0xcccccc
})
.rotate({ angle: 45 })
}
.borderRadius(15)
.shadow({ radius: 100, color: '#ededed' })
.width('90%')
.alignItems(VerticalAlign.Center)
.padding({ left: 16, top: 12, bottom: 12 })
.height(80)
// Second component: navigation destination
NavDestination() {
// Content of the destination view, which is generally a custom component.
Column() {
Text("Destination"+ item +" content ")
.fontSize(20)
.fontColor(Color.Black)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
}
.width('100%')
.height('100%')
.backgroundColor(0xf5f5f5)
}
.title('Destination page') // Title of the level-2 page.
}
}
.width('100%')
}, item => item)
}
.listDirection(Axis.Vertical)
.edgeEffect(EdgeEffect.Spring)
.sticky(StickyStyle.Header)
.chainAnimation(false)
.borderRadius(15)
.width('100%')
.height('100%')
}
.width('100%')
.mode(NavigationMode.Auto) // Set the display mode of the navigation bar to Auto.
.title('Navigation transition') // Set the title text.
.titleMode(NavigationTitleMode.Full) // Set the display mode of the page title bar.
.menus(this.NavigationMenus) // Set the title bar menu.
}
.width('100%')
}
}
}
```
![en-us_image_0000001588458252](figures/en-us_image_0000001588458252.gif)
# Shadow Effect
You can use the [shadow](../reference/arkui-ts/ts-universal-attributes-image-effect.md) API to apply a shadow effect to a component. Even better, you can set the parameter of this API to [ShadowOptions](../reference/arkui-ts/ts-universal-attributes-image-effect.md#shadowoptions) to customize the shadow effect. When the radius or color opacity in **ShadowOptions** is set to **0**, there is no shadow effect.
```ts
@Entry
@Component
struct ShadowOptionDemo {
build() {
Row() {
Column() {
Column() {
Text('shadowOption').fontSize(12)
}
.width(100)
.aspectRatio(1)
.margin(10)
.justifyContent(FlexAlign.Center)
.backgroundColor(Color.White)
.borderRadius(20)
.shadow({ radius: 10, color: Color.Gray })
Column() {
Text('shadowOption').fontSize(12)
}
.width(100)
.aspectRatio(1)
.margin(10)
.justifyContent(FlexAlign.Center)
.backgroundColor('#a8a888')
.borderRadius(20)
.shadow({ radius: 10, color: Color.Gray, offsetX: 20, offsetY: 20 })
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
.height('100%')
}
}
```
![en-us_image_0000001598502322](figures/en-us_image_0000001598502322.png)
# Shared Element Transition
Shared element transition is a type of transition achieved by animating the size and position between styles of the same or similar elements during page switching. It is typically used with the modal transition for combined effects. When used with transition and attribute animations, it can make its way into a wider range of use cases.
## Implementation with transition and Attribute Animation
This example implements a shared element transition for the scenario where, as a component is expanded, sibling components in the same container disappear or appear. Specifically, attribute animations are applied to width and height changes of a component before and after the expansion; enter/exit animations are applied to the sibling components as they disappear or disappear.
1. Build the component to be expanded, and build two pages for it through state variables: one for the normal state and one for the expanded state.
```ts
// Build two pages for the normal and expanded states of the same component, which are then used based on the declared state variables.
@Component
export struct MyExtendView {
// Declare the isExpand variable to be synced with the parent component.
@Link isExpand: boolean;
@State cardList: Array<CardData> = xxxx;
build() {
List() {
// Customize the expanded component as required.
if (this.isExpand) {
Text('expand')
.transition(TransitionEffect.translate(y:300).animation({ curve: curves.springMotion(0.6, 0.8) }))
}
ForEach(this.cardList, (item: CradData) => {
MyCard({ cardData: item })
})
}
.width(this.isExpand ? 200 : 500) // Define the attributes of the expanded component.
.animation({ curve: curves.springMotion()}) // Bind an animation to component attributes.
}
}
```
2. Expand the component to be expanded. Use state variables to control the disappearance or appearance of sibling components, and apply the enter/exit transition to the disappearance and appearance.
```ts
@State isExpand: boolean = false
...
List() {
// Control the appearance or disappearance of sibling components through the isExpand variable, and configure the enter/exit transition.
if (!this.isExpand) {
Text ('I appear in normal state')
.transition(TransitionEffect.translate(y:300).animation({ curve: curves.springMotion(0.6, 0.9) }))
}
MyExtendView({ isExpand: $isExpand })
.onClick(() => {
this.isExpand = !this.isExpand;
})
// Control the appearance or disappearance of sibling components through the isExpand variable, and configure the enter/exit transition.
if (this.isExpand) {
Text ('I appear in expanded state')
.transition(TransitionEffect.translate(y:300).animation({ curve: curves.springMotion() }))
}
}
...
```
Below is the complete sample code and effect.
```ts
// utils.ets
import curves from '@ohos.curves';
// Build two pages for the normal and expanded states of the same component, which are then used based on the declared state variables.
@Component
export struct share_transition_expand {
// Declare the isExpand variable to be synced with the parent component.
// Expand the component.
@Link isExpand: boolean;
// Currently expanded component.
@State curIndex: number = 0;
private listArray: Array<number> = [1, 2, 3, 4, 5, 6];
build() {
Column() {
List() {
ForEach(this.listArray, (item, index) => {
// Customize the expanded component as required.
if (!this.isExpand || this.curIndex == index) {
ListItem() {
Column() {
Row() {
Row()
.backgroundColor(Color.Pink)
.borderRadius(20)
.width(80)
.height(80)
Column() {
Text ('Click to expand Item' + item)
.fontSize(20)
Text ('Shared element transition')
.fontSize(12)
.fontColor(0x909399)
}
.alignItems(HorizontalAlign.Start)
.justifyContent(FlexAlign.SpaceAround)
.margin({ left: 10 })
.height(80)
}
.width('90%')
.height(100)
if (this.isExpand) {
Row() {
Text('Expanded state')
.fontSize(28)
.fontColor(0x909399)
.textAlign(TextAlign.Center)
.transition(TransitionEffect.OPACITY.animation({ curve: curves.springMotion(0.6, 0.9) }))
}
.width('90%')
.justifyContent(FlexAlign.Center)
}
}
.onClick(() => {
// Define the animation parameters for expanding and collapsing.
animateTo({ curve: curves.springMotion(0.6, 0.9) }, () => {
this.curIndex = index;
this.isExpand = !this.isExpand;
})
})
.width('90%')
.height(this.isExpand && this.curIndex == index ? '85%' : 100) // Define the attributes of the expanded component as required.
.alignItems(HorizontalAlign.Center)
.borderRadius(10)
.margin({ top: 15 })
.backgroundColor(Color.White)
.shadow({ radius: 20, color: 0x909399, offsetX: 20, offsetY: 10 })
// Control the appearance or disappearance of sibling components through the isExpand variable, and configure the enter/exit transition.
.transition(TransitionEffect.scale({ x: 0, y: 0 }).animation({ curve: curves.springMotion(0.3, 1.5) }))
}
.zIndex(this.curIndex == index ? 1 : 0)
}
})
}
.height('100%')
.alignListItem(ListItemAlign.Center)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Start)
}
}
```
```ts
// Index.ets
import { share_transition_expand } from './utils';
@Entry
@Component
struct ShareTransitionDemo {
@State isExpand: boolean = false;
build() {
Column() {
Text('Sibling nodes appear and disappear.')
.fontWeight(FontWeight.Bold)
.fontSize(30)
.fontColor(Color.Black)
.margin(10)
share_transition_expand({ isExpand: $isExpand })
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Start)
}
}
```
![en-us_image_0000001600653160](figures/en-us_image_0000001600653160.gif)
## Implementation with transition and zIndex
This example implements a shared element transition for the scenario where, as a component is expanded, it is displayed on the top of the container while sibling components in the same container stay. This is achieved with the use of **zIndex**. Specifically:
- Build two pages for the normal and expanded states of the same component, which are then used based on the declared state variables.
- Change the display level of components through the **zIndex** attribute. Set this attribute to **1** for the component in the expanded state and retain the default value **0** for other sibling components. In this way, the component in the expanded state will be displayed over the sibling components.
- With the **translate** attribute, move the component to the top of the parent container when it is expanded.
- Use a placeholder container so that the location of the sibling components remains unchanged. The outer container is placed as a placeholder, and the internal container changes the size.
Below is the complete sample code and effect.
```ts
// utils.ets
import curves from '@ohos.curves';
// Build two pages for the normal and expanded states of the same component, which are then used based on the declared state variables.
@Component
export struct share_zIndex_expand {
// Declare the isExpand variable to be synced with the parent component.
@Link isExpand: boolean;
@Link curIndex: number;
@State listArray: Array<number> = [1, 2, 3, 4, 5, 6];
private parentScroller: Scroller; // Upper-layer scroller controller.
build() {
Column() {
List() {
ForEach(this.listArray, (item, index) => {
// Customize the expanded component as required.
if (!this.isExpand || this.curIndex == index) {
ListItem() {
Column() {
Row() {
Row()
.backgroundColor(Color.Pink)
.borderRadius(20)
.width(80)
.height(80)
Column() {
Text ('Click to expand Item' + item)
.fontSize(20)
Text ('Shared element transition')
.fontSize(12)
.fontColor(0x909399)
}
.alignItems(HorizontalAlign.Start)
.justifyContent(FlexAlign.SpaceAround)
.margin({ left: 10 })
.height(80)
}
.width('90%')
.height(100)
if (this.isExpand && this.curIndex == index) {
Row() {
Text('Expanded state')
.fontSize(28)
.fontColor(0x909399)
.textAlign(TextAlign.Center)
.transition(TransitionEffect.OPACITY.animation({ curve: curves.springMotion(0.6, 0.9) }))
}
.width('90%')
.justifyContent(FlexAlign.Center)
}
}
.width('90%')
.height(this.isExpand && this.curIndex == index ? 750 : 100)
.alignItems(HorizontalAlign.Center)
.borderRadius(10)
.margin({ top: 15 })
.backgroundColor(Color.White)
.shadow({ radius: 20, color: 0x909399, offsetX: 20, offsetY: 10 })
}
.onClick(() => {
// Define the animation parameters for expanding and collapsing.
animateTo({ curve: curves.springMotion(0.6, 0.9) }, () => {
this.curIndex = index;
this.isExpand = !this.isExpand;
})
})
.zIndex(this.curIndex == index? 1: 0) // When the current list item is selected, its zIndex attribute is set to 1, and it is displayed over other sibling components whose zIndex is 0.
.translate({ // Move the list item to the top of the parent container through translate.
y: this.isExpand && this.curIndex == index ? -60 - this.parentScroller.currentOffset()['yOffset'] : 0
})
}
})
}
.clip(false)
.height('100%') // Fixed size of the placeholder container.
.alignListItem(ListItemAlign.Center)
}
.zIndex(1)
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Start)
}
}
```
```ts
// Index.ets
import { share_zIndex_expand } from './utils'
@Entry
@Component
struct ShareZIndexDemo {
@State isExpand: boolean = false;
@State curIndex: number = 0;
scroller: Scroller = new Scroller();
build() {
Scroll(this.scroller) {
Column() {
Text ('zIndex changes z-axis')
.fontWeight(FontWeight.Bold)
.fontSize(30)
.fontColor(Color.Black)
.zIndex(0)
.margin(10)
share_zIndex_expand({ isExpand: $isExpand, curIndex: $curIndex, parentScroller: this.scroller })
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Start)
}
}
}
```
![en-us_image_0000001600332176](figures/en-us_image_0000001600332176.gif)
## Implementation with geometryTransition
This example implements a shared element transition with [geometryTransition](../reference/arkui-ts/ts-transition-animation-geometrytransition.md), which is used for implicit shared element transitions during component switching.
Below is the complete sample code and effect for using **geometryTransition** and the **if/else** syntax to implement a shared element transition:
```ts
@Entry
@Component
struct IfElseGeometryTransition {
@State isShow: boolean = false;
build() {
Stack({ alignContent: Alignment.Center }) {
if (this.isShow) {
Image($r('app.media.test'))
.autoResize(false)
.clip(true)
.width(300)
.height(400)
.offset({ y: 100 })
.geometryTransition("picture")
.transition(TransitionEffect.OPACITY)
} else {
// geometryTransition is bound to a container. Therefore, a relative layout must be configured for the child components of the container.
// The multiple levels of containers here are used to demonstrate passing of relative layout constraints.
Column() {
Column() {
Image($r('app.media.icon'))
.width('100%').height('100%')
}.width('100%').height('100%')
}
.width(80)
.height(80)
// geometryTransition synchronizes rounded corner settings, but only for the bound component, which is the container in this example.
// In other words, rounded corner settings of the container are synchronized, and those of the child components are not.
.borderRadius(20)
.clip(true)
.geometryTransition("picture")
// transition ensures that the component is not destructed immediately when it exits. You can customize the transition effect.
.transition(TransitionEffect.OPACITY)
}
}
.onClick(() => {
animateTo({ duration: 1000 }, () => {
this.isShow = !this.isShow;
})
})
}
}
```
![en-us_image_0000001599644878](figures/en-us_image_0000001599644878.gif)
Below is the sample code and effect for using **geometryTransition** and a modal transition API to implement a shared element transition:
```ts
import curves from '@ohos.curves';
@Entry
@Component
struct GeometryTransitionDemo {
// Define the state variable used to control modal transition.
@State isPresent: boolean = false;
// Use @Builder to build the modal.
@Builder
MyBuilder() {
Column() {
Text(this.isPresent ? 'Page 2' : 'Page 1')
.fontWeight(FontWeight.Bold)
.fontSize(30)
.fontColor(Color.Black)
.margin(20)
Row() {
Text('Shared component 1')
.fontWeight(FontWeight.Bold)
.fontSize(20)
.fontColor(Color.White)
}
.justifyContent(FlexAlign.Center)
.borderRadius(10)
.backgroundColor(0xf56c6c)
.width('100%')
.aspectRatio(1)
.margin({ bottom: 20 })
// New shared element, <Row, whose ID is share1.
.geometryTransition('share1')
Column() {
Text ('Expanded page')
.textAlign(TextAlign.Center)
.fontSize(15)
.fontColor(this.isPresent ? Color.White : Color.Transparent)
.margin(20)
Text('Click anywhere to return')
.textAlign(TextAlign.Center)
.fontSize(15)
.fontColor(this.isPresent ? Color.White : Color.Transparent)
}
.width('100%')
.transition(TransitionEffect.OPACITY.animation({ curve: curves.springMotion(0.6, 1.2) }))
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Start)
.transition(TransitionEffect.opacity(0.99))
.backgroundColor(this.isPresent ? 0x909399 : Color.Transparent)
.clip(true)
.onClick(() => {
animateTo({ duration: 1000 }, () => {
this.isPresent = !this.isPresent;
})
})
}
build() {
Column() {
Text('Page 1')
.fontWeight(FontWeight.Bold)
.fontSize(30)
.fontColor(Color.Black)
.margin(20)
Row() {
Text('Shared component 1')
.fontWeight(FontWeight.Bold)
.fontSize(20)
.fontColor(Color.White)
}
.justifyContent(FlexAlign.Center)
.borderRadius(10)
.backgroundColor(0xf56c6c)
.width(150)
.height(150)
.margin(20)
// Modal transition component
.bindContentCover($$this.isPresent, this.MyBuilder, ModalTransition.NONE)
// The <Row> component is assigned the ID share1 and configured to have the shared element effect.
.geometryTransition('share1')
.onClick(() => {
animateTo({ curve: curves.springMotion(0.6, 1.2) }, () => {
// Change the state variable in the closure to display the modal.
this.isPresent = !this.isPresent;
})
})
Text('Component 2')
.fontWeight(FontWeight.Bold)
.fontSize(20)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.borderRadius(10)
.backgroundColor(0x67C23A)
.width(150)
.height(150)
.margin(20)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Start)
.backgroundColor(Color.White)
}
}
```
![en-us_image_0000001597320326](figures/en-us_image_0000001597320326.gif)
## Implementation with Attribute Animation
```ts
import curves from '@ohos.curves';
@Entry
@Component
struct AutoAchieveShareTransitionDemo {
private items: string[] = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'];
// Specify whether the component is expanded.
@State expand: boolean = false;
// Attributes related to the shared element.
@State rect_top: number = 0; // Position of the shared element.
@State rect_bottom: number = 0;
@State rect_left: number = 0;
@State rect_right: number = 0;
// Attributes related to the newly created element.
@State item: string = ''; // Record the expanded element.
@State cardHeight: number = 300; // Widget height.
@State cardOpacity: number = 1; // Widget opacity.
@State layoutHeight: number = 300; // Height of the expanded page.
@State layoutWidth: string = '90%'; // Width of the expanded page.
@State layoutOffset: number = 0; // Offset of the expanded page.
@State layoutOpacity: number = 0; // Opacity of the expanded page.
// In the callback invoked when the transition is complete.
@State count: number = 0;
build() {
Stack() {
Scroll() {
Column({ space: 20 }) {
ForEach(this.items, (item, index) => {
Row() {
Column() {
Text('Shared element ' + item)
.fontSize(30)
.fontColor(Color.Black)
.fontWeight(FontWeight.Bolder)
Text ('Expand widget')
.fontSize(20)
.fontColor(0x909399)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
.width('90%')
.height(this.cardHeight)
.padding(20)
.backgroundColor(Color.Pink)
.borderRadius(10)
.shadow({ radius: 10, color: 0x909399, offsetX: 10, offsetY: 10 })
.opacity(this.expand && this.item == item ? 0 : 1)
// Set a unique ID and obtain the attribute information of the component corresponding to the ID.
.id(item)
.onClick(() => {
// Obtain the position and size of the corresponding component.
let strJson = getInspectorByKey(item);
let obj = JSON.parse(strJson);
let rectInfo = JSON.parse('[' + obj.$rect + ']');
let rect_left = JSON.parse('[' + rectInfo[0] + ']')[0];
let rect_top = JSON.parse('[' + rectInfo[0] + ']')[1];
let rect_right = JSON.parse('[' + rectInfo[1] + ']')[0];
let rect_bottom = JSON.parse('[' + rectInfo[1] + ']')[1];
let rect_value = {
"left": rect_left, "top": rect_top, "right": rect_right, "bottom": rect_bottom
};
// Set the location, content, and status of the shared element.
this.rect_top = rect_top;
this.item = item;
this.expand = true;
this.count += 1;
animateTo({ curve: curves.springMotion() }, () => {
this.layoutHeight = 2772 / 3.5;
this.layoutWidth = '100%';
this.layoutOffset = -((rect_top - 136) / 3.5);
})
})
})
}
.width('100%')
.margin({ top: 20 })
}
.height('100%')
// Create an element that is the same as the component based on the obtained component information.
if (this.expand) {
Column() {
// Share element.
Row() {
Column() {
Text('Shared element ' + this.item)
.fontSize(30)
.fontColor(Color.Black)
.fontWeight(FontWeight.Bolder)
Text ('Expand widget')
.fontSize(20)
.fontColor(0x909399)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
.width('100%')
.height(this.cardHeight)
.padding(20)
.backgroundColor(Color.Pink)
// New element.
Text('Expanded page\n\nExpanded page\n\nExpanded page\n\nExpanded page\n\nExpanded page\n\nExpanded page\n\nExpanded page\n\nExpanded page')
.fontSize(20)
.fontColor(0xcccccc)
.margin({ top: 20 })
}
.borderRadius(this.layoutWidth == '100%' ? 0 : 10)
.shadow({ radius: 10, color: 0x909399, offsetX: 10, offsetY: 10 })
.width(this.layoutWidth)
.height(this.layoutHeight)
.clip(true)
.backgroundColor(Color.White)
// Work out the absolute position of the new element.
.position({
x: this.layoutWidth == '90%' ? '5%' : 0,
y: (this.rect_top - 136) / 3.5
})
.translate({
y: this.layoutOffset
})
.onClick(() => {
this.count -= 1;
animateTo({
curve: curves.springMotion(),
onFinish: (() => {
if (this.count == 0) {
this.expand = false;
}
})
}, () => {
this.layoutHeight = this.cardHeight;
this.layoutWidth = '90%';
this.layoutOffset = 0;
})
})
}
}
}
}
```
![en-us_image_0000001599374166](figures/en-us_image_0000001599374166.gif)
# Spring Curve
In a damped spring system corresponding to a damped spring curve (spring curve for short), an object that deviates from the equilibrium position is forced to oscillate due to a reverse force generated by spring deformation; this oscillation is resisted by the damping force. Except for the special case where the damping is 0, the oscillation gradually decays in amplitude towards 0, and the resultant animation curve is naturally continuous.
An animation using the spring curve slows down toward the end where the velocity of 0, instead of stopping abruptly.
ArkUI provides four types of damped spring curve APIs:
- [springMotion](../reference/apis/js-apis-curve.md#curvesspringmotion9): creates a spring animation curve. The animation duration is automatically calculated based on the curve parameters, attribute change values, and initial spring velocity. Manually set animation duration values do not take effect.
**springMotion** does not provide any API for setting the velocity, as the velocity is obtained through inheritance. For an attribute, if there is already a springMotion or responsiveSpringMotion animation running, a new spring animation will stop the running animation and inherit the attribute values and velocity of that animation as its initial values. This spring curve API provides default parameters, which you can directly use when appropriate.
```ts
function springMotion(response?: number, dampingFraction?: number, overlapDuration?: number): ICurve;
```
- [responsiveSpringMotion](../reference/apis/js-apis-curve.md#curvesresponsivespringmotion9): creates a responsive spring animation curve. It is a special case of **springMotion**, with the only difference in the default values. It is typically used to create an animation with a gesture on the screen. You can use **springMotion** to create an animation for when the user lifts their finger off the screen. The created animation automatically inherits the previous velocity for animation transition.
When the **overlapDuration** parameter of the new animation is not **0** and the previous spring animation of the current attribute is not yet complete, **response** and **dampingFracion** transit from the values of the previous animation to that of the new animation within the period specified by **overlapDuration**.
```ts
function responsiveSpringMotion(response?: number, dampingFraction?: number, overlapDuration?: number): ICurve;
```
- [interpolatingSpring](../reference/apis/js-apis-curve.md#curvesinterpolatingspring10): creates an interpolating spring curve animated from 0 to 1. It applies to scenarios where the initial animation velocity needs to be specified. The animation duration is automatically calculated, and the manually specified animation duration does not take effect.
The actual animation value is calculated based on the curve. Therefore, the velocity should be the normalized speed, which is equal to the absolute speed of the animation attribute change divided by the amount of the animation attribute change. In light of this, this API is not applicable to the scenario where the attribute value of the animation start point is the same as that of the animation end point, since under this scenario, the amount of the animation attribute change is 0, and the normalized speed does not exist.
```ts
function interpolatingSpring(velocity: number, mass: number, stiffness: number, damping: number): ICurve;
```
- [springCurve](../reference/apis/js-apis-curve.md#curvesspringcurve9): creates a spring curve with the specified animation duration. This API is almost the same as **interpolatingSpring**. However, for an animation that uses **springCurve**, the physical duration of the curve is mapped to the specified duration, which is equivalent to stretching or compressing the curve on the time axis and violating the original physical rule of the curve. Whenever possible, avoid using this API.
```ts
function springCurve(velocity: number, mass: number, stiffness: number, damping: number): ICurve;
```
The following shows a complete example and effect of spring curves. For details about how to connect gestures and animations, see [Animation Smoothing](arkts-animation-smoothing.md).
```ts
import curves from '@ohos.curves';
class Spring {
public title: string;
public subTitle: string;
public iCurve: ICurve;
constructor(title: string, subTitle: string, iCurve: ICurve) {
this.title = title;
this.iCurve = iCurve;
this.subTitle = subTitle;
}
}
// Spring component
@Component
struct Motion {
@Prop dRotate: number
private title: string
private subTitle: string
private iCurve: ICurve
build() {
Row() {
Column() {
Text(this.title)
.fontColor(Color.Black)
.fontSize(16)
Text(this.subTitle)
.fontColor(0xcccccc)
.fontSize(12)
}
.width(200)
.alignItems(HorizontalAlign.Start)
.justifyContent(FlexAlign.Center)
.height(100)
Stack({ alignContent: Alignment.Top }) {
// Circle
Column()
.width(100)
.height(100)
.border({
width: 10,
color: 0xf56c6c,
radius: 50
})
.backgroundColor(Color.White)
// Mask layer
Column() {
Row()
.width(100)
.height(100)
.border({
width: 10,
color: 0x909399,
radius: 50
})
.backgroundColor(0xf56c6c)
}
.width(100)
.height(50)
.clip(true)
.rotate({ angle: this.dRotate, centerX: 50, centerY: 50 })
.animation({ curve: this.iCurve, iterations: -1 })
}
.width(100)
.height(100)
}
.height(110)
.borderWidth({ bottom: 1 })
.borderColor(0xf5f5f5)
.margin({ bottom: 5 })
.alignItems(VerticalAlign.Top)
}
}
@Entry
@Component
export struct SpringDemo {
@State dRotate: number = 0;
private springs: Spring[] = [
new Spring('springMotion()', '(springMotion(1, 0.25): \n\nCycle: 2; damping: 0.25)', curves.springMotion(1, 0.25)),
new Spring('responsiveSpringMotion()', 'responsiveSpringMotion(1, 0.25): \n\nDefault responsive spring curve', curves.responsiveSpringMotion(1, 0.25)),
new Spring('interpolatingSpring()', '(interpolatingSpring(10, 1, 228, 30): \n\nInitial velocity: 100; quality: 1; stiffness: 228; damping: 30)', curves.interpolatingSpring(10, 1, 228, 30)),
new Spring('springCurve()', '(springCurve(10, 1, 228, 30): \n\nInitial velocity: 100; quality: 1; stiffness: 228; damping: 30)', curves.springCurve(10, 1, 228, 30))
];
build() {
Column() {
ForEach(this.springs, (item: Spring) => {
Motion({ title: item.title, subTitle: item.subTitle, iCurve: item.iCurve, dRotate: this.dRotate })
})
}
.justifyContent(FlexAlign.Center)
.width('100%')
.height(437)
.margin({ top: 20 })
.onClick(() => {
this.dRotate = 360;
})
}
}
```
![en-us_image_0000001649089041](figures/en-us_image_0000001649089041.gif)
# Traditional Curve
The animation curve, defined by a timing function, is a speed curve that controls the time consumed by an animation on attribute changes. The slope of the animation curve at a certain moment indicates the animation velocity and corresponds to the attribute change speed. A well-designed animation curve should be continuously smooth, in line with the user's intent, and consistent with the real world. When designing animation curves for your animations and transitions, take into account use cases and user intents. Animation curves can be classified into physics-based curves (ArkUI provides multiple physics-based spring curves) and traditional curves based on whether they model the real world. Compared with the traditional curve, the movement trajectory generated by the physics-based curve would feel more natural to users and help create a more engaging experience. In light of this, you are advised to use the physics-based curve when possible.
Traditional curves are mathematically described curves. A typical representative is the cubic Bezier curve. You define the curve shape with a set of control points, to bring out the expected animation effect, such as ease in and ease out. As aforementioned, a traditional curve is not based on the real-world behavior. This means that it does not change its shape to respond to user behavior, and lacks the natural and engaging feel given by a physics-based curve. When creating animations, prioritize physics-based curves and use traditional curves only in rare cases.
ArkUI provides APIs for traditional curves such as Bezier and step curves. For details, see [Interpolation Calculation](../reference/apis/js-apis-curve.md).
The following is an example of a traditional curve.
```ts
class MyCurve {
public title: string;
public curve: Curve;
public color: Color | string;
constructor(title: string, curve: Curve, color: Color | string = '') {
this.title = title;
this.curve = curve;
this.color = color;
}
}
const myCurves: MyCurve[] = [
new MyCurve(' Linear', Curve.Linear, 0x409EFF),
new MyCurve(' Ease', Curve.Ease, 0x67C23A),
new MyCurve(' EaseIn', Curve.EaseIn, 0xE6A23C),
new MyCurve(' EaseOut', Curve.EaseOut, 0xF56C6C),
new MyCurve(' EaseInOut', Curve.EaseInOut, 0xFFB6C1),
new MyCurve(' FastOutSlowIn', Curve.FastOutSlowIn, 0xDC143C),
new MyCurve(' LinearOutSlowIn', Curve.LinearOutSlowIn, 0xFF00FF),
new MyCurve(' FastOutLinearIn', Curve.FastOutLinearIn, 0x00BFFF),
new MyCurve(' ExtremeDeceleration', Curve.ExtremeDeceleration, 0x5F9EA0),
new MyCurve(' Sharp', Curve.Sharp, 0x00FFFF),
new MyCurve(' Rhythm', Curve.Rhythm, 0x66CDAA),
new MyCurve(' Smooth', Curve.Smooth, 0x7CFC00),
new MyCurve(' Friction', Curve.Friction, 0xFFA500)
]
@Entry
@Component
export struct CurveDemo {
@State dRotate: number = 0; // Rotation angle.
build() {
Column() {
// Curve example
Grid() {
ForEach(myCurves, (item: MyCurve) => {
GridItem() {
Column() {
Row()
.width(20)
.height(20)
.borderRadius(10)
.backgroundColor(item.color)
Text(item.title)
.fontSize(10)
.fontColor(0x909399)
}
.width('100%')
}
})
}
.columnsTemplate('1fr 1fr 1fr')
.rowsTemplate('1fr 1fr 1fr 1fr 1fr')
.padding(10)
.width('100%')
.height(300)
Stack() {
// Swing pipe
Row()
.width(290)
.height(290)
.border({
width: 10,
color: 0xE6E8EB,
radius: 145
})
ForEach(myCurves, (item: MyCurve) => {
// Balls
Column() {
Row()
.width(20)
.height(20)
.borderRadius(10)
.backgroundColor(item.color)
}
.width(20)
.height(300)
.rotate({ angle: this.dRotate })
.animation({ duration: 2000, iterations: -1, curve: item.curve, delay: 100 })
})
}
.width('100%')
.height(437)
.onClick(() => {
this.dRotate ? null : this.dRotate = 360;
})
}
.width('100%')
}
}
```
![en-us_image_0000001641260233](figures/en-us_image_0000001641260233.gif)
# Transition Animation Overview
Compared with [attribute animations](arkts-attribute-animation-overview.md), which work for components that are always present, transition animations are applied to animate the appearing or disappearing components. With transition animations, you are freed from the burdensome tasks of disappearing component management, which are unavoidable if you used attribute animations instead: deleting the component in the callback invoked when the animation is complete; checking the component status in the callback, in case that the component that has been deleted appears again before the animation ends.
Transition animations are classified into basic transition animations and advanced template-based transition animations. They come in any of the following types:
- [Enter/Exit transition](arkts-enter-exit-transition.md): used on appearing and disappearing components. It is a basic type of transition.
- [Navigation transition](arkts-navigation-transition.md): used during page navigation, where one page disappears and another page appears. For example, it can be used for switching from a level-1 menu page to a level-2 details page.
- [Modal transition](arkts-modal-transition.md): achieved by a modal – a view that appears on top of the current view while the current view remains. The dialog box is a typical type of modal.
- [Shared element transition](arkts-shared-element-transition.md): achieved by animating the size and position between styles of the same or similar elements during page switching.
......@@ -84,8 +84,8 @@ The table below lists the main tasks involved in UI development with ArkUI. You
| Develop the layout | Understand the common layouts and how to improve layout performance. | - [Layout Overview](arkts-layout-development-overview.md)<br>- [Improving Layout Performance](arkts-layout-development-performance-boost.md)|
| Add components | Learn the usage of common built-in components, custom components, and GUI elements supported by APIs.| - [Common Components](arkts-common-components-button.md)<br>- [Custom Components](../quick-start/arkts-create-custom-components.md)<br>- [Popup and Menu](arkts-popup-and-menu-components-popup.md)|
| Set page routing and component navigation| Learn how to set page routes and navigation between components. | - [Page Routing](arkts-routing.md)<br>- [Navigation](arkts-navigation-navigation.md)|
| Use graphics | Understand how to display images, draw custom geometry, and make custom graphics on the canvas. | - [Displaying Images](arkts-graphics-display.md)<br>- [Drawing Geometric Shapes](arkts-geometric-shape-drawing.md)<br>- [Drawing Custom Graphics Using the Canvas](arkts-drawing-customization-on-canvas.md) |
| Apply animations | Learn the typical scenarios of applying animations on components and pages. | - [Animation Within a Page](arkts-layout-update-animation.md)<br>- [Animation Between Pages](arkts-zoom-animation.md)|
| Use graphics | Understand how to display images, draw custom geometry, and make custom graphics on the canvas. | - [Displaying Images](arkts-graphics-display.md)<br>- [Drawing Geometric Shapes](arkts-geometric-shape-drawing.md)<br>- [Drawing Custom Graphics Using the Canvas](arkts-drawing-customization-on-canvas.md)|
| Apply animations | Learn the typical scenarios of applying animations on components and pages. | - [Attribute Animation](arkts-attribute-animation-overview.md)<br>- [Transition Animation](arkts-transition-overview.md)<br>- [Component Animation](arkts-component-animation.md)<br>- [Animated Curve](arkts-traditional-curve.md)<br>- [Animation Smoothing](arkts-animation-smoothing.md)<br>- [Animation Effects](arkts-blur-effect.md)|
| Bind events | Learn the basic concepts of events and how to use common events and gesture events. | - [Universal Events](arkts-common-events-touch-screen-event.md)<br>- [Gesture Events](arkts-gesture-events-binding.md)|
##
......
......@@ -34,7 +34,7 @@
- [Kernel for the Standard System](kernel/kernel-standard-overview.md)
- [Driver](driver/Readme-EN.md)
- [Compilation and Building](subsystems/subsys-build-all.md)
- [Distributed Remote Startup](subsystems/subsys-remote-start.md)
- [ArkUI](subsystems/subsys-arkui-customize_titlebar.md)
- [Graphics](subsystems/subsys-graphics-overview.md)
- [Multimedia](subsystems/subsys-multimedia-camera-overview.md)
- [Utils](subsystems/subsys-utils-guide.md)
......@@ -52,10 +52,8 @@
- [Mini- and Small-System Devices](guide/device-wlan-led-control.md)
- [Standard-System Devices](guide/device-clock-guide.md)
- Debugging
- [Test Case Development](device-test/developer_test.md)
- [Device Test](device-test/Readme-EN.md)
- [R&D Tools](subsystems/subsys-toolchain-hdc-guide.md)
- XTS Certification
- [XTS Test Case Development](device-test/xts.md)
- Tools
- [Docker Environment](get-code/gettools-acquire.md)
- [IDE](get-code/gettools-ide.md)
......
# Smartperf-Host
# Smartperf-Host User Guide
## Overview
Smartperf-Host is an intuitive performance and power optimization tool that offers in-depth data mining and fine-grained data visualization. In this tool, you can gain visibility into a multitude of metrics in terms of CPU scheduling, frequency, process and thread time slices, heap memory, frame rate, and more, in swimlanes. Better yet, you can analyze the collected data intuitively on the GUI.
## Architecture
......
......@@ -24,9 +24,10 @@
- [Using Cargo2gn](subsys-build-cargo2gn-guide.md)
- [FAQs](subsys-build-FAQ.md)
- [ArkCompiler Development](subsys-arkcompiler-guide.md)
- [Distributed Remote Startup](subsys-remote-start.md)
- Graphics
- [Graphics Overview](subsys-graphics-overview.md)
- ArkUI
- [Custom Window Title Bar Development](subsys-arkui-customize_titlebar.md)
- Small-System Graphics
- [Overview of Small-System Graphics](subsys-graphics-overview.md)
- [Common Component Development](subsys-graphics-common-guide.md)
- [Container Component Development](subsys-graphics-container-guide.md)
- [Development of Layout Container Components](subsys-graphics-layout-guide.md)
......
# Custom Window Title Bar Development
## Overview
While OpenHarmony provides default UX styles for window title bars, it allows device vendors to develop custom window title bars to meet specific needs.
## Development Guidelines
### How to Develop
Perform the following steps:
1. In **MaximizeMode** (in **frameworks/core/components/common/layout/constants.h**), define the enums, for example, **MODE_AVOID_SYSTEM_BAR** and **MODE_FULL_FILL**.
```cpp
enum class MaximizeMode : uint32_t {
MODE_AVOID_SYSTEM_BAR,
MODE_FULL_FILL,
MODE_RECOVER,
};
```
2. In **ContainerModalViewFactory::GetView** (in **foundation/arkui/ace_engine/frameworks/core/components_ng/pattern/container_modal/container_modal_view_factory.h**), add the creation of the custom window title bar based on the current value of **MaximizeMode**.
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
>
> The **ContainerModalViewFactory::GetView** method is a factory method. Below shows the method expanded:
```cpp
class ACE_EXPORT ContainerModalViewFactory {
public:
static RefPtr<FrameNode> GetView(RefPtr<FrameNode>& content, MaximizeMode mode) {
if (mode == MaximizeMode::MODE_AVOID_SYSTEM_BAR ||
mode == MaximizeMode::MODE_FULL_FILL) {
return ContainerModalViewEnhance::Create(content);
} else {
return ContainerModalView::Create(content);
}
}
};
```
In the preceding example, vendor enhance creates a custom title bar branch based on the value of **MaximizeMode** (**MaximizeMode::MODE_AVOID_SYSTEM_BAR** or **MaximizeMode::MODE_FULL_FILL**).
3. Create a folder in the **foundation/arkui/ace_engine/frameworks/core/components_ng/pattern/container_modal** directory to store your custom title bar code.
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
>
> The structure of the **container_modal** folder is as follows:
```shell
├── container_modal_accessibility_property.cpp
├── container_modal_accessibility_property.h
├── container_modal_pattern.cpp
├── container_modal_pattern.h
├── container_modal_view.cpp
├── container_modal_view_factory.h
├── container_modal_view.h
└── enhance
├── container_modal_pattern_enhance.cpp
├── container_modal_pattern_enhance.h
├── container_modal_view_enhance.cpp
└── container_modal_view_enhance.h
```
The **container_modal_\*** files in the **container_modal** folder contain the code related to the default title bar view. You can add your custom code files in the created folder, **enhance** in this example.
4. Complete build configuration for the new .cpp files in **foundation/arkui/ace_engine/frameworks/core/components_ng/pattern/BUILD.gn**.
When your development of the custom title bar is complete, debug and verify the title bar.
### Debugging and Verification
Before the verification, prepare the following files (which must be stored in the same path):
- **open_maximize.bat**
Below shows the content of this file:
```shell
hdc shell mount -o rw,remount /sys_prod
hdc file send window_manager_config_open.xml sys_prod/etc/window/resources/window_manager_config.xml
hdc shell reboot
```
- **window_manager_config_open.xml**
Below shows the content of this file:
```html
<?xml version="1.0" encoding="utf-8"?>
<Configs>
<decor enable="true"/>
<modeChangeHotZones>50 50 50</modeChangeHotZones>
<maxFloatingWidth>1706</maxFloatingWidth>
<maxFloatingHeight>1000</maxFloatingHeight>
<minFloatingWidth>398</minFloatingWidth>
<minFloatingHeight>528</minFloatingHeight>
<floatingBottomPosY>0</floatingBottomPosY>
<defaultFloatingWindow>82 121 1068 706</defaultFloatingWindow>
<defaultWindowMode>102</defaultWindowMode>
<defaultMaximizeMode>0</defaultMaximizeMode>
<dragFrameGravity>5</dragFrameGravity>
<maxUniRenderAppWindowNumber>10</maxUniRenderAppWindowNumber>
<maxFloatingWindowSize>2880</maxFloatingWindowSize>
<splitRatios>0.5 0.33 0.67</splitRatios>
<keyboardAnimation>
<timing>
<durationIn>500</durationIn>
<durationOut>150</durationOut>
<curve name="cubic">0.2 0.0 0.2 1.0</curve>
</timing>
</keyboardAnimation>
<windowAnimation>
<timing>
<duration>200</duration>
<curve name="cubic">0.0 0.0 0.2 1.0</curve>
</timing>
<scale>0.9 0.9</scale>
<rotation>0 0 1 0</rotation>
<translate>0 0</translate>
<opacity>0</opacity>
</windowAnimation>
<windowEffect>
<appWindows>
<cornerRadius>
<fullScreen>off</fullScreen>
<split>off</split>
<float>defaultCornerRadiusL</float>
</cornerRadius>
<shadow>
<focused>
<elevation>0</elevation>
<color>#000000</color>
<offsetX>0</offsetX>
<offsetY>15</offsetY>
<alpha>0.4</alpha>
<radius>34</radius>
</focused>
<unfocused>
<elevation>0</elevation>
<color>#000000</color>
<offsetX>0</offsetX>
<offsetY>15</offsetY>
<alpha>0.2</alpha>
<radius>17</radius>
</unfocused>
</shadow>
</appWindows>
</windowEffect>
</Configs>
```
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
>
> The **window_manager_config_open.xml** file contains various configuration items. Before the verification, you must change the default value of **MaximizeMode** to the one you have defined, that is, the value obtained by **MaximizeMode maximizeMode = GetWindowManager()->GetWindowMaximizeMode()**. The system loads the corresponding title bar according to the value.
Then, debug the custom title bar as follows:
1. Burn the image that contains the custom title bar code to the device.
2. Run the **open_maximize.bat** script.
3. Run the demo to check whether the title bar works properly.
# Distributed Remote Startup<a name="EN-US_TOPIC_0000001051071561"></a>
## Overview<a name="section186634310418"></a>
The Distributed Manager Service sets up a distributed service platform in OpenHarmony by using a proxy between the primary and secondary devices. With the Distributed Manager Service, the primary device \(OpenHarmony-powered smart TV\) can start a Feature Ability \(FA\) deployed on the secondary device \(a memory-constrained OpenHarmony device such as an IP camera or a lite wearable\).
For example, if a user presses the **Remind Me** button for a TV program on the smart TV, the smart TV will start the corresponding reminder FA on the lite wearable to remind the user when the particular TV program is available.
## Basic Concepts<a name="section982651246"></a>
- FA
Feature Ability, representing an ability with a UI for interacting with users
- Remote startup
Cross-device FA startup, which is the counterpart of local FA startup
## Available APIs<a name="section125479541744"></a>
The following table describes the API that can be used by smart TVs to remotely start an FA. This API is provided in the **AbilitySlice** class. For details, see the Java API reference for OpenHarmony application development.
**Table 1** API for remotely starting an FA on the distributed network
<a name="table1731550155318"></a>
<table><thead align="left"><tr id="row4419501537"><th class="cellrowborder" valign="top" width="57.38999999999999%" id="mcps1.2.3.1.1"><p id="p54150165315"><a name="p54150165315"></a><a name="p54150165315"></a>Method</p>
</th>
<th class="cellrowborder" valign="top" width="42.61%" id="mcps1.2.3.1.2"><p id="p941150145313"><a name="p941150145313"></a><a name="p941150145313"></a>Description</p>
</th>
</tr>
</thead>
<tbody><tr id="row34145016535"><td class="cellrowborder" valign="top" width="57.38999999999999%" headers="mcps1.2.3.1.1 "><p id="p1682733119213"><a name="p1682733119213"></a><a name="p1682733119213"></a>void startAbility(Want want)</p>
</td>
<td class="cellrowborder" valign="top" width="42.61%" headers="mcps1.2.3.1.2 "><p id="p13562171015712"><a name="p13562171015712"></a><a name="p13562171015712"></a>Remotely starts an FA based on the specified <strong id="b8984536181113"><a name="b8984536181113"></a><a name="b8984536181113"></a>Want</strong> information. If the name and type of the <strong id="b599520304618"><a name="b599520304618"></a><a name="b599520304618"></a>want</strong> parameter are different from those used in the integrated development environment (IDE), use the parameter name and type in the IDE.</p>
</td>
</tr>
</tbody>
</table>
**Table 2** Description of the want parameter
<a name="table02120432364"></a>
<table><thead align="left"><tr id="row172294315361"><th class="cellrowborder" valign="top" width="14.000000000000002%" id="mcps1.2.4.1.1"><p id="p722144318360"><a name="p722144318360"></a><a name="p722144318360"></a>Parameter</p>
</th>
<th class="cellrowborder" valign="top" width="17%" id="mcps1.2.4.1.2"><p id="p10227434363"><a name="p10227434363"></a><a name="p10227434363"></a>Type</p>
</th>
<th class="cellrowborder" valign="top" width="69%" id="mcps1.2.4.1.3"><p id="p22284383616"><a name="p22284383616"></a><a name="p22284383616"></a>Description</p>
</th>
</tr>
</thead>
<tbody><tr id="row3228436365"><td class="cellrowborder" valign="top" width="14.000000000000002%" headers="mcps1.2.4.1.1 "><p id="p1391227193713"><a name="p1391227193713"></a><a name="p1391227193713"></a>want</p>
</td>
<td class="cellrowborder" valign="top" width="17%" headers="mcps1.2.4.1.2 "><p id="p20993611193719"><a name="p20993611193719"></a><a name="p20993611193719"></a>ohos.aafwk.content.Want</p>
</td>
<td class="cellrowborder" valign="top" width="69%" headers="mcps1.2.4.1.3 "><p id="p10555172211377"><a name="p10555172211377"></a><a name="p10555172211377"></a>When you use <strong id="b1013275220199"><a name="b1013275220199"></a><a name="b1013275220199"></a>startAbility(Want want)</strong> to remotely start an FA, you must first specify the <strong id="b1125035416223"><a name="b1125035416223"></a><a name="b1125035416223"></a>deviceId</strong>, <strong id="b16473135811222"><a name="b16473135811222"></a><a name="b16473135811222"></a>bundleName</strong>, and <strong id="b157931324230"><a name="b157931324230"></a><a name="b157931324230"></a>abilityName</strong> attributes of the target FA in the <strong id="b34832152239"><a name="b34832152239"></a><a name="b34832152239"></a>Want</strong> object.</p>
</td>
</tr>
</tbody>
</table>
## Limitations and Constraints<a name="section1165911177314"></a>
- The primary device can remotely start an FA of the secondary device, but the secondary device cannot remotely start an FA of the primary device.
- Before the remote startup, ensure that the two OpenHarmony devices are on the same network segment and can ping each other on the distributed network. Otherwise, the remote startup fails.
- Currently, only the FAs that have the same public key \(that is, the same Huawei certificate\) can be started between the primary and secondary devices.
## How to Develop<a name="section34171333656"></a>
To enable the primary device \(smart TV\) to start an FA of the secondary device \(assuming that the target FA has been developed\), perform the following steps:
1. Complete FA development for the smart TV on DevEco Studio.
2. Obtain the IDs of online secondary devices.
```
// Import the header files required for device selection.
import ohos.distributedschedule.interwork.DeviceInfo;
import ohos.distributedschedule.interwork.DeviceManager;
// Obtain the online device list.
List<DeviceInfo> deviceInfoListOnline = DeviceManager.getDmsDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);
String remote_device_id;
if (deviceInfoListOnline.size() > 0)
{
remote_device_id = deviceInfoListOnline[0].GetDeviceId(); // Obtain the ID of the first device in the online device list.
}
```
3. Create a **Want** instance. You should first create an **ElementName** object with **deviceId**, **bundleName**, **abilityName** specified and add this object to the **Want** instance. Then, set the multi-device startup flag **Want.FLAG\_ABILITYSLICE\_MULTI\_DEVICE** to the **Want** instance to enable remote FA startup.
```
// Import related header files.
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Want;
import ohos.bundle.ElementName;
// Start the remote FA on the secondary device.
Want want = new Want(); // Create a Want instance that encapsulates information about the remote FA to start.
// Use the device ID obtained in step 2 and specify the FA information.
ElementName name = new ElementName(remote_device_id, "com.huawei.remote_package_name", "remote_class_name");
want.setElement(name); // Add information about the target FA for startup to the Want instance.
want.setFlags(Want.FLAG_ABILITYSLICE_MULTI_DEVICE); // Set the multi-device startup flag. If this flag is not set, remote FA startup will be unavailable.
startAbility(want); // Start the specified FA based on the want parameter. If the name and type of the want parameter are different from those used in the IDE, use the parameter name and type in the IDE.
```
......@@ -388,15 +388,22 @@
- [Configuring Parameters for Accelerating Local Build](subsystems/subsys-build-reference.md)
- [Viewing Ninja Build Information](subsystems/subsys-build-reference.md)
- [HAP Build Guide](subsystems/subsys-build-gn-hap-compilation-guide.md)
- Rust Compilation and Building
- [Rust Module Configuration Rules and Guide](subsystems/subsys-build-rust-compilation.md)
- [Interactive Tool User Guide](subsystems/subsys-build-bindgen-cxx-guide.md)
- [Using Cargo2gn](subsystems/subsys-build-cargo2gn-guide.md)
- [FAQs](subsystems/subsys-build-FAQ.md)
- [ArkCompiler Development](subsystems/subsys-arkcompiler-guide.md)
- [Distributed Remote Startup](subsystems/subsys-remote-start.md)
- ArkUI
- [Custom Window Title Bar Development](subsystems/subsys-arkui-customize_titlebar.md)
- Graphics
- [Graphics Overview](subsystems/subsys-graphics-overview.md)
- [Common Component Development](subsystems/subsys-graphics-common-guide.md)
- [Container Component Development](subsystems/subsys-graphics-container-guide.md)
- [Development of Layout Container Components](subsystems/subsys-graphics-layout-guide.md)
- [Common Component Development](subsystems/subsys-graphics-common-guide.md)
- [Animator Development](subsystems/subsys-graphics-animation-guide.md)
- [Using Qt Creator on Windows](subsystems/subsys-graphics-simulator-guide.md)
- [Small-System Graphics Framework Integration](subsystems/subsys-graphics-porting-guide.md)
- Multimedia
- Camera
- [Camera Overview](subsystems/subsys-multimedia-camera-overview.md)
......@@ -532,6 +539,7 @@
- Debugging
- [Development Self-Test Framework User Guide](device-test/developer_test.md)
- [xDevice User Guide](device-test/xdevice.md)
- [Smartperf-Host User Guide](device-test/smartperf-host.md)
- R&D Tools
- [bytrace](subsystems/subsys-toolchain-bytrace-guide.md)
- [hdc](subsystems/subsys-toolchain-hdc-guide.md)
......
# ArkUI Subsystem Changelog
## cl.arkui.1 Change of Certain Predicates of uiAppearance from Public APIs to System APIs
Changed the namespace **uiAppearance** and its internal **DarkMode** enum predicates from public APIs to system APIs.
**Change Impact**
None. The namespace **uiAppearance** and its internal **DarkMode** enum are used only by system APIs before and after the change.
**Key API/Component Changes**
The system API description is added to the following APIs:
- declare namespace uiAppearance
- enum DarkMode
- ALWAYS_DARK = 0
- ALWAYS_LIGHT = 1
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册