提交 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)
......@@ -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)
此差异已折叠。
此差异已折叠。
# 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)
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册