提交 770a2fc6 编写于 作者: S sienna1128 提交者: Gitee

Merge branch 'master' of gitee.com:openharmony/docs into gesture

Signed-off-by: Nsienna1128 <lixiaoyan45@huawei.com>
...@@ -317,6 +317,7 @@ zh-cn/application-dev/reference/apis/js-apis-system-parameter.md @qinxiaowang ...@@ -317,6 +317,7 @@ zh-cn/application-dev/reference/apis/js-apis-system-parameter.md @qinxiaowang
zh-cn/application-dev/reference/apis/js-apis-thermal.md @qinxiaowang zh-cn/application-dev/reference/apis/js-apis-thermal.md @qinxiaowang
zh-cn/application-dev/reference/apis/js-apis-update.md @HelloCrease zh-cn/application-dev/reference/apis/js-apis-update.md @HelloCrease
zh-cn/application-dev/reference/apis/js-apis-usb.md @ge-yafang zh-cn/application-dev/reference/apis/js-apis-usb.md @ge-yafang
zh-cn/application-dev/reference/apis/js-apis-colorSpaceManager.mdd @ge-yafang
zh-cn/application-dev/reference/apis/js-apis-vibrator.md @HelloCrease zh-cn/application-dev/reference/apis/js-apis-vibrator.md @HelloCrease
zh-cn/application-dev/reference/apis/js-apis-appAccount.md @zengyawen zh-cn/application-dev/reference/apis/js-apis-appAccount.md @zengyawen
zh-cn/application-dev/reference/apis/js-apis-distributed-account.md @zengyawen zh-cn/application-dev/reference/apis/js-apis-distributed-account.md @zengyawen
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
The **distributedDataObject** module provides APIs to implement data collaboration of the same application across multiple devices. In addition, the devices that form a Super Device can listen for object status and data changes with each other. The **distributedDataObject** module provides APIs to implement data collaboration of the same application across multiple devices. In addition, the devices that form a Super Device can listen for object status and data changes with each other.
For example, when the data of the a distributed data object is added, deleted, or modified for application A on device 1, application A on device 2 can obtain the updated data. In addition, device 2 can listen for data changes and online/offline of the data objects on device 1. For example, when the data of a distributed data object is added, deleted, or modified for application A on device 1, application A on device 2 can obtain the updated data. In addition, device 2 can listen for data changes and online/offline of the data objects on device 1.
## Available APIs ## Available APIs
...@@ -18,7 +18,7 @@ Call **createDistributedObject()** to create a distributed data object instance. ...@@ -18,7 +18,7 @@ Call **createDistributedObject()** to create a distributed data object instance.
**Table 1** API for creating a distributed data object instance **Table 1** API for creating a distributed data object instance
| Package| API| Description| | Package| API| Description|
| -------- | -------- | -------- | | -------- | -------- | -------- |
| ohos.data.distributedDataObject| createDistributedObject(source: object): DistributedObject | Creates a distributed data object instance for data operations.<br>- **source**: attributes of the **distributedObject** set.<br>- **DistributedObject**: returns the distributed object created.| | ohos.data.distributedDataObject| createDistributedObject(source: object): DistributedObject | Creates a distributed data object instance for data operations.<br>- **source**: attributes of the distributed data object to set.<br>- **DistributedObject**: returns the distributed data object created. |
### Generating a Session ID ### Generating a Session ID
...@@ -29,14 +29,14 @@ Call **genSessionId()** to generate a session ID randomly. The generated session ...@@ -29,14 +29,14 @@ Call **genSessionId()** to generate a session ID randomly. The generated session
| -------- | -------- | -------- | | -------- | -------- | -------- |
| ohos.data.distributedDataObject| genSessionId(): string | Generates a session ID, which can be used as the session ID of a distributed data object.| | ohos.data.distributedDataObject| genSessionId(): string | Generates a session ID, which can be used as the session ID of a distributed data object.|
### Setting a SessionID for a Distributed Data Object ### Setting a Session ID for a Distributed Data Object
Call **setSessionId()** to set a session ID for a distributed data object. The session ID is a unique identifier for one collaboration across devices. The distributed data objects to be synchronized must be associated with the same session ID. Call **setSessionId()** to set a session ID for a distributed data object. The session ID is a unique identifier for one collaboration across devices. The distributed data objects to be synchronized must be associated with the same session ID.
**Table 3** API for setting a session ID **Table 3** API for setting a session ID
| Class| API| Description| | Class| API| Description|
| -------- | -------- | -------- | | -------- | -------- | -------- |
| DistributedDataObject | setSessionId(sessionId?: string): boolean | Sets a session ID for a distributed data object.<br>**sessionId**: session ID of a distributed object in a trusted network. To remove a distributed data object from the network, set this parameter to "" or leave it empty.| | DistributedDataObject | setSessionId(sessionId?: string): boolean | Sets a session ID for a distributed data object.<br>**sessionId**: session ID of a distributed data object in a trusted network. To remove a distributed data object from the network, set this parameter to "" or leave it empty. |
### Observing Data Changes ### Observing Data Changes
...@@ -47,7 +47,7 @@ Call **on()** to subscribe to data changes of a distributed data object. When th ...@@ -47,7 +47,7 @@ Call **on()** to subscribe to data changes of a distributed data object. When th
| Class| API| Description| | Class| API| Description|
| -------- | -------- | -------- | | -------- | -------- | -------- |
| DistributedDataObject| on(type: 'change', callback: Callback<{ sessionId: string, fields: Array&lt;string&gt; }>): void | Subscribes to data changes.| | DistributedDataObject| on(type: 'change', callback: Callback<{ sessionId: string, fields: Array&lt;string&gt; }>): void | Subscribes to data changes.|
| DistributedDataObject| off(type: 'change', callback?: Callback<{ sessionId: string, fields: Array&lt;string&gt; }>): void | Unsubscribes from data changes. **Callback**: specifies the data changes to unsubscribe from. If this parameter is not specified, all data changes of this distributed data object will be unsubscribed from.| | DistributedDataObject| off(type: 'change', callback?: Callback<{ sessionId: string, fields: Array&lt;string&gt; }>): void | Unsubscribes from data changes. <br/>**Callback**: callback to unregister. If this parameter is not specified, all data changes of this distributed data object will be unsubscribed from. |
### Observing Online or Offline Status ### Observing Online or Offline Status
...@@ -59,7 +59,7 @@ Call **on()** to subscribe to status changes of a distributed data object. The s ...@@ -59,7 +59,7 @@ Call **on()** to subscribe to status changes of a distributed data object. The s
| DistributedDataObject| on(type: 'status', callback: Callback<{ sessionId: string, networkId: string, status: 'online' \| 'offline' }>): void | Subscribes to the status changes of a distributed data object.| | DistributedDataObject| on(type: 'status', callback: Callback<{ sessionId: string, networkId: string, status: 'online' \| 'offline' }>): void | Subscribes to the status changes of a distributed data object.|
| DistributedDataObject| off(type: 'status', callback?: Callback<{ sessionId: string, deviceId: string, status: 'online' \| 'offline' }>): void | Unsubscribes from status changes of a distributed data object.| | DistributedDataObject| off(type: 'status', callback?: Callback<{ sessionId: string, deviceId: string, status: 'online' \| 'offline' }>): void | Unsubscribes from status changes of a distributed data object.|
### Saving a Distributed Data Object and Revoking the Data Saving Operation ### Saving or Deleting a Distributed Data Object
Call **save()** to save a distributed data object. When the application is active, the saved data will not be released. When the application exits and restarts, the data saved on the device will be restored. Call **save()** to save a distributed data object. When the application is active, the saved data will not be released. When the application exits and restarts, the data saved on the device will be restored.
...@@ -71,11 +71,12 @@ The saved data will be released in the following cases: ...@@ -71,11 +71,12 @@ The saved data will be released in the following cases:
- The application has been uninstalled. - The application has been uninstalled.
- Data is successfully restored. - Data is successfully restored.
**Table 6** APIs for saving a distributed data object and revoking the saving operation **Table 6** APIs for saving and deleting a distributed data object
| Class| API| Description| | Class| API| Description|
| -------- | -------- | -------- | | -------- | -------- | -------- |
| DistributedDataObject | save(deviceId: string): Promise&lt;SaveSuccessResponse&gt; | Saves a distributed data object.| | DistributedDataObject | save(deviceId: string): Promise&lt;SaveSuccessResponse&gt; | Saves a distributed data object.|
| DistributedDataObject| revokeSave(): Promise&lt;RevokeSaveSuccessResponse&gt; | Revokes the data saving operation.| | DistributedDataObject| revokeSave(): Promise&lt;RevokeSaveSuccessResponse&gt; | Deletes a distributed data object. |
## How to Develop ## How to Develop
...@@ -89,12 +90,10 @@ The following example shows how to implement distributed data object synchroniza ...@@ -89,12 +90,10 @@ The following example shows how to implement distributed data object synchroniza
2. Apply for the permission. 2. Apply for the permission.
Add the required permission (FA model) in the **config.json** file. Add the permissions required (FA model) to the **config.json** file. The sample code is as follows:
The sample code is as follows: ```json
{
```json
{
"module": { "module": {
"reqPermissions": [ "reqPermissions": [
{ {
...@@ -103,30 +102,27 @@ The following example shows how to implement distributed data object synchroniza ...@@ -103,30 +102,27 @@ The following example shows how to implement distributed data object synchroniza
] ]
} }
} }
``` ```
For the apps based on the stage model, see [Declaring Permissions](../security/accesstoken-guidelines.md#stage-model). For the apps based on the stage model, see [Declaring Permissions](../security/accesstoken-guidelines.md#stage-model).
This permission must also be granted by the user when the application is started for the first time. The sample code is as follows: This permission must also be granted by the user when the application is started for the first time. The sample code is as follows:
```json ```js
import featureAbility from '@ohos.ability.featureAbility'; import featureAbility from '@ohos.ability.featureAbility';
function grantPermission() { function grantPermission() {
console.info('grantPermission'); console.info('grantPermission');
let context = featureAbility.getContext(); let context = featureAbility.getContext();
context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], 666, function (result) { context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], 666, function (result) {
console.info(`result.requestCode=${result.requestCode}`) console.info(`result.requestCode=${result.requestCode}`)
}) })
console.info('end grantPermission'); console.info('end grantPermission');
} }
grantPermission(); grantPermission();
``` ```
3. Obtain a distributed data object instance. 3. Obtain a distributed data object instance.
The sample code is as follows: The sample code is as follows:
...@@ -142,12 +138,10 @@ The following example shows how to implement distributed data object synchroniza ...@@ -142,12 +138,10 @@ The following example shows how to implement distributed data object synchroniza
var sessionId = distributedObject.genSessionId(); var sessionId = distributedObject.genSessionId();
``` ```
4. Add the distributed data object instance to the synchronization network. 4. Add the distributed data object instance to a network for data synchronization. The data objects in the synchronization network include the local and remote objects.
The data objects in the synchronization network include the local and remote objects.
The sample code is as follows: The sample code is as follows:
```js ```js
// Local object // Local object
var local_object = distributedObject.createDistributedObject({ var local_object = distributedObject.createDistributedObject({
...@@ -167,16 +161,16 @@ The following example shows how to implement distributed data object synchroniza ...@@ -167,16 +161,16 @@ The following example shows how to implement distributed data object synchroniza
parent: undefined, parent: undefined,
list: undefined list: undefined
}); });
// After learning that the device goes online, the remote object synchronizes data. That is, name changes to jack and age to 18. // After learning that the local device goes online, the remote object synchronizes data. That is, name changes to jack and age to 18.
remote_object.setSessionId(sessionId); remote_object.setSessionId(sessionId);
``` ```
5. Observe the data changes of the distributed data object. 5. Observe the data changes of the distributed data object.
You can subscribe to data changes of the remote object. When the data in the remote object changes, a callback will be called to return the data changes. You can subscribe to data changes of the remote object. When the data in the remote object changes, a callback will be called to return the data changes.
The sample code is as follows: The sample code is as follows:
```js ```js
function changeCallback(sessionId, changeData) { function changeCallback(sessionId, changeData) {
console.info("change" + sessionId); console.info("change" + sessionId);
...@@ -185,13 +179,13 @@ The following example shows how to implement distributed data object synchroniza ...@@ -185,13 +179,13 @@ The following example shows how to implement distributed data object synchroniza
changeData.forEach(element => { changeData.forEach(element => {
console.info("changed !" + element + " " + local_object[element]); console.info("changed !" + element + " " + local_object[element]);
}); });
} }
} }
// To refresh the page in changeCallback, correctly bind (this) to the changeCallback. // To refresh the page in changeCallback, correctly bind (this) to the changeCallback.
local_object.on("change", this.changeCallback.bind(this)); local_object.on("change", this.changeCallback.bind(this));
``` ```
6. Modify attributes of the distributed data object. 6. Modify attributes of the distributed data object.
The object attributes support basic data types (such as number, Boolean, and string) and complex data types (array and nested basic types). The object attributes support basic data types (such as number, Boolean, and string) and complex data types (array and nested basic types).
...@@ -250,7 +244,7 @@ The following example shows how to implement distributed data object synchroniza ...@@ -250,7 +244,7 @@ The following example shows how to implement distributed data object synchroniza
local_object.on("status", this.statusCallback); local_object.on("status", this.statusCallback);
``` ```
10. Save a distributed data object and revoke the data saving operation. 10. Save a distributed data object and delete it.
```js ```js
// Save a distributed data object. // Save a distributed data object.
...@@ -261,7 +255,7 @@ The following example shows how to implement distributed data object synchroniza ...@@ -261,7 +255,7 @@ The following example shows how to implement distributed data object synchroniza
}, (result) => { }, (result) => {
console.info("save local failed."); console.info("save local failed.");
}); });
// Revoke the data saving operation. // Delete a distributed data object..
g_object.revokeSave().then((result) => { g_object.revokeSave().then((result) => {
console.info("revokeSave success."); console.info("revokeSave success.");
}, (result) => { }, (result) => {
...@@ -271,7 +265,7 @@ The following example shows how to implement distributed data object synchroniza ...@@ -271,7 +265,7 @@ The following example shows how to implement distributed data object synchroniza
11. Unsubscribe from the status changes of the distributed data object. 11. Unsubscribe from the status changes of the distributed data object.
You can specify the callback to unregister. If you do not specify the callback, this API unregisters all status change callbacks of this distributed data object. You can specify the callback to unregister. If you do not specify the callback, all status change callbacks of this distributed data object will be unregistered.
The sample code is as follows: The sample code is as follows:
...@@ -282,9 +276,7 @@ The following example shows how to implement distributed data object synchroniza ...@@ -282,9 +276,7 @@ The following example shows how to implement distributed data object synchroniza
local_object.off("status"); local_object.off("status");
``` ```
12. Remove a distributed data object from the synchronization network. 12. Remove a distributed data object from the synchronization network. Data changes on the local object will not be synchronized to the removed distributed data object.
Data changes on the local object will not be synchronized to the removed distributed data object.
The sample code is as follows: The sample code is as follows:
......
...@@ -16,13 +16,15 @@ import wifi from '@ohos.wifi'; ...@@ -16,13 +16,15 @@ import wifi from '@ohos.wifi';
enableWifi(): boolean enableWifi(): boolean
Enables WLAN. Enables WLAN.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications) **Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications)
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -33,13 +35,15 @@ This is a system API. ...@@ -33,13 +35,15 @@ This is a system API.
disableWifi(): boolean disableWifi(): boolean
Disables WLAN. Disables WLAN.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications) **Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications)
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -56,6 +60,7 @@ Checks whether WLAN is enabled. ...@@ -56,6 +60,7 @@ Checks whether WLAN is enabled.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if WLAN is enabled; returns **false** otherwise.| | boolean | Returns **true** if WLAN is enabled; returns **false** otherwise.|
...@@ -72,6 +77,7 @@ Starts a scan for WLAN. ...@@ -72,6 +77,7 @@ Starts a scan for WLAN.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -88,6 +94,7 @@ Obtains the scan result. This API uses a promise to return the result. ...@@ -88,6 +94,7 @@ Obtains the scan result. This API uses a promise to return the result.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| Promise&lt;&nbsp;Array&lt;[WifiScanInfo](#wifiscaninfo)&gt;&nbsp;&gt; | Promise used to return the detected hotspots.| | Promise&lt;&nbsp;Array&lt;[WifiScanInfo](#wifiscaninfo)&gt;&nbsp;&gt; | Promise used to return the detected hotspots.|
...@@ -104,6 +111,7 @@ Obtains the scan result. This API uses an asynchronous callback to return the re ...@@ -104,6 +111,7 @@ Obtains the scan result. This API uses an asynchronous callback to return the re
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| callback | AsyncCallback&lt;&nbsp;Array&lt;[WifiScanInfo](#wifiscaninfo)&gt;&gt; | Yes| Callback invoked to return the result. If the operation is successful, **err** is **0** and **data** is the detected hotspots. Otherwise, **err** is a non-zero value and **data** is empty.| | callback | AsyncCallback&lt;&nbsp;Array&lt;[WifiScanInfo](#wifiscaninfo)&gt;&gt; | Yes| Callback invoked to return the result. If the operation is successful, **err** is **0** and **data** is the detected hotspots. Otherwise, **err** is a non-zero value and **data** is empty.|
...@@ -157,6 +165,7 @@ Represents WLAN hotspot information. ...@@ -157,6 +165,7 @@ Represents WLAN hotspot information.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
| **Name**| **Type**| **Readable/Writable**| **Description**| | **Name**| **Type**| **Readable/Writable**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| ssid | string | Read only| Service set identifier (SSID) of the hotspot, in UTF-8 format.| | ssid | string | Read only| Service set identifier (SSID) of the hotspot, in UTF-8 format.|
...@@ -167,8 +176,8 @@ Represents WLAN hotspot information. ...@@ -167,8 +176,8 @@ Represents WLAN hotspot information.
| band | number | Read only| Frequency band of the WLAN access point (AP).| | band | number | Read only| Frequency band of the WLAN access point (AP).|
| frequency | number | Read only| Frequency of the WLAN AP.| | frequency | number | Read only| Frequency of the WLAN AP.|
| channelWidth | number | Read only| Channel width of the WLAN AP.| | channelWidth | number | Read only| Channel width of the WLAN AP.|
| centerFrequency0<sup>9+</sup> | number | Read only| Center frequency.| | centerFrequency0<sup>9+</sup> | number | Read only| Center frequency of the hotspot.|
| centerFrequency1<sup>9+</sup> | number | Read only| Center frequency.| | centerFrequency1<sup>9+</sup> | number | Read only| Center frequency of the hotspot. If the hotspot uses two non-overlapping WLAN channels, two center frequencies, namely **centerFrequency0** and **centerFrequency1**, are returned.|
| infoElems<sup>9+</sup> | Array&lt;[WifiInfoElem](#wifiinfoelem9)&gt; | Read only| Information elements.| | infoElems<sup>9+</sup> | Array&lt;[WifiInfoElem](#wifiinfoelem9)&gt; | Read only| Information elements.|
| timestamp | number | Read only| Timestamp.| | timestamp | number | Read only| Timestamp.|
...@@ -179,6 +188,7 @@ Enumerates the WLAN security types. ...@@ -179,6 +188,7 @@ Enumerates the WLAN security types.
**System capability**: SystemCapability.Communication.WiFi.Core **System capability**: SystemCapability.Communication.WiFi.Core
| **Name**| **Default Value**| **Description**| | **Name**| **Default Value**| **Description**|
| -------- | -------- | -------- | | -------- | -------- | -------- |
| WIFI_SEC_TYPE_INVALID | 0 | Invalid security type.| | WIFI_SEC_TYPE_INVALID | 0 | Invalid security type.|
...@@ -197,8 +207,11 @@ Enumerates the WLAN security types. ...@@ -197,8 +207,11 @@ Enumerates the WLAN security types.
Represents a WLAN information element. Represents a WLAN information element.
**System API**: This is a system API.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
| **Name**| **Type**| **Readable/Writable**| **Description**| | **Name**| **Type**| **Readable/Writable**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| eid | number | Read only| ID of the information element.| | eid | number | Read only| ID of the information element.|
...@@ -211,6 +224,7 @@ Enumerates the WLAN channel widths. ...@@ -211,6 +224,7 @@ Enumerates the WLAN channel widths.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
| **Name**| **Default Value**| **Description**| | **Name**| **Default Value**| **Description**|
| -------- | -------- | -------- | | -------- | -------- | -------- |
| WIDTH_20MHZ | 0 | 20 MHz.| | WIDTH_20MHZ | 0 | 20 MHz.|
...@@ -232,6 +246,7 @@ Obtains the scan result. This API returns the result synchronously. ...@@ -232,6 +246,7 @@ Obtains the scan result. This API returns the result synchronously.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| &nbsp;Array&lt;[WifiScanInfo](#wifiscaninfo)&gt; | Scan result obtained.| | &nbsp;Array&lt;[WifiScanInfo](#wifiscaninfo)&gt; | Scan result obtained.|
...@@ -242,18 +257,21 @@ Obtains the scan result. This API returns the result synchronously. ...@@ -242,18 +257,21 @@ Obtains the scan result. This API returns the result synchronously.
addDeviceConfig(config: WifiDeviceConfig): Promise&lt;number&gt; addDeviceConfig(config: WifiDeviceConfig): Promise&lt;number&gt;
Adds network configuration. This API uses a promise to return the result. Adds network configuration. This API uses a promise to return the result.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.SET_WIFI_CONFIG **Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.SET_WIFI_CONFIG
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| config | [WifiDeviceConfig](#wifideviceconfig) | Yes| WLAN configuration to add.| | config | [WifiDeviceConfig](#wifideviceconfig) | Yes| WLAN configuration to add.|
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| Promise&lt;number&gt; | Promise used to return the WLAN configuration ID. If **-1** is returned, the operation has failed.| | Promise&lt;number&gt; | Promise used to return the WLAN configuration ID. If **-1** is returned, the operation has failed.|
...@@ -264,6 +282,7 @@ Represents the WLAN configuration. ...@@ -264,6 +282,7 @@ Represents the WLAN configuration.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
| **Name**| **Type**| **Readable/Writable**| **Description**| | **Name**| **Type**| **Readable/Writable**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| ssid | string | Read only| SSID of the hotspot, in UTF-8 format.| | ssid | string | Read only| SSID of the hotspot, in UTF-8 format.|
...@@ -271,22 +290,25 @@ Represents the WLAN configuration. ...@@ -271,22 +290,25 @@ Represents the WLAN configuration.
| preSharedKey | string | Read only| PSK of the hotspot.| | preSharedKey | string | Read only| PSK of the hotspot.|
| isHiddenSsid | boolean | Read only| Whether the network is hidden.| | isHiddenSsid | boolean | Read only| Whether the network is hidden.|
| securityType | [WifiSecurityType](#wifisecuritytype) | Read only| Security type.| | securityType | [WifiSecurityType](#wifisecuritytype) | Read only| Security type.|
| creatorUid | number | Read only| User ID, which is available only to system applications.| | creatorUid | number | Read only| ID of the creator.<br> **System API**: This is a system API.|
| disableReason | number | Read only| Reason for disabling WLAN. This parameter is available only to system applications.| | disableReason | number | Read only| Reason for disabling WLAN.<br> **System API**: This is a system API.|
| netId | number | Read only| Allocated network ID, which is available only to system applications.| | netId | number | Read only| Network ID.<br> **System API**: This is a system API.|
| randomMacType | number | Read only| Random MAC type, which is available only to system applications.| | randomMacType | number | Read only| Random MAC type.<br> **System API**: This is a system API.|
| randomMacAddr | string | Read only| Random MAC address, which is available only for system applications.| | randomMacAddr | string | Read only| Random MAC address.<br> **System API**: This is a system API.|
| ipType | [IpType](#iptype7) | Read only| IP address type, which is available only to system applications.| | ipType | [IpType](#iptype7) | Read only| IP address type.<br> **System API**: This is a system API.|
| staticIp | [IpConfig](#ipconfig7) | Read only| Static IP address configuration, which is available only to system applications.| | staticIp | [IpConfig](#ipconfig7) | Read only| Static IP address configuration.<br> **System API**: This is a system API.|
| eapConfig<sup>9+</sup> | [WifiEapConfig](#wifieapconfig9) | Read only| EAP configuration, which is available only to system applications.| | eapConfig<sup>9+</sup> | [WifiEapConfig](#wifieapconfig9) | Read only| EAP configuration.<br> **System API**: This is a system API.|
## IpType<sup>7+</sup> ## IpType<sup>7+</sup>
Enumerate the IP address types. Enumerate the IP address types.
**System API**: This is a system API.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
| Name| Default Value| Description| | Name| Default Value| Description|
| -------- | -------- | -------- | | -------- | -------- | -------- |
| STATIC | 0 | Static IP address.| | STATIC | 0 | Static IP address.|
...@@ -298,6 +320,8 @@ Enumerate the IP address types. ...@@ -298,6 +320,8 @@ Enumerate the IP address types.
Represents IP configuration information. Represents IP configuration information.
**System API**: This is a system API.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
| **Name**| **Type**| **Readable/Writable**| **Description**| | **Name**| **Type**| **Readable/Writable**| **Description**|
...@@ -312,6 +336,8 @@ Represents IP configuration information. ...@@ -312,6 +336,8 @@ Represents IP configuration information.
Represents EAP configuration information. Represents EAP configuration information.
**System API**: This is a system API.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
| **Name**| **Type**| **Readable/Writable**| **Description**| | **Name**| **Type**| **Readable/Writable**| **Description**|
...@@ -335,6 +361,8 @@ Represents EAP configuration information. ...@@ -335,6 +361,8 @@ Represents EAP configuration information.
Enumerates the EAP authentication methods. Enumerates the EAP authentication methods.
**System API**: This is a system API.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
| Name| Default Value| Description| | Name| Default Value| Description|
...@@ -354,6 +382,8 @@ Enumerates the EAP authentication methods. ...@@ -354,6 +382,8 @@ Enumerates the EAP authentication methods.
Enumerates the Phase 2 authentication methods. Enumerates the Phase 2 authentication methods.
**System API**: This is a system API.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
| Name| Default Value| Description| | Name| Default Value| Description|
...@@ -373,13 +403,15 @@ Enumerates the Phase 2 authentication methods. ...@@ -373,13 +403,15 @@ Enumerates the Phase 2 authentication methods.
addDeviceConfig(config: WifiDeviceConfig, callback: AsyncCallback&lt;number&gt;): void addDeviceConfig(config: WifiDeviceConfig, callback: AsyncCallback&lt;number&gt;): void
Adds network configuration. This API uses an asynchronous callback to return the result. Adds network configuration. This API uses an asynchronous callback to return the result.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.SET_WIFI_CONFIG **Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.SET_WIFI_CONFIG
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| config | [WifiDeviceConfig](#wifideviceconfig) | Yes| WLAN configuration to add.| | config | [WifiDeviceConfig](#wifideviceconfig) | Yes| WLAN configuration to add.|
...@@ -397,11 +429,13 @@ Adds the configuration of an untrusted network. This API uses a promise to retur ...@@ -397,11 +429,13 @@ Adds the configuration of an untrusted network. This API uses a promise to retur
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| config | [WifiDeviceConfig](#wifideviceconfig) | Yes| WLAN configuration to add.| | config | [WifiDeviceConfig](#wifideviceconfig) | Yes| WLAN configuration to add.|
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| Promise&lt;boolean&gt; | Promise used to return the result. If the operation is successful, **true** is returned; otherwise, **false** is returned.| | Promise&lt;boolean&gt; | Promise used to return the result. If the operation is successful, **true** is returned; otherwise, **false** is returned.|
...@@ -418,6 +452,7 @@ Adds the configuration of an untrusted network. This API uses an asynchronous ca ...@@ -418,6 +452,7 @@ Adds the configuration of an untrusted network. This API uses an asynchronous ca
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| config | [WifiDeviceConfig](#wifideviceconfig) | Yes| WLAN configuration to add.| | config | [WifiDeviceConfig](#wifideviceconfig) | Yes| WLAN configuration to add.|
...@@ -435,11 +470,13 @@ Removes the configuration of an untrusted network. This API uses a promise to re ...@@ -435,11 +470,13 @@ Removes the configuration of an untrusted network. This API uses a promise to re
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| config | [WifiDeviceConfig](#wifideviceconfig) | Yes| WLAN configuration to remove.| | config | [WifiDeviceConfig](#wifideviceconfig) | Yes| WLAN configuration to remove.|
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| Promise&lt;boolean&gt; | Promise used to return the result. If the operation is successful, **true** is returned; otherwise, **false** is returned.| | Promise&lt;boolean&gt; | Promise used to return the result. If the operation is successful, **true** is returned; otherwise, **false** is returned.|
...@@ -456,6 +493,7 @@ Removes the configuration of an untrusted network. This API uses an asynchronous ...@@ -456,6 +493,7 @@ Removes the configuration of an untrusted network. This API uses an asynchronous
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| config | [WifiDeviceConfig](#wifideviceconfig) | Yes| WLAN configuration to remove.| | config | [WifiDeviceConfig](#wifideviceconfig) | Yes| WLAN configuration to remove.|
...@@ -473,11 +511,13 @@ Adds the configuration of a candidate network. This API uses a promise to return ...@@ -473,11 +511,13 @@ Adds the configuration of a candidate network. This API uses a promise to return
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| config | [WifiDeviceConfig](#wifideviceconfig) | Yes| WLAN configuration to add.| | config | [WifiDeviceConfig](#wifideviceconfig) | Yes| WLAN configuration to add.|
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| Promise&lt;number&gt; | Promise used to return the network configuration ID.| | Promise&lt;number&gt; | Promise used to return the network configuration ID.|
...@@ -494,6 +534,7 @@ Adds the configuration of a candidate network. This API uses an asynchronous cal ...@@ -494,6 +534,7 @@ Adds the configuration of a candidate network. This API uses an asynchronous cal
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| config | [WifiDeviceConfig](#wifideviceconfig) | Yes| WLAN configuration to add.| | config | [WifiDeviceConfig](#wifideviceconfig) | Yes| WLAN configuration to add.|
...@@ -511,11 +552,13 @@ Removes the configuration of a candidate network. This API uses a promise to ret ...@@ -511,11 +552,13 @@ Removes the configuration of a candidate network. This API uses a promise to ret
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| networkId | number | Yes| ID of the network configuration to remove.| | networkId | number | Yes| ID of the network configuration to remove.|
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| Promise&lt;void&gt; | Promise used to return the result.| | Promise&lt;void&gt; | Promise used to return the result.|
...@@ -532,6 +575,7 @@ Removes the configuration of a candidate network. This API uses an asynchronous ...@@ -532,6 +575,7 @@ Removes the configuration of a candidate network. This API uses an asynchronous
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| networkId | number | Yes| ID of the network configuration to remove.| | networkId | number | Yes| ID of the network configuration to remove.|
...@@ -549,6 +593,7 @@ Obtains candidate network configuration. ...@@ -549,6 +593,7 @@ Obtains candidate network configuration.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| &nbsp;Array&lt;[WifiDeviceConfig](#wifideviceconfig)&gt; | Candidate network configuration obtained.| | &nbsp;Array&lt;[WifiDeviceConfig](#wifideviceconfig)&gt; | Candidate network configuration obtained.|
...@@ -556,7 +601,7 @@ Obtains candidate network configuration. ...@@ -556,7 +601,7 @@ Obtains candidate network configuration.
## wifi.connectToCandidateConfig<sup>9+</sup> ## wifi.connectToCandidateConfig<sup>9+</sup>
connectToCandidateConfig(networkId: number): boolean connectToCandidateConfig(networkId: number): void
Connects to a candidate network. Connects to a candidate network.
...@@ -565,33 +610,32 @@ Connects to a candidate network. ...@@ -565,33 +610,32 @@ Connects to a candidate network.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| networkId | number | Yes| ID of the candidate network configuration.| | networkId | number | Yes| ID of the candidate network configuration.|
**Return value**
| **Type**| **Description**|
| -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
## wifi.connectToNetwork ## wifi.connectToNetwork
connectToNetwork(networkId: number): boolean connectToNetwork(networkId: number): boolean
Connects to the specified network. Connects to the specified network.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications) **Required permissions**: ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications)
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| networkId | number | Yes| Network configuration ID.| | networkId | number | Yes| Network configuration ID.|
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -602,20 +646,22 @@ This is a system API. ...@@ -602,20 +646,22 @@ This is a system API.
connectToDevice(config: WifiDeviceConfig): boolean connectToDevice(config: WifiDeviceConfig): boolean
Connects to the specified network. Connects to the specified network.
This is a system API.
**Required permissions**: **System API**: This is a system API.
ohos.permission.SET_WIFI_INFO, ohos.permission.SET_WIFI_CONFIG, and ohos.permissio.MANAGE_WIFI_CONNECTION (available only to system applications)
**Required permissions**: ohos.permission.SET_WIFI_INFO, ohos.permission.SET_WIFI_CONFIG, and ohos.permissio.MANAGE_WIFI_CONNECTION (available only to system applications)
**System capability**: **System capability**:
SystemCapability.Communication.WiFi.STA SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| config | [WifiDeviceConfig](#wifideviceconfig) | Yes| WLAN configuration.| | config | [WifiDeviceConfig](#wifideviceconfig) | Yes| WLAN configuration.|
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -625,16 +671,17 @@ This is a system API. ...@@ -625,16 +671,17 @@ This is a system API.
disconnect(): boolean disconnect(): boolean
Disconnects from the specified network. Disconnects the network.
This is a system API.
**Required permissions**: **System API**: This is a system API.
ohos.permission.SET_WIFI_INFO and ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications)
**Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications)
**System capability**: **System capability**:
SystemCapability.Communication.WiFi.STA SystemCapability.Communication.WiFi.STA
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -651,12 +698,14 @@ Obtains the WLAN signal level. ...@@ -651,12 +698,14 @@ Obtains the WLAN signal level.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| rssi | number | Yes| RSSI of the hotspot, in dBm.| | rssi | number | Yes| RSSI of the hotspot, in dBm.|
| band | number | Yes| Frequency band of the WLAN AP.| | band | number | Yes| Frequency band of the WLAN AP.|
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| number | Signal level obtained. The value range is [0, 4].| | number | Signal level obtained. The value range is [0, 4].|
...@@ -673,6 +722,7 @@ Obtains WLAN connection information. This API uses a promise to return the resul ...@@ -673,6 +722,7 @@ Obtains WLAN connection information. This API uses a promise to return the resul
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Return value** **Return value**
| Type| Description| | Type| Description|
| -------- | -------- | | -------- | -------- |
| Promise&lt;[WifiLinkedInfo](#wifilinkedinfo)&gt; | Promise used to return the WLAN connection information obtained.| | Promise&lt;[WifiLinkedInfo](#wifilinkedinfo)&gt; | Promise used to return the WLAN connection information obtained.|
...@@ -689,6 +739,7 @@ Obtains WLAN connection information. This API uses an asynchronous callback to r ...@@ -689,6 +739,7 @@ Obtains WLAN connection information. This API uses an asynchronous callback to r
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| Name| Type| Mandatory| Description| | Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| callback | AsyncCallback&lt;[WifiLinkedInfo](#wifilinkedinfo)&gt; | Yes| Callback invoked to return the result. If the operation is successful, **err** is **0** and **data** is the WLAN connection information obtained. If **err** is not **0**, an error has occurred.| | callback | AsyncCallback&lt;[WifiLinkedInfo](#wifilinkedinfo)&gt; | Yes| Callback invoked to return the result. If the operation is successful, **err** is **0** and **data** is the WLAN connection information obtained. If **err** is not **0**, an error has occurred.|
...@@ -723,19 +774,19 @@ Represents the WLAN connection information. ...@@ -723,19 +774,19 @@ Represents the WLAN connection information.
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| ssid | string | Read only| SSID of the hotspot, in UTF-8 format.| | ssid | string | Read only| SSID of the hotspot, in UTF-8 format.|
| bssid | string | Read only| BSSID of the hotspot.| | bssid | string | Read only| BSSID of the hotspot.|
| networkId | number | Read only| Network configuration ID, which is available only to system applications.| | networkId | number | Read only| Network configuration ID.<br> **System API**: This is a system API.|
| rssi | number | Read only| RSSI of the hotspot, in dBm.| | rssi | number | Read only| RSSI of the hotspot, in dBm.|
| band | number | Read only| Frequency band of the WLAN AP.| | band | number | Read only| Frequency band of the WLAN AP.|
| linkSpeed | number | Read only| Speed of the WLAN AP.| | linkSpeed | number | Read only| Speed of the WLAN AP.|
| frequency | number | Read only| Frequency of the WLAN AP.| | frequency | number | Read only| Frequency of the WLAN AP.|
| isHidden | boolean | Read only| Whether to hide the WLAN AP.| | isHidden | boolean | Read only| Whether to hide the WLAN AP.|
| isRestricted | boolean | Read only| Whether to restrict data volume at the WLAN AP.| | isRestricted | boolean | Read only| Whether to restrict data volume at the WLAN AP.|
| chload | number | Read only| Channel load. A larger value indicates a higher load. This parameter is only available to system applications.| | chload | number | Read only| Channel load. A larger value indicates a higher load.<br> **System API**: This is a system API.|
| snr | number | Read only| Signal-to-noise ratio (SNR), which is available only to system applications.| | snr | number | Read only| Signal-to-noise ratio (SNR).<br> **System API**: This is a system API.|
| macType<sup>9+</sup> | number | Read only| MAC address type.| | macType<sup>9+</sup> | number | Read only| MAC address type.|
| macAddress | string | Read only| MAC address of the device.| | macAddress | string | Read only| MAC address of the device.|
| ipAddress | number | Read only| IP address of the device that sets up the WLAN connection.| | ipAddress | number | Read only| IP address of the device that sets up the WLAN connection.|
| suppState | [SuppState](#suppstate) | Read only| Supplicant state, which is available only to system applications.| | suppState | [SuppState](#suppstate) | Read only| Supplicant state.<br> **System API**: This is a system API.|
| connState | [ConnState](#connstate) | Read only| WLAN connection state.| | connState | [ConnState](#connstate) | Read only| WLAN connection state.|
...@@ -761,6 +812,8 @@ Enumerates the WLAN connection states. ...@@ -761,6 +812,8 @@ Enumerates the WLAN connection states.
Enumerates the supplicant states. Enumerates the supplicant states.
**System API**: This is a system API.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
| Name| Default Value| Description| | Name| Default Value| Description|
...@@ -790,6 +843,7 @@ Checks whether the WLAN is connected. ...@@ -790,6 +843,7 @@ Checks whether the WLAN is connected.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the WLAN is connected; returns **false** otherwise.| | boolean | Returns **true** if the WLAN is connected; returns **false** otherwise.|
...@@ -800,13 +854,15 @@ Checks whether the WLAN is connected. ...@@ -800,13 +854,15 @@ Checks whether the WLAN is connected.
getSupportedFeatures(): number getSupportedFeatures(): number
Obtains the features supported by this device. Obtains the features supported by this device.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.GET_WIFI_INFO **Required permissions**: ohos.permission.GET_WIFI_INFO
**System capability**: SystemCapability.Communication.WiFi.Core **System capability**: SystemCapability.Communication.WiFi.Core
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| number | Feature value. | | number | Feature value. |
...@@ -839,11 +895,13 @@ Checks whether the device supports the specified WLAN feature. ...@@ -839,11 +895,13 @@ Checks whether the device supports the specified WLAN feature.
**Parameters** **Parameters**
| **Name**| **Type**| Mandatory| **Description**| | **Name**| **Type**| Mandatory| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| featureId | number | Yes| Feature ID.| | featureId | number | Yes| Feature ID.|
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the feature is supported; returns **false** otherwise.| | boolean | Returns **true** if the feature is supported; returns **false** otherwise.|
...@@ -854,13 +912,15 @@ Checks whether the device supports the specified WLAN feature. ...@@ -854,13 +912,15 @@ Checks whether the device supports the specified WLAN feature.
getDeviceMacAddress(): string[] getDeviceMacAddress(): string[]
Obtains the device MAC address. Obtains the device MAC address.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.GET_WIFI_LOCAL_MAC and ohos.permission.GET_WIFI_INFO (available only to system applications) **Required permissions**: ohos.permission.GET_WIFI_LOCAL_MAC and ohos.permission.GET_WIFI_INFO (available only to system applications)
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| string[] | MAC address obtained.| | string[] | MAC address obtained.|
...@@ -877,6 +937,7 @@ Obtains IP information. ...@@ -877,6 +937,7 @@ Obtains IP information.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| [IpInfo](#ipinfo7) | IP information obtained.| | [IpInfo](#ipinfo7) | IP information obtained.|
...@@ -910,6 +971,7 @@ Obtains the country code. ...@@ -910,6 +971,7 @@ Obtains the country code.
**System capability**: SystemCapability.Communication.WiFi.Core **System capability**: SystemCapability.Communication.WiFi.Core
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| string | Country code obtained.| | string | Country code obtained.|
...@@ -920,13 +982,15 @@ Obtains the country code. ...@@ -920,13 +982,15 @@ Obtains the country code.
reassociate(): boolean reassociate(): boolean
Re-associates with the network. Re-associates with the network.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications) **Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications)
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -937,13 +1001,15 @@ This is a system API. ...@@ -937,13 +1001,15 @@ This is a system API.
reconnect(): boolean reconnect(): boolean
Reconnects to the network. Reconnects to the network.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications) **Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications)
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -954,13 +1020,15 @@ This is a system API. ...@@ -954,13 +1020,15 @@ This is a system API.
getDeviceConfigs(): &nbsp;Array&lt;[WifiDeviceConfig](#wifideviceconfig)&gt; getDeviceConfigs(): &nbsp;Array&lt;[WifiDeviceConfig](#wifideviceconfig)&gt;
Obtains network configuration. Obtains network configuration.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.GET_WIFI_INFO, ohos.permission.LOCATION, and ohos.permission.GET_WIFI_CONFIG **Required permissions**: ohos.permission.GET_WIFI_INFO, ohos.permission.LOCATION, and ohos.permission.GET_WIFI_CONFIG
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| &nbsp;Array&lt;[WifiDeviceConfig](#wifideviceconfig)&gt; | Array of network configuration obtained.| | &nbsp;Array&lt;[WifiDeviceConfig](#wifideviceconfig)&gt; | Array of network configuration obtained.|
...@@ -968,24 +1036,27 @@ This is a system API. ...@@ -968,24 +1036,27 @@ This is a system API.
## wifi.updateNetwork<sup>7+</sup> ## wifi.updateNetwork<sup>7+</sup>
updateNetwork(config: WifiDeviceConfig): boolean updateNetwork(config: WifiDeviceConfig): number
Updates network configuration. Updates network configuration.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.SET_WIFI_CONFIG **Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.SET_WIFI_CONFIG
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| config | [WifiDeviceConfig](#wifideviceconfig) | Yes| New WLAN configuration.| | config | [WifiDeviceConfig](#wifideviceconfig) | Yes| New WLAN configuration.|
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | number | ID of the updated network configuration. The value **-1** indicates that the operation has failed.|
## wifi.disableNetwork<sup>7+</sup> ## wifi.disableNetwork<sup>7+</sup>
...@@ -993,18 +1064,21 @@ This is a system API. ...@@ -993,18 +1064,21 @@ This is a system API.
disableNetwork(netId: number): boolean disableNetwork(netId: number): boolean
Disables network configuration. Disables network configuration.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications) **Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications)
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| netId | number | Yes| ID of the network configuration to disable.| | netId | number | Yes| ID of the network configuration to disable.|
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -1015,13 +1089,15 @@ This is a system API. ...@@ -1015,13 +1089,15 @@ This is a system API.
removeAllNetwork(): boolean removeAllNetwork(): boolean
Removes the configuration of all networks. Removes the configuration of all networks.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications) **Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications)
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -1032,18 +1108,21 @@ This is a system API. ...@@ -1032,18 +1108,21 @@ This is a system API.
removeDevice(id: number): boolean removeDevice(id: number): boolean
Removes the specified network configuration. Removes the specified network configuration.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications) **Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications)
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| id | number | Yes| ID of the network configuration to remove.| | id | number | Yes| ID of the network configuration to remove.|
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -1054,13 +1133,15 @@ This is a system API. ...@@ -1054,13 +1133,15 @@ This is a system API.
enableHotspot(): boolean enableHotspot(): boolean
Enables this hotspot. Enables this hotspot.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.MANAGE_WIFI_HOTSPOT (available only to system applications) **Required permissions**: ohos.permission.MANAGE_WIFI_HOTSPOT (available only to system applications)
**System capability**: SystemCapability.Communication.WiFi.AP.Core **System capability**: SystemCapability.Communication.WiFi.AP.Core
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -1071,13 +1152,15 @@ This is a system API. ...@@ -1071,13 +1152,15 @@ This is a system API.
disableHotspot(): boolean disableHotspot(): boolean
Disables this hotspot. Disables this hotspot.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.MANAGE_WIFI_HOTSPOT (available only to system applications) **Required permissions**: ohos.permission.MANAGE_WIFI_HOTSPOT (available only to system applications)
**System capability**: SystemCapability.Communication.WiFi.AP.Core **System capability**: SystemCapability.Communication.WiFi.AP.Core
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -1088,13 +1171,15 @@ This is a system API. ...@@ -1088,13 +1171,15 @@ This is a system API.
isHotspotDualBandSupported(): boolean isHotspotDualBandSupported(): boolean
Checks whether the hotspot supports dual band. Checks whether the hotspot supports dual band.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.GET_WIFI_INFO and ohos.permission.MANAGE_WIFI_HOTSPOT (available only to system applications) **Required permissions**: ohos.permission.GET_WIFI_INFO and ohos.permission.MANAGE_WIFI_HOTSPOT (available only to system applications)
**System capability**: SystemCapability.Communication.WiFi.AP.Core **System capability**: SystemCapability.Communication.WiFi.AP.Core
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the feature is supported; returns **false** otherwise.| | boolean | Returns **true** if the feature is supported; returns **false** otherwise.|
...@@ -1105,13 +1190,15 @@ This is a system API. ...@@ -1105,13 +1190,15 @@ This is a system API.
isHotspotActive(): boolean isHotspotActive(): boolean
Checks whether this hotspot is active. Checks whether this hotspot is active.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.GET_WIFI_INFO **Required permissions**: ohos.permission.GET_WIFI_INFO
**System capability**: SystemCapability.Communication.WiFi.AP.Core **System capability**: SystemCapability.Communication.WiFi.AP.Core
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the hotspot is active; returns **false** otherwise.| | boolean | Returns **true** if the hotspot is active; returns **false** otherwise.|
...@@ -1122,18 +1209,21 @@ This is a system API. ...@@ -1122,18 +1209,21 @@ This is a system API.
setHotspotConfig(config: HotspotConfig): boolean setHotspotConfig(config: HotspotConfig): boolean
Sets hotspot configuration. Sets hotspot configuration.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.GET_WIFI_CONFIG **Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.GET_WIFI_CONFIG
**System capability**: SystemCapability.Communication.WiFi.AP.Core **System capability**: SystemCapability.Communication.WiFi.AP.Core
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| config | [HotspotConfig](#hotspotconfig7) | Yes| Hotspot configuration to set.| | config | [HotspotConfig](#hotspotconfig7) | Yes| Hotspot configuration to set.|
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -1143,6 +1233,8 @@ This is a system API. ...@@ -1143,6 +1233,8 @@ This is a system API.
Represents the hotspot configuration. Represents the hotspot configuration.
**System API**: This is a system API.
**System capability**: SystemCapability.Communication.WiFi.AP.Core **System capability**: SystemCapability.Communication.WiFi.AP.Core
| **Name**| **Type**| **Readable/Writable**| **Description**| | **Name**| **Type**| **Readable/Writable**| **Description**|
...@@ -1159,13 +1251,15 @@ Represents the hotspot configuration. ...@@ -1159,13 +1251,15 @@ Represents the hotspot configuration.
getHotspotConfig(): HotspotConfig getHotspotConfig(): HotspotConfig
obtains hotspot configuration. obtains hotspot configuration.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.GET_WIFI_INFO and ohos.permission.GET_WIFI_CONFIG **Required permissions**: ohos.permission.GET_WIFI_INFO and ohos.permission.GET_WIFI_CONFIG
**System capability**: SystemCapability.Communication.WiFi.AP.Core **System capability**: SystemCapability.Communication.WiFi.AP.Core
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| [HotspotConfig](#hotspotconfig7) | Hotspot configuration obtained.| | [HotspotConfig](#hotspotconfig7) | Hotspot configuration obtained.|
...@@ -1176,13 +1270,15 @@ This is a system API. ...@@ -1176,13 +1270,15 @@ This is a system API.
getStations(): &nbsp;Array&lt;[StationInfo](#stationinfo7)&gt; getStations(): &nbsp;Array&lt;[StationInfo](#stationinfo7)&gt;
Obtains information about the connected stations. Obtains information about the connected stations.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.GET_WIFI_INFO, ohos.permission.LOCATION, and ohos.permission.MANAGE_WIFI_HOTSPOT (available only to system applications) **Required permissions**: ohos.permission.GET_WIFI_INFO, ohos.permission.LOCATION, and ohos.permission.MANAGE_WIFI_HOTSPOT (available only to system applications)
**System capability**: SystemCapability.Communication.WiFi.AP.Core **System capability**: SystemCapability.Communication.WiFi.AP.Core
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| &nbsp;Array&lt;[StationInfo](#stationinfo7)&gt; | Connected stations obtained.| | &nbsp;Array&lt;[StationInfo](#stationinfo7)&gt; | Connected stations obtained.|
...@@ -1192,6 +1288,8 @@ This is a system API. ...@@ -1192,6 +1288,8 @@ This is a system API.
Represents the station information. Represents the station information.
**System API**: This is a system API.
**System capability**: SystemCapability.Communication.WiFi.AP.Core **System capability**: SystemCapability.Communication.WiFi.AP.Core
| **Name**| **Type**| **Readable/Writable**| **Description**| | **Name**| **Type**| **Readable/Writable**| **Description**|
...@@ -1212,6 +1310,7 @@ Obtains P2P link information. This API uses a promise to return the result. ...@@ -1212,6 +1310,7 @@ Obtains P2P link information. This API uses a promise to return the result.
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Return value** **Return value**
| Type| Description| | Type| Description|
| -------- | -------- | | -------- | -------- |
| Promise&lt;[WifiP2pLinkedInfo](#wifip2plinkedinfo8)&gt; | Promise used to return the P2P link information obtained.| | Promise&lt;[WifiP2pLinkedInfo](#wifip2plinkedinfo8)&gt; | Promise used to return the P2P link information obtained.|
...@@ -1254,6 +1353,7 @@ Obtains P2P link information. This API uses an asynchronous callback to return t ...@@ -1254,6 +1353,7 @@ Obtains P2P link information. This API uses an asynchronous callback to return t
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Parameters** **Parameters**
| Name| Type| Mandatory| Description| | Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| callback | AsyncCallback&lt;[WifiP2pLinkedInfo](#wifip2plinkedinfo8)&gt; | Yes| Callback invoked to return the result. If the operation is successful, **err** is **0** and **data** is the P2P link information. If **err** is not **0**, an error has occurred.| | callback | AsyncCallback&lt;[WifiP2pLinkedInfo](#wifip2plinkedinfo8)&gt; | Yes| Callback invoked to return the result. If the operation is successful, **err** is **0** and **data** is the P2P link information. If **err** is not **0**, an error has occurred.|
...@@ -1270,6 +1370,7 @@ Obtains the current P2P group information. This API uses a promise to return the ...@@ -1270,6 +1370,7 @@ Obtains the current P2P group information. This API uses a promise to return the
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Return value** **Return value**
| Type| Description| | Type| Description|
| -------- | -------- | | -------- | -------- |
| Promise&lt;[WifiP2pGroupInfo](#wifip2pgroupinfo8)&gt; | Promise used to return the group information obtained.| | Promise&lt;[WifiP2pGroupInfo](#wifip2pgroupinfo8)&gt; | Promise used to return the group information obtained.|
...@@ -1286,6 +1387,7 @@ Obtains the current P2P group information. This API uses an asynchronous callbac ...@@ -1286,6 +1387,7 @@ Obtains the current P2P group information. This API uses an asynchronous callbac
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Parameters** **Parameters**
| Name| Type| Mandatory| Description| | Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| callback | AsyncCallback&lt;[WifiP2pGroupInfo](#wifip2pgroupinfo8)&gt; | Yes| Callback invoked to return the result. If the operation is successful, **err** is **0** and **data** is the group information obtained. If **err** is not **0**, an error has occurred.| | callback | AsyncCallback&lt;[WifiP2pGroupInfo](#wifip2pgroupinfo8)&gt; | Yes| Callback invoked to return the result. If the operation is successful, **err** is **0** and **data** is the group information obtained. If **err** is not **0**, an error has occurred.|
...@@ -1302,6 +1404,7 @@ Obtains the peer device list in the P2P connection. This API uses a promise to r ...@@ -1302,6 +1404,7 @@ Obtains the peer device list in the P2P connection. This API uses a promise to r
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Return value** **Return value**
| Type| Description| | Type| Description|
| -------- | -------- | | -------- | -------- |
| Promise&lt;[WifiP2pDevice[]](#wifip2pdevice8)&gt; | Promise used to return the peer device list.| | Promise&lt;[WifiP2pDevice[]](#wifip2pdevice8)&gt; | Promise used to return the peer device list.|
...@@ -1318,6 +1421,7 @@ Obtains the peer device list in the P2P connection. This API uses an asynchronou ...@@ -1318,6 +1421,7 @@ Obtains the peer device list in the P2P connection. This API uses an asynchronou
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Parameters** **Parameters**
| Name| Type| Mandatory| Description| | Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| callback | AsyncCallback&lt;[WifiP2pDevice[]](#wifip2pdevice8)&gt; | Yes| Callback invoked to return the result. If the operation is successful, **err** is **0** and **data** is the peer device list obtained. If **err** is not **0**, an error has occurred.| | callback | AsyncCallback&lt;[WifiP2pDevice[]](#wifip2pdevice8)&gt; | Yes| Callback invoked to return the result. If the operation is successful, **err** is **0** and **data** is the peer device list obtained. If **err** is not **0**, an error has occurred.|
...@@ -1364,6 +1468,7 @@ Obtains the local device information in the P2P connection. This API uses a prom ...@@ -1364,6 +1468,7 @@ Obtains the local device information in the P2P connection. This API uses a prom
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Return value** **Return value**
| Type| Description| | Type| Description|
| -------- | -------- | | -------- | -------- |
| Promise&lt;[WifiP2pDevice](#wifip2pdevice8)&gt; | Promise used to return the local device information obtained.| | Promise&lt;[WifiP2pDevice](#wifip2pdevice8)&gt; | Promise used to return the local device information obtained.|
...@@ -1380,6 +1485,7 @@ Obtains the local device information in the P2P connection. This API uses an asy ...@@ -1380,6 +1485,7 @@ Obtains the local device information in the P2P connection. This API uses an asy
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Parameters** **Parameters**
| Name| Type| Mandatory| Description| | Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| callback | AsyncCallback&lt;[WifiP2pDevice](#wifip2pdevice8)&gt; | Yes| Callback invoked to return the result. If the operation is successful, **err** is **0** and **data** is the local device information obtained. If **err** is not **0**, an error has occurred.| | callback | AsyncCallback&lt;[WifiP2pDevice](#wifip2pdevice8)&gt; | Yes| Callback invoked to return the result. If the operation is successful, **err** is **0** and **data** is the local device information obtained. If **err** is not **0**, an error has occurred.|
...@@ -1402,6 +1508,7 @@ Creates a P2P group. ...@@ -1402,6 +1508,7 @@ Creates a P2P group.
| config | [WifiP2PConfig](#wifip2pconfig8) | Yes| Group configuration.| | config | [WifiP2PConfig](#wifip2pconfig8) | Yes| Group configuration.|
**Return value** **Return value**
| Type| Description| | Type| Description|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -1446,6 +1553,7 @@ Removes this P2P group. ...@@ -1446,6 +1553,7 @@ Removes this P2P group.
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Return value** **Return value**
| Type| Description| | Type| Description|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -1463,11 +1571,13 @@ Sets up a P2P connection. ...@@ -1463,11 +1571,13 @@ Sets up a P2P connection.
**Parameters** **Parameters**
| **Name**| **Type**| Mandatory| **Description**| | **Name**| **Type**| Mandatory| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| config | [WifiP2PConfig](#wifip2pconfig8) | Yes| P2P group configuration.| | config | [WifiP2PConfig](#wifip2pconfig8) | Yes| P2P group configuration.|
**Return value** **Return value**
| Type| Description| | Type| Description|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -1551,6 +1661,7 @@ Cancels this P2P connection. ...@@ -1551,6 +1661,7 @@ Cancels this P2P connection.
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Return value** **Return value**
| Type| Description| | Type| Description|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -1567,6 +1678,7 @@ Starts to discover devices. ...@@ -1567,6 +1678,7 @@ Starts to discover devices.
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Return value** **Return value**
| Type| Description| | Type| Description|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -1583,6 +1695,7 @@ Stops discovering devices. ...@@ -1583,6 +1695,7 @@ Stops discovering devices.
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Return value** **Return value**
| Type| Description| | Type| Description|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -1594,17 +1707,21 @@ deletePersistentGroup(netId: number): boolean ...@@ -1594,17 +1707,21 @@ deletePersistentGroup(netId: number): boolean
Deletes a persistent group. Deletes a persistent group.
**Required permissions**: ohos.permission.GET_WIFI_INFO **System API**: This is a system API.
**Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.MANAGE_WIFI_CONNECTION
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Parameters** **Parameters**
| **Name**| **Type**| Mandatory| **Description**| | **Name**| **Type**| Mandatory| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| netId | number | Yes| ID of the group to delete.| | netId | number | Yes| ID of the group to delete.|
**Return value** **Return value**
| Type| Description| | Type| Description|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -1615,13 +1732,15 @@ Deletes a persistent group. ...@@ -1615,13 +1732,15 @@ Deletes a persistent group.
getP2pGroups(): Promise&lt;Array&lt;WifiP2pGroupInfo&gt;&gt; getP2pGroups(): Promise&lt;Array&lt;WifiP2pGroupInfo&gt;&gt;
Obtains information about all P2P groups. This API uses a promise to return the result. Obtains information about all P2P groups. This API uses a promise to return the result.
This is a system API.
**System API**: This is a system API.
**Required permissions**: ohos.permission.GET_WIFI_INFO and ohos.permission.LOCATION **Required permissions**: ohos.permission.GET_WIFI_INFO and ohos.permission.LOCATION
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Return value** **Return value**
| Type| Description| | Type| Description|
| -------- | -------- | | -------- | -------- |
| Promise&lt;&nbsp;Array&lt;[WifiP2pGroupInfo](#wifip2pgroupinfo8)&gt;&nbsp;&gt; | Promise used to return the group information obtained.| | Promise&lt;&nbsp;Array&lt;[WifiP2pGroupInfo](#wifip2pgroupinfo8)&gt;&nbsp;&gt; | Promise used to return the group information obtained.|
...@@ -1652,11 +1771,14 @@ getP2pGroups(callback: AsyncCallback&lt;Array&lt;WifiP2pGroupInfo&gt;&gt;): void ...@@ -1652,11 +1771,14 @@ getP2pGroups(callback: AsyncCallback&lt;Array&lt;WifiP2pGroupInfo&gt;&gt;): void
Obtains information about all P2P groups. This API uses an asynchronous callback to return the result. Obtains information about all P2P groups. This API uses an asynchronous callback to return the result.
**System API**: This is a system API.
**Required permissions**: ohos.permission.GET_WIFI_INFO and ohos.permission.LOCATION **Required permissions**: ohos.permission.GET_WIFI_INFO and ohos.permission.LOCATION
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Parameters** **Parameters**
| Name| Type| Mandatory| Description| | Name| Type| Mandatory| Description|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| callback | AsyncCallback&lt;&nbsp;Array&lt;[WifiP2pGroupInfo](#wifip2pgroupinfo8)&gt;&gt; | Yes| Callback invoked to return the result. If the operation is successful, **err** is **0** and **data** is the group information obtained. If **err** is not **0**, an error has occurred.| | callback | AsyncCallback&lt;&nbsp;Array&lt;[WifiP2pGroupInfo](#wifip2pgroupinfo8)&gt;&gt; | Yes| Callback invoked to return the result. If the operation is successful, **err** is **0** and **data** is the group information obtained. If **err** is not **0**, an error has occurred.|
...@@ -1667,19 +1789,21 @@ Obtains information about all P2P groups. This API uses an asynchronous callback ...@@ -1667,19 +1789,21 @@ Obtains information about all P2P groups. This API uses an asynchronous callback
setDeviceName(devName: string): boolean setDeviceName(devName: string): boolean
Sets the device name. Sets the device name.
This is a system API.
**Required permissions**: **System API**: This is a system API.
ohos.permission.SET_WIFI_INFO and ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications)
**Required permissions**: ohos.permission.SET_WIFI_INFO and ohos.permission.MANAGE_WIFI_CONNECTION (available only to system applications)
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| devName | string | Yes| Device name to set.| | devName | string | Yes| Device name to set.|
**Return value** **Return value**
| **Type**| **Description**| | **Type**| **Description**|
| -------- | -------- | | -------- | -------- |
| boolean | Returns **true** if the operation is successful; returns **false** otherwise.| | boolean | Returns **true** if the operation is successful; returns **false** otherwise.|
...@@ -1696,6 +1820,7 @@ Registers the WLAN state change events. ...@@ -1696,6 +1820,7 @@ Registers the WLAN state change events.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **wifiStateChange**.| | type | string | Yes| Event type. The value is **wifiStateChange**.|
...@@ -1722,6 +1847,7 @@ Unregisters the WLAN state change events. ...@@ -1722,6 +1847,7 @@ Unregisters the WLAN state change events.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **wifiStateChange**.| | type | string | Yes| Event type. The value is **wifiStateChange**.|
...@@ -1755,6 +1881,7 @@ Registers the WLAN connection state change events. ...@@ -1755,6 +1881,7 @@ Registers the WLAN connection state change events.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **wifiConnectionChange**.| | type | string | Yes| Event type. The value is **wifiConnectionChange**.|
...@@ -1779,6 +1906,7 @@ Unregisters the WLAN connection state change events. ...@@ -1779,6 +1906,7 @@ Unregisters the WLAN connection state change events.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **wifiConnectionChange**.| | type | string | Yes| Event type. The value is **wifiConnectionChange**.|
...@@ -1796,6 +1924,7 @@ Registers the WLAN scan state change events. ...@@ -1796,6 +1924,7 @@ Registers the WLAN scan state change events.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **wifiScanStateChange**.| | type | string | Yes| Event type. The value is **wifiScanStateChange**.|
...@@ -1838,6 +1967,7 @@ Registers the RSSI change events. ...@@ -1838,6 +1967,7 @@ Registers the RSSI change events.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **wifiRssiChange**.| | type | string | Yes| Event type. The value is **wifiRssiChange**.|
...@@ -1855,6 +1985,7 @@ Unregisters the RSSI change events. ...@@ -1855,6 +1985,7 @@ Unregisters the RSSI change events.
**System capability**: SystemCapability.Communication.WiFi.STA **System capability**: SystemCapability.Communication.WiFi.STA
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **wifiRssiChange**.| | type | string | Yes| Event type. The value is **wifiRssiChange**.|
...@@ -1872,6 +2003,7 @@ Registers the hotspot state change events. ...@@ -1872,6 +2003,7 @@ Registers the hotspot state change events.
**System capability**: SystemCapability.Communication.WiFi.AP.Core **System capability**: SystemCapability.Communication.WiFi.AP.Core
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **hotspotStateChange**.| | type | string | Yes| Event type. The value is **hotspotStateChange**.|
...@@ -1898,6 +2030,7 @@ Unregisters the hotspot state change events. ...@@ -1898,6 +2030,7 @@ Unregisters the hotspot state change events.
**System capability**: SystemCapability.Communication.WiFi.AP.Core **System capability**: SystemCapability.Communication.WiFi.AP.Core
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **hotspotStateChange**.| | type | string | Yes| Event type. The value is **hotspotStateChange**.|
...@@ -1915,6 +2048,7 @@ Registers the P2P state change events. ...@@ -1915,6 +2048,7 @@ Registers the P2P state change events.
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **p2pStateChange**.| | type | string | Yes| Event type. The value is **p2pStateChange**.|
...@@ -1941,6 +2075,7 @@ Unregisters the P2P state change events. ...@@ -1941,6 +2075,7 @@ Unregisters the P2P state change events.
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **p2pStateChange**.| | type | string | Yes| Event type. The value is **p2pStateChange**.|
...@@ -1958,6 +2093,7 @@ Registers the P2P connection state change events. ...@@ -1958,6 +2093,7 @@ Registers the P2P connection state change events.
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **p2pConnectionChange**.| | type | string | Yes| Event type. The value is **p2pConnectionChange**.|
...@@ -1975,6 +2111,7 @@ Unregisters the P2P connection state change events. ...@@ -1975,6 +2111,7 @@ Unregisters the P2P connection state change events.
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **p2pConnectionChange**.| | type | string | Yes| Event type. The value is **p2pConnectionChange**.|
...@@ -1992,6 +2129,7 @@ Registers the P2P device state change events. ...@@ -1992,6 +2129,7 @@ Registers the P2P device state change events.
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **p2pDeviceChange**.| | type | string | Yes| Event type. The value is **p2pDeviceChange**.|
...@@ -2009,6 +2147,7 @@ Unregisters the P2P device state change events. ...@@ -2009,6 +2147,7 @@ Unregisters the P2P device state change events.
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **p2pDeviceChange**.| | type | string | Yes| Event type. The value is **p2pDeviceChange**.|
...@@ -2026,6 +2165,7 @@ Registers the P2P peer device state change events. ...@@ -2026,6 +2165,7 @@ Registers the P2P peer device state change events.
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **p2pPeerDeviceChange**.| | type | string | Yes| Event type. The value is **p2pPeerDeviceChange**.|
...@@ -2043,6 +2183,7 @@ Unregisters the P2P peer device state change events. ...@@ -2043,6 +2183,7 @@ Unregisters the P2P peer device state change events.
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **p2pPeerDeviceChange**.| | type | string | Yes| Event type. The value is **p2pPeerDeviceChange**.|
...@@ -2060,6 +2201,7 @@ Registers the P2P persistent group state change events. ...@@ -2060,6 +2201,7 @@ Registers the P2P persistent group state change events.
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **p2pPersistentGroupChange**.| | type | string | Yes| Event type. The value is **p2pPersistentGroupChange**.|
...@@ -2077,6 +2219,7 @@ Unregisters the P2P persistent group state change events. ...@@ -2077,6 +2219,7 @@ Unregisters the P2P persistent group state change events.
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **p2pPersistentGroupChange**.| | type | string | Yes| Event type. The value is **p2pPersistentGroupChange**.|
...@@ -2094,6 +2237,7 @@ Registers the P2P device discovery state change events. ...@@ -2094,6 +2237,7 @@ Registers the P2P device discovery state change events.
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **p2pDiscoveryChange**.| | type | string | Yes| Event type. The value is **p2pDiscoveryChange**.|
...@@ -2118,6 +2262,7 @@ Unregisters the P2P device discovery state change events. ...@@ -2118,6 +2262,7 @@ Unregisters the P2P device discovery state change events.
**System capability**: SystemCapability.Communication.WiFi.P2P **System capability**: SystemCapability.Communication.WiFi.P2P
**Parameters** **Parameters**
| **Name**| **Type**| **Mandatory**| **Description**| | **Name**| **Type**| **Mandatory**| **Description**|
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | Yes| Event type. The value is **p2pDiscoveryChange**.| | type | string | Yes| Event type. The value is **p2pDiscoveryChange**.|
......
...@@ -6,20 +6,20 @@ Components support dynamic rotation, translation, and scaling effects. These eff ...@@ -6,20 +6,20 @@ Components support dynamic rotation, translation, and scaling effects. These eff
> >
> The initial APIs of this component are supported since API version 7. Newly added APIs will be marked with a superscript to indicate their earliest API version. > The initial APIs of this component are supported since API version 7. Newly added APIs will be marked with a superscript to indicate their earliest API version.
| Name | Type | Default Value | Description | | Name | Type | Description |
| ------------------------- | ------------------------------------------------------------ | ------------------------------------- | ------------------------------------------------------------ | | ------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| transform-origin | string<sup>6+</sup> \| \<percentage> \| \<length> string<sup>6+</sup> \| \<percentage> \| \<length> | center center | Origin position of the transformed element. The unit can be px or a percentage (relative to the animation target component). If only one value is specified, the other one is **50%**. The available values for the first string are **left**, **center**, and **right**. The available values for the second string are **top**, **center**, and **bottom**.<br>Example:<br/>transform-origin: 200px 30%<br/>transform-origin: 100px topt<br/>ransform-origin: center center | | transform-origin | string<sup>6+</sup> \| \<percentage> \| \<length> string<sup>6+</sup> \| \<percentage> \| \<length> | Origin position of the transformed element. The unit can be px or a percentage (relative to the animation target component). If only one value is specified, the other one is **50%**. The available values for the first string are **left**, **center**, and **right**. The available values for the second string are **top**, **center**, and **bottom**.<br>Example:<br/>transform-origin: 200px 30%<br/>transform-origin: 100px topt<br/>ransform-origin: center center<br/>Default value: **center center** |
| transform | string | - | Translation, rotation, and scaling attributes.<br/>For details, see **transform**. | | transform | string | Translation, rotation, and scaling attributes.<br/>For details, see **transform**. |
| animation<sup>6+</sup> | string | 0s ease 0s 1 normal none running none | Animation attributes in the format of **duration \| timing-function \| delay \| iteration-count \| direction \| fill-mode \| play-state \| name**. The order of the parameters is not specified, but the **duration** and **delay** parameters are parsed based on where they are placed. | | animation<sup>6+</sup> | string | Animation attributes in the format of **duration \| timing-function \| delay \| iteration-count \| direction \| fill-mode \| play-state \| name**. The order of the parameters is not specified, but the **duration** and **delay** parameters are parsed based on where they are placed.<br/>Default value: 0s&nbsp;ease&nbsp;0s&nbsp;1&nbsp;normal&nbsp;none&nbsp;running&nbsp;none |
| animation-name | string | - | @keyframes rule. For details, see **@keyframes**. | | animation-name | string | @keyframes rule. For details, see **@keyframes**. |
| animation-delay | \<time> | 0 | Delay for playing the animation, in ms or s, for example, **1000 ms** or **1s**. The default unit is ms. | | animation-delay | \<time> | Delay for playing the animation, in ms or s, for example, **1000 ms** or **1s**. The default unit is ms.<br/>Default value: 0 |
| animation-duration | \<time> | 0 | Animation duration, in ms or s, for example, **1000 ms** or **1s**. The default unit is ms.<br/>NOTE:<br/>**animation-duration** must be specified. Otherwise, the duration is **0**, which means the animation will not be played. | | animation-duration | \<time> | Animation duration, in ms or s, for example, **1000 ms** or **1s**. The default unit is ms.<br/>**NOTE**<br/>**animation-duration** must be specified. Otherwise, the duration is **0**, which means the animation will not be played.<br/>Default value: **0** |
| animation-iteration-count | number \| infinite | 1 | Number of times that an animation is played. The animation is played once by default. You can set the value to **infinite** to play the animation infinitely. | | animation-iteration-count | number \| infinite | Number of times that an animation is played. The animation is played once by default. You can set the value to **infinite** to play the animation infinitely.<br/>Default value: **1** |
| animation-timing-function | string | ease | Speed curve of an animation, which makes the animation more fluent.Available values are as follows: <br>- **linear**: The animation speed keeps unchanged. <br>- **ease**: The animation starts at a low speed and then accelerates. It slows down before the animation ends. **cubic-bezier(0.25, 0.1, 0.25, 1.0)** <br>- **ease-in**: The animation starts at a low speed. **cubic-bezier(0.42, 0.0, 1.0, 1.0)** <br>- **ease-out**: The animation ends at a low speed. **cubic-bezier(0.0, 0.0, 0.58, 1.0)** <br>- **ease-in-out**: The animation starts and ends at a low speed. **cubic-bezier(0.42, 0.0, 0.58, 1.0)****<br>- **friction**: Damping curve, **cubic-bezier(0.2, 0.0, 0.2, 1.0)****<br>- **extreme-deceleration**: Extreme deceleration curve, **cubic-bezier(0.0, 0.0, 0.0, 1.0) curve****<br>- **sharp**: Sharp curve, **cubic-bezier(0.33, 0.0, 0.67, 1.0)****<br>- **rhythm**: Rhythm curve, **cubic-bezier(0.7, 0.0, 0.2, 1.0)****<br>- **smooth**: Smooth curve, **cubic-bezier(0.4, 0.0, 0.4, 1.0)****<br>- **cubic-bezier**: You can customize an animation speed curve in the **cubic-bezier()** function. The x and y values of each input parameter must be between 0 and 1.<br>- steps: step curve <sup>6+</sup>. Syntax: steps(number[, end\|start]); The number parameter is mandatory. The value must be a positive integer. The second parameter is optional. It indicates that the start point or end point of each interval changes step by step. The value can be end or start. The default value is end. | | animation-timing-function | string | Speed curve of an animation, which makes the animation more fluent.Available values are as follows: <br>- **linear**: The animation speed keeps unchanged. <br>- **ease**: The animation starts slowly, accelerates, and then slows down towards the end. The cubic-bezier curve (0.25, 0.1, 0.25, 1.0) is used.<br>- **ease-in**: The animation starts at a low speed. The cubic-bezier curve (0.42, 0.0, 1.0, 1.0) is used.<br>- **ease-out**: The animation ends at a low speed. The cubic-bezier curve (0.0, 0.0, 0.58, 1.0) is used.<br>- **ease-in-out**: The animation starts and ends at a low speed. The cubic-bezier curve (0.42, 0.0, 0.58, 1.0) is used.<br>- **friction**: The animation uses the friction cubic-bezier curve (0.2, 0.0, 0.2, 1.0).<br>- **extreme-deceleration**: The animation uses the extreme deceleration cubic-bezier curve (0.0, 0.0, 0.0, 1.0).<br>- **sharp**: The animation uses the sharp cubic-bezier curve (0.33, 0.0, 0.67, 1.0).<br>- **rhythm**: The animation uses the rhythm cubic-bezier curve (0.7, 0.0, 0.2, 1.0).<br>- **smooth**: The animation uses the smooth cubic-bezier curve (0.4, 0.0, 0.4, 1.0).<br>- **cubic-bezier**: You can customize an animation speed curve in the **cubic-bezier()** function. The x and y values of each input parameter must be between 0 and 1.<br>- **steps**: The animation uses the step curve<sup>6+</sup>. The syntax is as follows: steps(number[, end\|start]), where the first parameter **number** is mandatory and must be a positive integer; the second parameter is optional and indicates that the start point or end point (default) of each interval changes step by step.<br/>Default value: **ease** |
| animation-direction<sup>6+</sup> | string | normal | Mode of playing the animation. <br>- **normal**: Plays the animation in forward loop mode. <br>- **reverse**: Plays the animation in reverse loop mode. <br>- **alternate**: Plays the animation in alternating loop mode. When the animation is played for an odd number of times, the playback is in forward direction. When the animation is played for an even number of times, the playback is in backward direction. <br>- **alternate-reverse**: Plays the animation in reverse-alternating loop mode. When the animation is played for an odd number of times, the playback is in backward direction. When the animation is played for an even number of times, the playback is in forward direction. | | animation-direction<sup>6+</sup> | string | Mode of playing the animation. <br>- **normal**: Plays the animation in forward loop mode. <br>- **reverse**: Plays the animation in reverse loop mode. <br>- **alternate**: Plays the animation in alternating loop mode. When the animation is played for an odd number of times, the playback is in forward direction. When the animation is played for an even number of times, the playback is in backward direction. <br>- **alternate-reverse**: Plays the animation in reverse-alternating loop mode. When the animation is played for an odd number of times, the playback is in backward direction. When the animation is played for an even number of times, the playback is in forward direction.<br/>Default value: **normal** |
| animation-fill-mode | string | none | Start and end styles of the animation <br>- **none**: No style is applied to the target before or after the animation is executed. <br>- **forwards**: The target keeps the state at the end of the animation (defined in the last key frame) after the animation is executed. <br>- **backwards**<sup>6+</sup>: The animation uses the value defined in the first key frame during the **animation-delay**. When **animation-direction** is set to **normal** or **alternate**, the value in the **from** key frame is used. When **animation-direction** is set to **reverse** or **alternate-reverse**, the value in the **to** key frame is used.. <br>- **both**<sup>6+</sup>: The animation follows the **forwards** and **backwards** rules. | | animation-fill-mode | string | Start and end styles of the animation <br>- **none**: No style is applied to the target before or after the animation is executed. <br>- **forwards**: The target keeps the state at the end of the animation (defined in the last key frame) after the animation is executed. <br>- **backwards**<sup>6+</sup>: The animation uses the value defined in the first key frame during the **animation-delay**. When **animation-direction** is set to **normal** or **alternate**, the value in the **from** key frame is used. When **animation-direction** is set to **reverse** or **alternate-reverse**, the value in the **to** key frame is used.. <br>- **both**<sup>6+</sup>: The animation follows the **forwards** and **backwards** rules.<br/>Default value: none |
| animation-play-state<sup>6+</sup> | string | running | Current state of the animation. <br>- **paused**: paused <br>- **running**: playing | | animation-play-state<sup>6+</sup> | string | Current state of the animation. <br>- **paused**: paused <br>- **running**: playing<br/>Default value: **running** |
| transition<sup>6+</sup> | string | all 0 ease 0 | Transition effect when the component status is switched. The following four attributes can be set through the **transition** attribute.<br>- **transition-property**: name of the CSS property for setting the transition effect. Currently, the width, height, and background color are supported. <br>- **transition-duration**: duration required for completing the transition effect, in seconds. <br>- **transition-timing-function**: time curve of the transition effect. The curve provided by the style animation is supported. <br>- **transition-delay**: delay for starting the transition effect, in seconds. | | transition<sup>6+</sup> | string | Transition effect when the component status is switched. The following four attributes can be set through the **transition** attribute.<br>- **transition-property**: name of the CSS property for setting the transition effect. Currently, the width, height, and background color are supported. <br>- **transition-duration**: duration required for completing the transition effect, in seconds. <br>- **transition-timing-function**: time curve of the transition effect. The curve provided by the style animation is supported. <br>- **transition-delay**: delay for starting the transition effect, in seconds.<br/>Default value: **all&nbsp;0&nbsp;ease&nbsp;0** |
**Table 1** transform **Table 1** transform
......
# stepper<a name="EN-US_TOPIC_0000001173324583"></a> # stepper
The **<stepper\>** component provides a step navigator. When multiple steps are required to complete a task, you can use the **<stepper\>** component to navigate your users through the whole process. The **\<stepper>** component provides a step navigator. When multiple steps are required to complete a task, you can use the **\<stepper>** component to navigate your users through the whole process.
## Required Permissions<a name="section11257113618419"></a> > **NOTE**
>
> This component is supported since API version 5. Updates will be marked with a superscript to indicate their earliest API version.
## Required Permissions
None None
## Child Components<a name="section9288143101012"></a>
Only the **<stepper-item\>** component is supported.
>![](../../public_sys-resources/icon-note.gif) **NOTE:**
>Steps in the **<stepper\>** are sorted according to the sequence of its **<stepper-item\>** child components.
## Attributes<a name="section191521418142311"></a>
In addition to the attributes in [Universal Attributes](js-components-common-attributes.md), the following attributes are supported.
<a name="table20633101642315"></a>
<table><thead align="left"><tr id="row663331618238"><th class="cellrowborder" valign="top" width="25.040000000000003%" id="mcps1.1.5.1.1"><p id="a45273e2103004ff3bdd3375013e96a2a"><a name="a45273e2103004ff3bdd3375013e96a2a"></a><a name="a45273e2103004ff3bdd3375013e96a2a"></a>Name</p>
</th>
<th class="cellrowborder" valign="top" width="25.11%" id="mcps1.1.5.1.2"><p id="ad5b10d4a60e44bb4a8bbb3b4416d7b27"><a name="ad5b10d4a60e44bb4a8bbb3b4416d7b27"></a><a name="ad5b10d4a60e44bb4a8bbb3b4416d7b27"></a>Type</p>
</th>
<th class="cellrowborder" valign="top" width="11.18%" id="mcps1.1.5.1.3"><p id="ab2ae3d9f60d6475ab95ba095851a9d07"><a name="ab2ae3d9f60d6475ab95ba095851a9d07"></a><a name="ab2ae3d9f60d6475ab95ba095851a9d07"></a>Default Value</p>
</th>
<th class="cellrowborder" valign="top" width="38.67%" id="mcps1.1.5.1.4"><p id="af5c3b773ed0a42e589819a6c8d257ca1"><a name="af5c3b773ed0a42e589819a6c8d257ca1"></a><a name="af5c3b773ed0a42e589819a6c8d257ca1"></a>Description</p>
</th>
</tr>
</thead>
<tbody><tr id="row9173122818343"><td class="cellrowborder" valign="top" width="25.040000000000003%" headers="mcps1.1.5.1.1 "><p id="p1517410284349"><a name="p1517410284349"></a><a name="p1517410284349"></a>index</p>
</td>
<td class="cellrowborder" valign="top" width="25.11%" headers="mcps1.1.5.1.2 "><p id="p1174172823415"><a name="p1174172823415"></a><a name="p1174172823415"></a>number</p>
</td>
<td class="cellrowborder" valign="top" width="11.18%" headers="mcps1.1.5.1.3 "><p id="p19174112863417"><a name="p19174112863417"></a><a name="p19174112863417"></a>-</p>
</td>
<td class="cellrowborder" valign="top" width="38.67%" headers="mcps1.1.5.1.4 "><p id="p7174328203414"><a name="p7174328203414"></a><a name="p7174328203414"></a>Index of the <strong id="b1432325813342"><a name="b1432325813342"></a><a name="b1432325813342"></a>&lt;stepper-item&gt;</strong> child component that is currently displayed.</p>
</td>
</tr>
</tbody>
</table>
## Styles<a name="section72591594253"></a>
Styles in [Universal Styles](js-components-common-styles.md) are supported.
>![](../../public_sys-resources/icon-note.gif) **NOTE:**
>By default, the **<stepper\>** component fills entire space of its container. To optimize user experience, it is recommended that the container should be as large as the application window in size, or should be the root component.
## Events<a name="section69611614182911"></a>
In addition to the events in [Universal Events](js-components-common-events.md), the following events are supported.
<a name="table836435619510"></a>
<table><thead align="left"><tr id="row153658563517"><th class="cellrowborder" valign="top" width="10.481048104810482%" id="mcps1.1.4.1.1"><p id="a0ff86a4560fa46bfbeb711d109869422"><a name="a0ff86a4560fa46bfbeb711d109869422"></a><a name="a0ff86a4560fa46bfbeb711d109869422"></a>Name</p>
</th>
<th class="cellrowborder" valign="top" width="41.91419141914191%" id="mcps1.1.4.1.2"><p id="a4c85eb8ca18b4169a25c4a9263fa63ed"><a name="a4c85eb8ca18b4169a25c4a9263fa63ed"></a><a name="a4c85eb8ca18b4169a25c4a9263fa63ed"></a>Parameter</p>
</th>
<th class="cellrowborder" valign="top" width="47.6047604760476%" id="mcps1.1.4.1.3"><p id="ab30b2353efa245fbad4d2aaa2ee33def"><a name="ab30b2353efa245fbad4d2aaa2ee33def"></a><a name="ab30b2353efa245fbad4d2aaa2ee33def"></a>Description</p>
</th>
</tr>
</thead>
<tbody><tr id="row990553521718"><td class="cellrowborder" valign="top" width="10.481048104810482%" headers="mcps1.1.4.1.1 "><p id="p1390619353170"><a name="p1390619353170"></a><a name="p1390619353170"></a>finish</p>
</td>
<td class="cellrowborder" valign="top" width="41.91419141914191%" headers="mcps1.1.4.1.2 "><p id="p7906113541716"><a name="p7906113541716"></a><a name="p7906113541716"></a>None</p>
</td>
<td class="cellrowborder" valign="top" width="47.6047604760476%" headers="mcps1.1.4.1.3 "><p id="p7906113531711"><a name="p7906113531711"></a><a name="p7906113531711"></a>Triggered when the last step on the navigator is complete.</p>
</td>
</tr>
<tr id="row24211338161718"><td class="cellrowborder" valign="top" width="10.481048104810482%" headers="mcps1.1.4.1.1 "><p id="p2421113881715"><a name="p2421113881715"></a><a name="p2421113881715"></a>skip</p>
</td>
<td class="cellrowborder" valign="top" width="41.91419141914191%" headers="mcps1.1.4.1.2 "><p id="p16421133841719"><a name="p16421133841719"></a><a name="p16421133841719"></a>None</p>
</td>
<td class="cellrowborder" valign="top" width="47.6047604760476%" headers="mcps1.1.4.1.3 "><p id="p1342113381171"><a name="p1342113381171"></a><a name="p1342113381171"></a>Triggered when users click the skip button, which works only if you have called <strong id="b494641310465"><a name="b494641310465"></a><a name="b494641310465"></a>setNextButtonStatus</strong> method to allow users to skip all steps.</p>
</td>
</tr>
<tr id="row153591438186"><td class="cellrowborder" valign="top" width="10.481048104810482%" headers="mcps1.1.4.1.1 "><p id="p163591032182"><a name="p163591032182"></a><a name="p163591032182"></a>change</p>
</td>
<td class="cellrowborder" valign="top" width="41.91419141914191%" headers="mcps1.1.4.1.2 "><p id="p1535910381819"><a name="p1535910381819"></a><a name="p1535910381819"></a>{ prevIndex: prevIndex, index: index}</p>
</td>
<td class="cellrowborder" valign="top" width="47.6047604760476%" headers="mcps1.1.4.1.3 "><p id="p113602034189"><a name="p113602034189"></a><a name="p113602034189"></a>Triggered when users click the left or right (text) button of the step navigator to switch between steps. <strong id="b108361233105012"><a name="b108361233105012"></a><a name="b108361233105012"></a>prevIndex</strong> indicates the index of the previous step, and <strong id="b1014617216510"><a name="b1014617216510"></a><a name="b1014617216510"></a>index</strong> indicates that of the current step.</p>
</td>
</tr>
<tr id="row6686131145112"><td class="cellrowborder" valign="top" width="10.481048104810482%" headers="mcps1.1.4.1.1 "><p id="p126879113514"><a name="p126879113514"></a><a name="p126879113514"></a>next</p>
</td>
<td class="cellrowborder" valign="top" width="41.91419141914191%" headers="mcps1.1.4.1.2 "><p id="p06871911115113"><a name="p06871911115113"></a><a name="p06871911115113"></a>{ index: index, pendingIndex: pendingIndex }</p>
</td>
<td class="cellrowborder" valign="top" width="47.6047604760476%" headers="mcps1.1.4.1.3 "><p id="p18140235202411"><a name="p18140235202411"></a><a name="p18140235202411"></a>Triggered when users click the next (text) button. <strong id="b155446175519"><a name="b155446175519"></a><a name="b155446175519"></a>index</strong> indicates the index of the current step, and <strong id="b16471726587"><a name="b16471726587"></a><a name="b16471726587"></a>pendingIndex</strong> indicates that of the step to go. The return value is in <strong id="b20759101845911"><a name="b20759101845911"></a><a name="b20759101845911"></a>{pendingIndex:</strong><em id="i13961625125919"><a name="i13961625125919"></a><a name="i13961625125919"></a> pendingIndex</em><strong id="b1882982055918"><a name="b1882982055918"></a><a name="b1882982055918"></a>}</strong> format. You can use <strong id="b79512405598"><a name="b79512405598"></a><a name="b79512405598"></a>pendingIndex</strong> to specify a <strong id="b1235062917016"><a name="b1235062917016"></a><a name="b1235062917016"></a>&lt;stepper-item&gt;</strong> child component as the next step to go.</p>
</td>
</tr>
<tr id="row914118186514"><td class="cellrowborder" valign="top" width="10.481048104810482%" headers="mcps1.1.4.1.1 "><p id="p1414151817510"><a name="p1414151817510"></a><a name="p1414151817510"></a>back</p>
</td>
<td class="cellrowborder" valign="top" width="41.91419141914191%" headers="mcps1.1.4.1.2 "><p id="p16910122113429"><a name="p16910122113429"></a><a name="p16910122113429"></a>{ index: index, pendingIndex: pendingIndex }</p>
</td>
<td class="cellrowborder" valign="top" width="47.6047604760476%" headers="mcps1.1.4.1.3 "><p id="p714261895119"><a name="p714261895119"></a><a name="p714261895119"></a>Triggered when users click the previous (text) button. <strong id="b1620921210312"><a name="b1620921210312"></a><a name="b1620921210312"></a>index</strong> indicates the index of the current step, and <strong id="b1621511211318"><a name="b1621511211318"></a><a name="b1621511211318"></a>pendingIndex</strong> indicates that of the step to go. The return value is in Object:{ <strong id="b102171121532"><a name="b102171121532"></a><a name="b102171121532"></a>{pendingIndex:</strong><em id="i42187121636"><a name="i42187121636"></a><a name="i42187121636"></a> pendingIndex</em><strong id="b1622051211313"><a name="b1622051211313"></a><a name="b1622051211313"></a>}</strong> format. You can use <strong id="b822118128316"><a name="b822118128316"></a><a name="b822118128316"></a>pendingIndex</strong> to specify a <strong id="b192236121235"><a name="b192236121235"></a><a name="b192236121235"></a>&lt;stepper-item&gt;</strong> child component as the previous step.</p>
</td>
</tr>
</tbody>
</table>
## Methods<a name="section1954212182148"></a>
In addition to the methods in [Universal Methods](js-components-common-methods.md), the following events are supported.
<a name="table12793153991411"></a>
<table><thead align="left"><tr id="row15793239141412"><th class="cellrowborder" valign="top" width="19.561956195619562%" id="mcps1.1.4.1.1"><p id="p9794143915141"><a name="p9794143915141"></a><a name="p9794143915141"></a>Name</p>
</th>
<th class="cellrowborder" valign="top" width="24.102410241024103%" id="mcps1.1.4.1.2"><p id="p107942395147"><a name="p107942395147"></a><a name="p107942395147"></a>Parameter</p>
</th>
<th class="cellrowborder" valign="top" width="56.33563356335634%" id="mcps1.1.4.1.3"><p id="p11794133913143"><a name="p11794133913143"></a><a name="p11794133913143"></a>Description</p>
</th>
</tr>
</thead>
<tbody><tr id="row157940399145"><td class="cellrowborder" valign="top" width="19.561956195619562%" headers="mcps1.1.4.1.1 "><p id="p1479453913144"><a name="p1479453913144"></a><a name="p1479453913144"></a>setNextButtonStatus</p>
</td>
<td class="cellrowborder" valign="top" width="24.102410241024103%" headers="mcps1.1.4.1.2 "><p id="p10794163914147"><a name="p10794163914147"></a><a name="p10794163914147"></a>{ status: string, label: label }</p>
</td>
<td class="cellrowborder" valign="top" width="56.33563356335634%" headers="mcps1.1.4.1.3 "><p id="p12794143917141"><a name="p12794143917141"></a><a name="p12794143917141"></a>Sets the status of the next (text) button in this step navigator. Available <strong id="b29094326514"><a name="b29094326514"></a><a name="b29094326514"></a>status</strong> values are as follows:</p>
<a name="ol12242138121713"></a><a name="ol12242138121713"></a><ol id="ol12242138121713"><li><strong id="b1032161115214"><a name="b1032161115214"></a><a name="b1032161115214"></a>normal</strong>: The next button is displayed normally and can navigate users to the next step when it is clicked.</li><li><strong id="b1661325920517"><a name="b1661325920517"></a><a name="b1661325920517"></a>disabled</strong>: The next button is grayed out and unavailable.</li><li><strong id="b873175710711"><a name="b873175710711"></a><a name="b873175710711"></a>waiting</strong>: The next button is not displayed, and a process bar is displayed instead.</li><li><strong id="b1990819331594"><a name="b1990819331594"></a><a name="b1990819331594"></a>skip</strong>: The skip button is displayed to allow users to skip all remaining steps.</li></ol>
</td>
</tr>
</tbody>
</table>
## Example<a name="section15374183712313"></a>
``` ## Child Components
Only the **\<stepper-item>** component is supported.
> **NOTE**
>
> Steps in the **\<stepper>** are sorted according to the sequence of its **\<stepper-item>** child components.
## Attributes
In addition to the [universal attributes](../arkui-js/js-components-common-attributes.md), the following attributes are supported.
| Name | Type | Default Value | Description |
| ----- | ------ | ---- | ------------------------------ |
| index | number | - | Index of the **<stepper-item>** child component that is currently displayed.|
## Styles
The [universal styles](../arkui-js/js-components-common-styles.md) are supported.
> **NOTE**
>
> By default, the **\<stepper>** component fills entire space of its container. To optimize user experience, it is recommended that the container should be as large as the application window in size, or should be the root component.
## Events
In addition to the [universal events](../arkui-js/js-components-common-events.md), the following events are supported.
| Name | Parameter | Description |
| ------ | ---------------------------------------- | ---------------------------------------- |
| finish | - | Triggered when the last step on the navigator is complete. |
| skip | - | Triggered when users click the skip button, which works only if you have called **setNextButtonStatus** method to allow users to skip all steps.|
| change | { prevIndex: prevIndex, index: index} | Triggered when users click the left or right (text) button of the step navigator to switch between steps. **prevIndex** indicates the index of the previous step, and **index** indicates that of the current step.|
| next | { index: index, pendingIndex: pendingIndex } | Triggered when users click the next (text) button. **index** indicates the index of the current step, and **pendingIndex** indicates that of the step to go. The return value is in **{pendingIndex:*** pendingIndex***}** format. You can use **pendingIndex** to specify a **<stepper-item>** child component as the next step to go.|
| back | { index: index, pendingIndex: pendingIndex } | Triggered when users click the previous (text) button. **index** indicates the index of the current step, and **pendingIndex** indicates that of the step to go. The return value is in Object:{ **{pendingIndex:*** pendingIndex***}** format. You can use **pendingIndex** to specify a **<stepper-item>** child component as the previous step.|
## Methods
In addition to the [universal methods](../arkui-js/js-components-common-methods.md), the following methods are supported.
| Name | Parameter | Description |
| ------------------- | ---------------------------------------- | ---------------------------------------- |
| setNextButtonStatus | { status: string, label: label } | Sets the status of the next (text) button in this step navigator. Available **status** values are as follows:<br>- **normal**: The next button is displayed normally and can navigate users to the next step when it is clicked.<br>- **disabled**: The next button is grayed out and unavailable.<br>- **waiting**: The next button is not displayed, and a process bar is displayed instead.<br>- **skip**: The skip button is displayed to allow users to skip all remaining steps.|
## Example
```html
<!-- xxx.hml --> <!-- xxx.hml -->
<div class = "container"> <div class = "container">
<stepper class="stepper" id="mystepper" index="0" onnext="nextclick" onback="backclick"> <stepper class="stepper" id="mystepper" index="0" onnext="nextclick" onback="backclick">
...@@ -150,7 +89,7 @@ In addition to the methods in [Universal Methods](js-components-common-methods. ...@@ -150,7 +89,7 @@ In addition to the methods in [Universal Methods](js-components-common-methods.
</div> </div>
``` ```
``` ```css
/* xxx.css */ /* xxx.css */
.container { .container {
margin-top: 20px; margin-top: 20px;
...@@ -174,7 +113,7 @@ In addition to the methods in [Universal Methods](js-components-common-methods. ...@@ -174,7 +113,7 @@ In addition to the methods in [Universal Methods](js-components-common-methods.
} }
``` ```
``` ```js
// xxx.js // xxx.js
export default { export default {
data: { data: {
...@@ -215,5 +154,4 @@ export default { ...@@ -215,5 +154,4 @@ export default {
} }
``` ```
![](figures/en-us_image_0000001127125114.gif) ![en-us_image_0000001127125114](figures/en-us_image_0000001127125114.gif)
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
- [Resource File Categories](ui-ts-basic-resource-file-categories.md) - [Resource File Categories](ui-ts-basic-resource-file-categories.md)
- [Accessing Resources](ts-resource-access.md) - [Accessing Resources](ts-resource-access.md)
- [Pixel Units](ts-pixel-units.md) - [Pixel Units](ts-pixel-units.md)
- [Types](ts-types.md)
- Declarative Syntax - Declarative Syntax
- [Overview](ts-syntax-intro.md) - [Overview](ts-syntax-intro.md)
- General UI Description Specifications - General UI Description Specifications
...@@ -20,8 +19,8 @@ ...@@ -20,8 +19,8 @@
- Declarative UI Description Specifications - Declarative UI Description Specifications
- [Configuration Without Parameters](ts-parameterless-configuration.md) - [Configuration Without Parameters](ts-parameterless-configuration.md)
- [Configuration with Mandatory Parameters](ts-configuration-with-mandatory-parameters.md) - [Configuration with Mandatory Parameters](ts-configuration-with-mandatory-parameters.md)
- [Attribute Configuration](ts-attribution-configuration.md) - [Attribute Configuration](ts-attribution-configuration.md)
- [Event Configuration](ts-event-configuration.md) - [Event Configuration](ts-event-configuration.md)
- [Child Component Configuration](ts-child-component-configuration.md) - [Child Component Configuration](ts-child-component-configuration.md)
- Componentization - Componentization
...@@ -73,7 +72,8 @@ ...@@ -73,7 +72,8 @@
- [Building a Food Category List Layout](ui-ts-building-category-list-layout.md) - [Building a Food Category List Layout](ui-ts-building-category-list-layout.md)
- [Building a Food Category Grid Layout](ui-ts-building-category-grid-layout.md) - [Building a Food Category Grid Layout](ui-ts-building-category-grid-layout.md)
- [Implementing Page Redirection and Data Transmission](ui-ts-page-redirection-data-transmission.md) - [Implementing Page Redirection and Data Transmission](ui-ts-page-redirection-data-transmission.md)
- [Recommendations for Improving Performance](ts-performance-improvement-recommendation.md)
- JavaScript-based Web-like Development Paradigm - JavaScript-based Web-like Development Paradigm
- [Overview](ui-js-overview.md) - [Overview](ui-js-overview.md)
- Framework - Framework
......
# Recommendations for Improving Performance
Poor-performing code may work, but will take away from your application performance. This topic presents a line-up of recommendations that you can take to improve your implementation, thereby avoiding possible performance drop.
## Lazy Loading
When developing a long list, use of loop rendering, as in the code snippet below, can greatly slow down page loading and increase server load.
```ts
@Entry
@Component
struct MyComponent {
@State arr: number[] = Array.from(Array(100), (v,k) =>k); // Construct an array of 0 to 99.
build() {
List() {
ForEach(this.arr, (item: number) => {
ListItem() {
Text(`item value: ${item}`)
}
}, (item: number) => item.toString())
}
}
}
```
The preceding code snippet loads all of the 100 list elements at a time during page loading. This is generally not desirable. Instead, what we need is to load data from the data source and create corresponding components on demand. This can be achieved through lazy loading. The sample code is as follows:
```ts
class BasicDataSource implements IDataSource {
private listeners: DataChangeListener[] = []
public totalCount(): number {
return 0
}
public getData(index: number): any {
return undefined
}
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
console.info('add listener')
this.listeners.push(listener)
}
}
unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
console.info('remove listener')
this.listeners.splice(pos, 1)
}
}
notifyDataReload(): void {
this.listeners.forEach(listener => {
listener.onDataReloaded()
})
}
notifyDataAdd(index: number): void {
this.listeners.forEach(listener => {
listener.onDataAdd(index)
})
}
notifyDataChange(index: number): void {
this.listeners.forEach(listener => {
listener.onDataChange(index)
})
}
notifyDataDelete(index: number): void {
this.listeners.forEach(listener => {
listener.onDataDelete(index)
})
}
notifyDataMove(from: number, to: number): void {
this.listeners.forEach(listener => {
listener.onDataMove(from, to)
})
}
}
class MyDataSource extends BasicDataSource {
private dataArray: string[] = ['item value: 0', 'item value: 1', 'item value: 2']
public totalCount(): number {
return this.dataArray.length
}
public getData(index: number): any {
return this.dataArray[index]
}
public addData(index: number, data: string): void {
this.dataArray.splice(index, 0, data)
this.notifyDataAdd(index)
}
public pushData(data: string): void {
this.dataArray.push(data)
this.notifyDataAdd(this.dataArray.length - 1)
}
}
@Entry
@Component
struct MyComponent {
private data: MyDataSource = new MyDataSource()
build() {
List() {
LazyForEach(this.data, (item: string) => {
ListItem() {
Row() {
Text(item).fontSize(20).margin({ left: 10 })
}
}
.onClick(() => {
this.data.pushData('item value: ' + this.data.totalCount())
})
}, item => item)
}
}
}
```
The preceding code initializes only three list elements during page loading and loads a new list item each time a list element is clicked.
## Prioritizing Conditional Rendering over Visibility Control
Use of the visibility attribute to hide or show a component, as in the code snippet below, results in re-creation of the component, leading to performance drop.
```ts
@Entry
@Component
struct MyComponent {
@State isVisible: Visibility = Visibility.Visible;
build() {
Column() {
Button ("Show/Hide")
.onClick(() => {
if (this.isVisible == Visibility.Visible) {
this.isVisible = Visibility.None
} else {
this.isVisible = Visibility.Visible
}
})
Row().visibility(this.isVisible)
.width(300).height(300).backgroundColor(Color.Pink)
}.width('100%')
}
}
```
To avoid the preceding issue, use the **if** conditional statement instead. The sample code is as follows:
```ts
@Entry
@Component
struct MyComponent {
@State isVisible: boolean = true;
build() {
Column() {
Button ("Show/Hide")
.onClick(() => {
this.isVisible = !this.isVisible
})
if (this.isVisible) {
Row()
.width(300).height(300).backgroundColor(Color.Pink)
}
}.width('100%')
}
}
```
## Prioritizing Flex over Column/Row
By default, the flex container needs to re-lay out flex items to comply with the **flexShrink** and **flexGrow** settings. This may result in drop in rendering performance.
```ts
@Entry
@Component
struct MyComponent {
build() {
Flex({ direction: FlexDirection.Column }) {
Flex().width(300).height(200).backgroundColor(Color.Pink)
Flex().width(300).height(200).backgroundColor(Color.Yellow)
Flex().width(300).height(200).backgroundColor(Color.Grey)
}
}
}
```
To avoid the preceding issue, replace **Flex** with **Column** and **Row**, which can create the same page layout as **Flex** does.
```ts
@Entry
@Component
struct MyComponent {
build() {
Column() {
Row().width(300).height(200).backgroundColor(Color.Pink)
Row().width(300).height(200).backgroundColor(Color.Yellow)
Row().width(300).height(200).backgroundColor(Color.Grey)
}
}
}
```
## Setting Width and Height for \<List> Components
When a **\<List>** component is nested within a **\<Scroll>** component, all of its content will be loaded if its width and height is not specified, which may result in performance drop.
```ts
@Entry
@Component
struct MyComponent {
private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
build() {
Scroll() {
List() {
ForEach(this.arr, (item) => {
ListItem() {
Text(`item value: ${item}`).fontSize(30).margin({ left: 10 })
}.height(100)
}, (item) => item.toString())
}
}.backgroundColor(Color.Pink)
}
}
```
Therefore, in the above scenario, you are advised to set the width and height for the **\<List>** component as follows:
```ts
@Entry
@Component
struct MyComponent {
private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
build() {
Scroll() {
List() {
ForEach(this.arr, (item) => {
ListItem() {
Text(`item value: ${item}`).fontSize(30).margin({ left: 10 })
}.height(100)
}, (item) => item.toString())
}.width('100%').height(500)
}.backgroundColor(Color.Pink)
}
}
```
## Minimizing White Blocks During Swiping
To minimize white blocks durign swiping, expand the UI loading range by increasing the value of **cachedCount** for the **\<List>** and **\<Grid>** components. **cachedCount** indicates the number of list or grid items preloaded outside of the screen.
If an item needs to request an online image, set **cachedCount** as appropriate so that the the image is downloaded in advance before the item comes into view on the screen, thereby reducing the number of white blocks.
The following is an example of using **cachedCount**:
```ts
@Entry
@Component
struct MyComponent {
private source: MyDataSource = new MyDataSource();
build() {
List() {
LazyForEach (this.source, item => {
ListItem() {
Text("Hello" + item)
.fontSize(100)
.onAppear(()=>{
console.log("appear:" + item)
})
}
})
}.cachedCount(3) // Increase the value to enlarge the range of logs that appear.
}
}
class MyDataSource implements IDataSource {
data: number[] = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
public totalCount(): number {
return this.data.length
}
public getData(index: number): any {
return this.data[index]
}
registerDataChangeListener(listener: DataChangeListener): void {
}
unregisterDataChangeListener(listener: DataChangeListener): void {
}
}
```
**Instructions**
A greater **cachedCount** value may result in higher CPU and memory overhead of the UI. Adjust the value by taking into account both the comprehensive performance and user experience.
\ No newline at end of file
# Types
## Resource
The **Resource** type is used to reference resources for setting component attribute values.
If a **Resource** object is created using `$r` or `$rawfile`, modifying attribute values of the object is prohibited.
- `$r('belonging.type.name')`
**belonging**: system or application resource. The value can be **'sys'** or **'app'**.
**type**: resource type, which can be **'color'**, **'float'**, **'string'**, or **'media'**.
**name**: resource name, which is determined during resource definition.
- `$rawfile('filename')`
**filename**: name of the file in **resources/rawfile** of the project.
| Name | Type | Readable| Writable| Description |
| ----------------------- | ------ | ---- | ---- | ---------- |
| id | number | Yes | No | Resource ID. |
| type | number | Yes | No | Resource type. |
| params | any[] | Yes | No | Optional resource parameters. |
| bundleName<sup>9+</sup> | string | Yes | No | Bundle name. |
| moduleName<sup>9+</sup> | string | Yes | No | Module name.|
## Length
The **Length** type is used to represent a size unit.
| Type | Description |
| -------- | ------------------------------------------------------------ |
| string | String type. Explicitly specify the length unit, for example, **'10px'**, or the length in percentage, for example, **'100%'**.|
| number | Number type. The default unit is vp. |
| Resource | Size referenced from system or application resources. |
## ResourceStr<sup>8+</sup>
The **ResourceStr** type is used to represent the types that can be used by input parameters of the string type.
| Type | Description |
| -------- | --------------------------------------------------- |
| string | String type. |
| Resource | String referenced from system or application resources.|
## Padding
The **Padding** type is used to describe the padding areas in different directions of a component.
| Name | Type | Mandatory| Description |
| ------- | ------ | ---- |------------------------ |
| top | Length | No | Height of the padding area on the top of the component. |
| right | Length | No | Width of the padding area on the right of the component.|
| bottom | Length | No | Height of the padding area at the bottom of the component. |
| left | Length | No | Width of the padding area on the left of the component.|
## Margin
The **Margin** type is used to describe the margin areas in different directions of a component.
| Name | Type | Mandatory| Description |
| ------- | ------ | ---- |------------------------ |
| top | Length | No | Height of the margin area above the component. |
| right | Length | No | Width of the margin area on the right of the component.|
| bottom | Length | No | Height of the margin area below the component. |
| left | Length | No | Width of the margin area on the left of the component.|
## EdgeWidths<sup>9+</sup>
The **EdgeWidths** type is used to describe the edge widths in different directions of a component.
| Name | Type | Mandatory| Description |
| ------- | ------ | ---- |--------------------- |
| top | Length | No | Width of the top edge of the component. |
| right | Length | No | Width of the right edge of the component. |
| bottom | Length | No | Width of the bottom edge of the component. |
| left | Length | No | Width of the left edge of the component. |
## BorderRadiuses<sup>9+</sup>
The **BorderRadiuses** type is used to describe the radius of the rounded corners of a component.
| Name | Type | Mandatory| Description |
| ----------- | ------ | ---- |--------------------- |
| topLeft | Length | No | Radius of the top left rounded corner of the component. |
| topRight | Length | No | Radius of the top right rounded corner of the component. |
| bottomLeft | Length | No | Radius of the bottom left rounded corner of the component. |
| bottomRight | Length | No | Radius of the bottom right rounded corner of the component. |
## EdgeColors<sup>9+</sup>
The **EdgeColors** type is used to describe the edge colors of a component.
| Name | Type | Mandatory| Description |
| ------- | --------------- | ---- |--------------------- |
| top | ResourceColor | No | Color of the top edge of the component. |
| right | ResourceColor | No | Color of the right edge of the component. |
| bottom | ResourceColor | No | Color of the bottom edge of the component. |
| left | ResourceColor | No | Color of the left edge of the component. |
## EdgeStyles<sup>9+</sup>
The **EdgeStyles** type is used to describe the edge styles of a component.
| Name | Type | Mandatory| Description |
| ------- | ------------- | ---- |--------------------- |
| top | BorderStyle | No | Style of the top edge of the component. |
| right | BorderStyle | No | Style of the right edge of the component. |
| bottom | BorderStyle | No | Style of the bottom edge of the component. |
| left | BorderStyle | No | Style of the left edge of the component. |
## Offset
The **Offset** type is used to describe the offset coordinates of a component in the layout.
| Name | Type | Mandatory| Description |
| -------- | ------ | ---- |--------------------- |
| dx | Length | Yes | Horizontal offset. |
| dy | Length | Yes | Vertical offset. |
## ResourceColor<sup>8+</sup>
The **ResourceColor** type is used to describe the color types of resources.
| Type | Description |
| -------- | ----------------------- |
| [Color](../reference/arkui-ts/ts-appendix-enums.md#color) | Color enum. |
| number | Color in the hexadecimal notation. |
| string | Color in the RGB or RGBA notion. |
| Resource | Color referenced from system or application resources.|
## LengthConstrain
The **LengthConstrain** type is used to limit the maximum and minimum lengths of a component.
| Name | Type | Mandatory| Description |
| --------- | ------ | ---- |---------------- |
| minLength | Length | Yes | Minimum length of the component. |
| maxLength | Length | Yes | Maximum length of the component. |
## Font
The **Font** type is used to set the text style.
| Name | Type | Mandatory| Description |
| ------ | ------------------------------ | ---- | ------------------------------------------------------------ |
| size | number | No | Font size. If the value is of the number type, the unit fp is used. |
| weight | number | No | Font weight. For the number type, the value ranges from 100 to 900, at an interval of 100. The default value is **400**. A larger value indicates a larger font weight.|
| family | [FontWeight](../reference/arkui-ts/ts-appendix-enums.md#fontweight) \| number \| string | No | Font family of the text. Use commas (,) to separate multiple fonts. The priority of the fonts is the sequence in which they are placed. An example value is **'Arial, sans-serif'**.|
| style | string \| Resource | No | Font style. |
## Area<sup>8+</sup>
The **Area** type is used to describe the area information of the target element.
| Name | Type | Description |
| -------------- | -------- | ------------------------------------------------- |
| width | Length | Width of the target element. The value is of the number type when being used as the return value and the unit is vp. |
| height | Length | Height of the target element. The value is of the number type when being used as the return value and the unit is vp. |
| position | Position | Position of the upper left corner of the target element relative to that of the parent element. |
| globalPosition | Position | Position of the upper left corner of the target element relative to that of the page. |
## Position<sup>8+</sup>
The **Position** type is used to represent coordinates of a point.
| Name | Type | Mandatory| Description |
| ----- | ------- | ---- | ------------------------------------------- |
| x | Length | No | X coordinate. The value is of the number type when being used as the return value and the unit is vp. |
| y | Length | No | Y coordinate. The value is of the number type when used as the return value and the unit is vp. |
## ConstraintSizeOptions
The **ConstraintSizeOptions** type is used to set the constraint size of a component, thereby limiting the size range during component layout.
| Name | Type | Mandatory | Description |
| --------- | -------- | ---- | -------------- |
| minWidth | Length | No | Minimum width of the element. |
| maxWidth | Length | No | Maximum width of the element. |
| minHeight | Length | No | Minimum height of the element. |
| maxHeight | Length | No | Maximum height of the element. |
## SizeOptions
The **SizeOptions** type is used to set the width and height.
| Name | Type | Mandatory| Description |
| ------- | -------- | ---- | -------------- |
| width | Length | No | Width of the element. |
| height | Length | No | Height of the element. |
## BorderOptions
The **BorderOptions** type is used to provide border information.
| Name | Type | Mandatory | Description |
| ------ | ----------------------- | ---- | ----------- |
| width | Length \| EdgeWidths<sup>9+</sup> | No | Border width. |
| color | ResourceColor \| EdgeColors<sup>9+</sup> | No | Border color. |
| radius | Length \| BorderRadiuses<sup>9+</sup> | No | Border radius. |
| style | [BorderStyle](../reference/arkui-ts/ts-appendix-enums.md#borderstyle) \| EdgeStyles<sup>9+</sup> | No | Border style. |
## ColorFilter<sup>9+</sup>
The **ColorFilter** type is used to create a color filter with a 4*5 matrix.
| Name | Type | Mandatory | Description |
| ----------- | -------- | ------ | --------------------------------------------------------------- |
| constructor | number[] | Yes | Constructor for creating a color filter with a 4\*5 matrix. The input parameter is [m*n], which is the matrix value in row m and column n. The matrix is row-first. |
## CustomBuilder<sup>8+</sup>
The **CustomBuilder** type is used to define custom UI descriptions in component attribute methods.
| Name | Type | Description |
| ------------- | ---------------------- | ------------------------------------------------------------ |
| CustomBuilder | ()&nbsp;=&gt;&nbsp;any | Builder of component attribute methods for defining custom UI descriptions. This type of method must be decorated by **@Builder**. For details, see [@Builder](ts-component-based-builder.md).|
# &lt;stepper&gt; Development # \<stepper> Development
When multiple steps are required to complete a task, you can use the **<stepper>** component to navigate your users through the whole process. For details, see [stepper](../reference/arkui-js/js-components-container-stepper.md).
When multiple steps are required to complete a task, you can use the **&lt;stepper&gt;** component to navigate your users through the whole process. For details, see [stepper](../reference/arkui-js/js-components-container-stepper.md).
> **NOTE** > **NOTE**
...@@ -9,9 +8,9 @@ When multiple steps are required to complete a task, you can use the **&lt;stepp ...@@ -9,9 +8,9 @@ When multiple steps are required to complete a task, you can use the **&lt;stepp
> This component is supported since API version 5. > This component is supported since API version 5.
## Creating a &lt;stepper&gt; Component ## Creating a \<stepper> Component
Create a **&lt;stepper&gt;** component in the .hml file under **pages/index**. Create a **\<stepper>** component in the .hml file under **pages/index**.
```html ```html
<!-- xxx.hml --> <!-- xxx.hml -->
...@@ -85,7 +84,7 @@ text{ ...@@ -85,7 +84,7 @@ text{
![en-us_image_0000001267767837](figures/en-us_image_0000001267767837.gif) ![en-us_image_0000001267767837](figures/en-us_image_0000001267767837.gif)
Set the **label** attribute to customize the button text for the **&lt;stepper-item&gt;**. Set the **label** attribute to customize the label for the **\<stepper-item>**.
```html ```html
<!-- xxx.hml --> <!-- xxx.hml -->
...@@ -149,8 +148,7 @@ export default { ...@@ -149,8 +148,7 @@ export default {
## Setting Styles ## Setting Styles
By default, the **&lt;stepper&gt;** component fills entire space of its container. The sample code below shows how to set the border and background color using the **border** and **background-color** attributes. By default, the **\<stepper>** component fills entire space of its container. The sample code below shows how to set the border and background color using the **border** and **background-color** attributes.
```html ```html
<!-- xxx.hml --> <!-- xxx.hml -->
<div class="container" > <div class="container" >
...@@ -194,7 +192,7 @@ text{ ...@@ -194,7 +192,7 @@ text{
## Adding Events ## Adding Events
The **&lt;stepper&gt;** component supports the **finish**, **change**, **next**, **back**, and **skip** events. The **\<stepper>** component supports the **finish**, **change**, **next**, **back**, and **skip** events.
- When the **change** and **next** or **back** events exist at the same time, the **next** or **back** event is executed before the **change** event. - When the **change** and **next** or **back** events exist at the same time, the **next** or **back** event is executed before the **change** event.
...@@ -271,12 +269,14 @@ export default { ...@@ -271,12 +269,14 @@ export default {
stepperChange(e){ stepperChange(e){
console.log("stepperChange"+e.index) console.log("stepperChange"+e.index)
prompt.showToast({ prompt.showToast({
// index indicates the sequence number of the current step.
message: 'Previous step: '+e.prevIndex+"-------Current step:"+e.index message: 'Previous step: '+e.prevIndex+"-------Current step:"+e.index
}) })
}, },
stepperNext(e){ stepperNext(e){
console.log("stepperNext"+e.index) console.log("stepperNext"+e.index)
prompt.showToast({ prompt.showToast({
// pendingIndex indicates the sequence number of the step to be redirected to.
message: 'Current step:'+e.index+"-------Next step:"+e.pendingIndex message: 'Current step:'+e.index+"-------Next step:"+e.pendingIndex
}) })
var index = {pendingIndex:e.pendingIndex } var index = {pendingIndex:e.pendingIndex }
...@@ -295,9 +295,9 @@ export default { ...@@ -295,9 +295,9 @@ export default {
## Example Scenario ## Example Scenario
Select the options displayed on the page. Your selection will be shown in real time. Click the next button to dynamically change the font color and font size on the page. In this example, you can select the options displayed on the page and see how your selection takes effect in real time. Clicking the next button will dynamically change the font color and font size of the selected option.
Use the &lt;stepper&gt; component to navigate through the steps. Create a [&lt;toggle&gt;](../reference/arkui-js/js-components-basic-toggle.md) component to implement the functions of selection and displaying the selection result. Then use the [&lt;select&gt;](../reference/arkui-js/js-components-basic-select.md) component to dynamically change the font color or size of the selected options. Use a **\<stepper>** component to navigate through the steps. Create a **\<Toggle>**(../reference/arkui-js/js-components-basic-toggle.md) component to implement the functions of selecting an option and displaying the selection result. Then use the **\<Select>**(../reference/arkui-js/js-components-basic-select.md) component to dynamically change the font color or size of the selected option.
```html ```html
<!-- xxx.hml --> <!-- xxx.hml -->
...@@ -404,4 +404,4 @@ export default { ...@@ -404,4 +404,4 @@ export default {
} }
``` ```
![en-us_image_0000001267887817](figures/en-us_image_0000001267887817.gif) ![en-us_image_0000001267887817](figures/en-us_image_0000001267887817.gif)
\ No newline at end of file
...@@ -404,8 +404,8 @@ typedef struct { ...@@ -404,8 +404,8 @@ typedef struct {
} TreeNodeInfo; } TreeNodeInfo;
typedef struct { typedef struct {
TreeNodeInfo nodeInfo; /* Tree information data structure of each node. */ TreeNodeInfo nodeInfo; /* Data structure of each node's tree information. */
void *userInfo; /* User information data structure of each node. */ void *userInfo; /* Data structure of each node's user information. */
} TreeNode; } TreeNode;
``` ```
......
...@@ -12,14 +12,14 @@ ...@@ -12,14 +12,14 @@
### 创建数据对象实例 ### 创建数据对象实例
创建一个分布式数据对象实例,开发者可以通过source指定分布式对象中的属性。 创建一个分布式数据对象实例,开发者可以通过source指定分布式数据对象中的属性。
**表1** 分布式数据对象实例创建接口 **表1** 分布式数据对象实例创建接口
| 包名 | 接口名 | 描述 | | 包名 | 接口名 | 描述 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
| ohos.data.distributedDataObject| createDistributedObject(source: object): DistributedObject | 创建一个分布式数据对象实例,用于数据操作。 <br>-&nbsp;source:设置distributedObject的属性。<br>-&nbsp;DistributedObject:返回值是创建好的分布式对象。 | | ohos.data.distributedDataObject| createDistributedObject(source: object): DistributedObject | 创建一个分布式数据对象实例,用于数据操作。 <br>-&nbsp;source:设置分布式数据对象的属性。<br>-&nbsp;DistributedObject:返回值是创建好的分布式数据对象。 |
### 创建分布式数据对象sessionId ### 创建分布式数据对象sessionId
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
| 类名 | 接口名 | 描述 | | 类名 | 接口名 | 描述 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
| DistributedDataObject | setSessionId(sessionId?: string): boolean | 为分布式数据对象设置sessionId。<br>&nbsp;sessionId:分布式对象在可信组网中的标识ID。如果要退出分布式组网,设置为""或不设置均可。 | | DistributedDataObject | setSessionId(sessionId?: string): boolean | 为分布式数据对象设置sessionId。<br>&nbsp;sessionId:分布式数据对象在可信组网中的标识ID。如果要退出分布式组网,设置为""或不设置均可。 |
### 订阅数据变更 ### 订阅数据变更
...@@ -214,7 +214,7 @@ ...@@ -214,7 +214,7 @@
// 删除所有的变更回调 // 删除所有的变更回调
localObject.off("change"); localObject.off("change");
``` ```
9. 监听分布式对象的上下线。可以监听对端分布式数据对象的上下线。 9. 监听分布式数据对象的上下线。可以监听对端分布式数据对象的上下线。
```js ```js
function statusCallback(sessionId, networkId, status) { function statusCallback(sessionId, networkId, status) {
...@@ -242,7 +242,7 @@ ...@@ -242,7 +242,7 @@
console.info("revokeSave failed."); console.info("revokeSave failed.");
}); });
``` ```
11. 删除监听分布式对象的上下线。可以指定删除监听的上下线回调;也可以不指定,这将会删除该分布式数据对象的所有上下线回调。 11. 删除监听分布式数据对象的上下线。可以指定删除监听的上下线回调;也可以不指定,这将会删除该分布式数据对象的所有上下线回调。
```js ```js
// 删除上下线回调statusCallback // 删除上下线回调statusCallback
...@@ -250,7 +250,7 @@ ...@@ -250,7 +250,7 @@
// 删除所有的上下线回调 // 删除所有的上下线回调
localObject.off("status"); localObject.off("status");
``` ```
12. 退出同步组网。分布式对象退出组网后,本地的数据变更对端不会同步。 12. 退出同步组网。分布式数据对象退出组网后,本地的数据变更对端不会同步。
```js ```js
localObject.setSessionId(""); localObject.setSessionId("");
......
...@@ -26,70 +26,30 @@ ...@@ -26,70 +26,30 @@
| -------- | -------- | -------- | | -------- | -------- | -------- |
| ohos.sensor | sensor.on(sensorType, callback:AsyncCallback&lt;Response&gt;): void | 持续监听传感器数据变化 | | ohos.sensor | sensor.on(sensorType, callback:AsyncCallback&lt;Response&gt;): void | 持续监听传感器数据变化 |
| ohos.sensor | sensor.once(sensorType, callback:AsyncCallback&lt;Response&gt;): void | 获取一次传感器数据变化 | | ohos.sensor | sensor.once(sensorType, callback:AsyncCallback&lt;Response&gt;): void | 获取一次传感器数据变化 |
| ohos.sensor | sensor.off(sensorType, callback:AsyncCallback&lt;void&gt;): void | 注销传感器数据的监听 | | ohos.sensor | sensor.off(sensorType, callback?:AsyncCallback&lt;void&gt;): void | 注销传感器数据的监听 |
## 开发步骤 ## 开发步骤
1. 获取设备上传感器的数据,需要在“config.json”里面进行配置请求权限。具体如下: 1. 获取设备上传感器的数据前,需要检查是否已经配置请求相应的权限。 <br>
系统提供的传感器权限有:
``` - ohos.permission.ACCELEROMETER
"reqPermissions": [
{ - ohos.permission.GYROSCOPE
"name": "ohos.permission.ACCELEROMETER",
"reason": "", - ohos.permission.ACTIVITY_MOTION
"usedScene": {
"ability": [ - ohos.permission.READ_HEALTH_DATA
"sensor.index.MainAbility",
".MainAbility" 具体配置方式请参考[权限申请声明](../security/accesstoken-guidelines.md)
],
"when": "inuse"
}
},
{
"name": "ohos.permission.GYROSCOPE",
"reason": "",
"usedScene": {
"ability": [
"sensor.index.MainAbility",
".MainAbility"
],
"when": "inuse"
}
},
{
"name": "ohos.permission.ACTIVITY_MOTION",
"reason": "ACTIVITY_MOTION_TEST",
"usedScene": {
"ability": [
"sensor.index.MainAbility",
".MainAbility"
],
"when": "inuse"
}
},
{
"name": "ohos.permission.READ_HEALTH_DATA",
"reason": "HEALTH_DATA_TEST",
"usedScene": {
"ability": [
"sensor.index.MainAbility",
".MainAbility"
],
"when": "inuse"
}
}
]
```
2. 持续监听传感器数据变化。 2. 持续监听传感器数据变化。
``` ```
import sensor from "@ohos.sensor" import sensor from "@ohos.sensor";
sensor.on(sensor.sensorType.SENSOR_TYPE_ACCELEROMETER,function(data){ sensor.on(sensor.SensorType.SENSOR_TYPE_ID_ACCELEROMETER, function(data){
console.info("Subscription succeeded. data = " + data);// 调用成功,打印对应传感器的数据 console.info("Data obtained successfully. x: " + data.x + "y: " + data.y + "z: " + data.z);// 获取数据成功
} });
);
``` ```
以SensorType为SENSOR_TYPE_ID_ACCELEROMETER为例展示运行结果,持续监听传感器接口的结果如下图所示: 以SensorType为SENSOR_TYPE_ID_ACCELEROMETER为例展示运行结果,持续监听传感器接口的结果如下图所示:
...@@ -99,11 +59,8 @@ ...@@ -99,11 +59,8 @@
3. 注销传感器数据监听。 3. 注销传感器数据监听。
``` ```
import sensor from "@ohos.sensor" import sensor from "@ohos.sensor";
sensor.off(sensor.sensorType.SENSOR_TYPE_ACCELEROMETER,function() { sensor.off(sensor.SensorType.SENSOR_TYPE_ID_ACCELEROMETER);
console.info("Succeeded in unsubscribing from acceleration sensor data.");// 注销成功,返回打印结果
}
);
``` ```
以SensorType为SENSOR_TYPE_ID_ACCELEROMETER为例展示运行结果,注销传感器成功结果如下图所示: 以SensorType为SENSOR_TYPE_ID_ACCELEROMETER为例展示运行结果,注销传感器成功结果如下图所示:
...@@ -113,11 +70,10 @@ ...@@ -113,11 +70,10 @@
4. 获取一次传感器数据变化。 4. 获取一次传感器数据变化。
``` ```
import sensor from "@ohos.sensor" import sensor from "@ohos.sensor";
sensor.once(sensor.sensorType.SENSOR_TYPE_ACCELEROMETER,function(data) { sensor.once(sensor.SensorType.SENSOR_TYPE_ID_ACCELEROMETER, function(data) {
console.info("Data obtained successfully. data=" + data);// 获取数据成功,打印对应传感器的数据 console.info("Data obtained successfully. x: " + data.x + "y: " + data.y + "z: " + data.z);// 获取数据成功
} });
);
``` ```
以SensorType为SENSOR_TYPE_ID_ACCELEROMETER为例展示运行结果,获取数据成功日志如下图所示: 以SensorType为SENSOR_TYPE_ID_ACCELEROMETER为例展示运行结果,获取数据成功日志如下图所示:
...@@ -127,12 +83,13 @@ ...@@ -127,12 +83,13 @@
若接口调用不成功,建议使用try/catch语句捕获代码中可能出现的错误信息。例如: 若接口调用不成功,建议使用try/catch语句捕获代码中可能出现的错误信息。例如:
``` ```
import sensor from "@ohos.sensor";
try { try {
sensor.once(sensor.sensorType.SENSOR_TYPE_ACCELEROMETER,function(data) { sensor.once(sensor.SensorType.SENSOR_TYPE_ID_ACCELEROMETER, function(data) {
console.info("Data obtained successfully. data=" + data);// 获取数据成功,打印对应传感器的数据 console.info("Data obtained successfully. x: " + data.x + "y: " + data.y + "z: " + data.z);// 获取数据成功
}); });
} catch (error) { } catch (error) {
console.error(error); console.error("Get sensor data fail");
} }
``` ```
## 相关实例 ## 相关实例
......
...@@ -22,42 +22,7 @@ ...@@ -22,42 +22,7 @@
## 开发步骤 ## 开发步骤
1. 控制设备上的振动器,需要在`config.json`里面进行配置请求权限。具体如下: 1. 控制设备上的振动器,需要申请权限ohos.permission.VIBRATE。具体配置方式请参考[权限申请声明](../security/accesstoken-guidelines.md)
```
"reqPermissions": [
{
"name": "ohos.permission.ACCELEROMETER",
"reason": "",
"usedScene": {
"ability": [
".MainAbility"
],
"when": "inuse"
}
},
{
"name": "ohos.permission.VIBRATE",
"reason": "",
"usedScene": {
"ability": [
".MainAbility"
],
"when": "inuse"
}
},
{
"name": "ohos.permission.ACTIVITY_MOTION",
"reason": "",
"usedScene": {
"ability": [
".MainAbility"
],
"when": "inuse"
}
}
]
```
2. 触发设备振动。 2. 触发设备振动。
......
...@@ -23,7 +23,7 @@ Vibrator属于控制类小器件,主要包含以下四个模块:Vibrator API ...@@ -23,7 +23,7 @@ Vibrator属于控制类小器件,主要包含以下四个模块:Vibrator API
## 约束与限制 ## 约束与限制
在使用振动器时,开发者需要配置请求振动器的权限ohos.permission.VIBRATE,才能控制振动器振动,权限类型是system_grant 在使用振动器时,开发者需要配置请求振动器的权限ohos.permission.VIBRATE,才能控制振动器振动。
...@@ -18,7 +18,7 @@ extraData代表发送请求的额外数据,支持如下数据: ...@@ -18,7 +18,7 @@ extraData代表发送请求的额外数据,支持如下数据:
适用于:OpenHarmony SDK 3.2.2.5版本,API9 Stage模型 适用于:OpenHarmony SDK 3.2.2.5版本,API9 Stage模型
错误码28代表CURLE_OPERATION_TIMEDOUT 。网络请求底层使用libcurl库,更多错误码可以查看相应文档。 错误码28代表CURLE_OPERATION_TIMEDOUT,操作超时。网络请求底层使用libcurl库,更多错误码可以查看相应文档。
参考文档:[开发指南](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-http.md#response%E5%B8%B8%E7%94%A8%E9%94%99%E8%AF%AF%E7%A0%81)[Curl错误码](https://curl.se/libcurl/c/libcurl-errors.html) 参考文档:[开发指南](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-http.md#response%E5%B8%B8%E7%94%A8%E9%94%99%E8%AF%AF%E7%A0%81)[Curl错误码](https://curl.se/libcurl/c/libcurl-errors.html)
......
# 一次开发,多端部署 # 一次开发,多端部署
- [前言](about-this-document.md) - [前言](foreword.md)
- [简介](introduction.md) - [简介](introduction.md)
- 应用UX设计 - [从一个例子开始](start-with-a-example.md)
- [设计原则和要点](design-principles.md) - 应用UX设计
- 应用架构设计 - [设计原则和要点](design-principles.md)
- [应用导航结构设计要求](navigation-design.md) - 应用架构设计
- [应用页面结构设计](page-design.md) - [应用导航结构设计要求](navigation-design.md)
- 界面布局 - [应用页面结构设计](page-design.md)
- [概述](layout-design-intro.md) - 界面布局
- 布局基础 - [概述](interface-layout-design-intro.md)
- [栅格系统](layout-grid.md) - 布局基础
- [自适应布局](layout-adaptive.md) - [栅格系统](design-grid.md)
- [响应式布局](layout-responsive.md) - [自适应布局](design-adaptive-layout.md)
- [布局基础运用案例](layout-design-cases.md) - [响应式布局](design-responsive-layout.md)
- 人机交互 - [布局基础运用案例](design-layout-cases.md)
- [交互基础](interaction-basics.md) - 人机交互
- [常见输入方式](common-input-modes.md) - [交互基础](interaction-basics.md)
- [交互事件归一](design-interaction-events-unification.md) - [常见输入方式](common-input-modes.md)
- 视觉风格 - [交互事件归一](design-interaction-event-normalization.md)
- [视觉基础](visual-style-basics.md) - 视觉风格
- [色彩](visual-style-color.md) - [视觉基础](visual-basics.md)
- [字体](visual-style-font.md) - [色彩](visual-style-color.md)
- [图标](visual-style-icon.md) - [字体](visual-style-font.md)
- [多态控件](design-polymorphic-components.md) - [图标](visual-style-icon.md)
- [设计自检表](design-checklist.md) - [多态控件](design-polymorphic-controls.md)
- [资源](resource.md) - [设计自检表](design-checklist.md)
- [IDE使用](ide-usage.md) - [设计交付](design-delivery.md)
- 一多能力的页面开发介绍 - [资源](design-resources.md)
- 布局能力 - [工程管理](ide-using.md)
- [布局能力简介](layout-intro.md) - 页面开发的一多能力介绍
- 自适应布局 - [简介](page-development-intro.md)
- [自适应布局简介](adaptive-layout-intro.md) - 布局能力
- [拉伸能力](adaptive-layout-stretching.md) - [布局简介](layout-intro.md)
- [均分能力](adaptive-layout-equalization.md) - [自适应布局](adaptive-layout.md)
- [占比能力](adaptive-layout-proportion.md) - [响应式布局](responsive-layout.md)
- [缩放能力](adaptive-layout-scaling.md) - [典型布局场景](typical-layout-scenario.md)
- [延伸能力](adaptive-layout-extension.md) - 典型页面场景
- [隐藏能力](adaptive-layout-hiding.md) - [应用市场首页](appgallery-home-page.md)
- [折行能力](adaptive-layout-wrapping.md) - [音乐专辑页](music-album-page.md)
- 响应式布局 - [交互归一](interaction-event-normalization.md)
- [栅格断点系统](grid-breakpoint.md) - [多态组件](polymorphic-controls.md)
- [媒体查询](media-query.md) - [资源使用](resource-usage.md)
- [典型场景](responsive-layout-cases.md) - [功能开发的一多能力介绍](development-intro.md)
- [交互归一](interaction-events-unification.md) - [案例应用](case.md)
- [多态组件](polymorphic-components.md) - [常见问题](faq.md)
- [资源使用](resource-usage.md)
- [一多能力的功能开发介绍](development-intro.md)
- 案例应用
- 短信应用
- [概览](sms-intro.md)
- 会话详情页面
- [页面结构](sms-session-page-structure.md)
- [顶部标题栏](sms-session-page-title-bar.md)
- [底部输入栏](sms-session-page-input-field.md)
- [信息列表](sms-session-page-message-list.md)
- [组合成型](sms-session-page-combined.md)
- [总结](sms-session-summary.md)
- [桌面应用](cases-home-screen.md)
- [常见问题](faqs.md)
# 前言
本指导的目的是快速及全面地指导读者使用OpenHarmony提供的“一次开发,多端部署”(本指导中简称“一多”)能力开发多设备应用。在应用开发前,开发者应尽可能全面考虑应用支持多设备的情况,避免在后期加入新的类型设备时需要对应用架构进行大幅调整。
## 本指导面向的读者
本指导适合开发OpenHarmony应用的UX设计师、应用开发人员,本指导书统称为“应用开发者”。这两者是根据开发角色不同而进行的区分。对于个人或者规模较小的应用,两者可能是同一个个体,但应当从角色上加以区分。
## 如何阅读本指导
应用在需求明确后,开发过程大致分为:应用设计(包含界面UX设计、业务功能设计)- 工程设计和创建 - 功能代码实现。本指导也是基于这个流程进行的内容编排。
阅读本文档时,应尽量按照章节顺序进行阅读。如果区分开发角色,那么UX设计师可以仅阅读第3章,而开发人员可以从第4章开始阅读。但无论何种角色,我们强烈建议阅读第2章。
本文档各章节简介如下:
- 第1章[前言](about-this-document.md)说明本指导面向的读者、如何阅读本指导等,指引读者更好地阅读。
- 第2章[简介](introduction.md)简短介绍了“一多”的背景、定义、目标、以及用于指导后续开发的一些基础知识。
- 第3章[应用UX设计](design-principles.md)介绍了应用UX设计理念。主要阐述了应用设计之初UX设计的原则和要点。该章节主要面向应用的UX设计师。
UX设计原则应该考虑多设备的“差异性” 、“一致性”、“灵活性”、“兼容性”。
UX设计要点则从6个方面阐述如何进行多设备应用设计,分别是“自适应应用架构”、“响应式界面布局”、“交互归一”、“视觉参数化”、“多态控件”、“针对性优化”。
最后,给出设计自检表,用于检查应用UX设计是否合理。
- 第4章[IDE使用](ide-usage.md)介绍了从工程角度如何开始开发应用,这非常有用,让读者可以直接上手创建多设备应用的工程,是后面学习“一多”能力的上手基础。
- 第5章[一多能力的页面开发介绍](layout-intro.md)、第6章[一多能力的功能开发介绍](development-intro.md)介绍了OpenHarmony提供的“一多”能力,其中每个能力都提供了代码示例和UX效果,让读者可以快速学习“一多”能力。
- 第7章提供了两个案例应用,阐述了从应用设计到开发这一过程中如何实践前面章节介绍的设计思路或“一多”能力,让读者可以整体上掌握“一多”在应用开发过程中的知识。
- 第8章[常见问题](faqs.md)提供了常见问题(FAQ),方便读者查阅。
本指导在介绍过程中还包括一些“说明”。这些“说明”,表示例外情况或者额外信息的补充。
# 均分能力
均分能力是指容器组件尺寸发生变化时,增加或减小的空间均匀分配给容器组件内所有空白区域。它常用于内容数量固定、均分显示的场景,比如工具栏、底部菜单栏等。
均分能力通常通过使用 **Flex均分布局**[Flex组件](../../reference/arkui-ts/ts-container-flex.md)的justifyContent属性设置为FlexAlign.SpaceEvenly)实现,即子元素在Flex主轴方向等间距布局,相邻元素之间的间距、第一个元素与行首的间距、最后一个元素到行尾的间距都完全一样。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 均分能力是特殊场景下拉伸能力的简单实现。也可以借助其它方式实现均分能力,如在每个组件间添加Blank组件等。
## 示例:
父容器尺寸变化过程中,图标及文字的尺寸不变,图标间的间距及图标离左右边缘的距离同时均等改变。
![zh-cn_image_0000001291935425](figures/zh-cn_image_0000001291935425.gif)
```ts
@Entry
@Component
struct EquipartitionCapabilitySample {
const list: number [] = [0, 1, 2, 3];
@State rate: number = 0.6;
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.rate * 100, min: 30, max: 60, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.onChange((value: number) => {
this.rate = value / 100;
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Column() {
// 均匀分配父容器主轴方向的剩余空间
Flex({ justifyContent: FlexAlign.SpaceEvenly }) {
ForEach(this.list, (item) => {
Column() {
Image($r("app.media.icon")).width(48).height(48).margin({ top: 8 })
Text('App name')
.width(64)
.height(30)
.lineHeight(15)
.fontSize(12)
.textAlign(TextAlign.Center)
.margin({ top: 8 })
.padding({ bottom: 15 })
}.width(80).height(102)
})
}
// 均匀分配父容器主轴方向的剩余空间
Flex({ justifyContent: FlexAlign.SpaceEvenly }) {
ForEach(this.list, (item) => {
Column() {
Image($r("app.media.icon")).width(48).height(48).margin({ top: 8 })
Text('App name')
.width(64)
.height(30)
.lineHeight(15)
.fontSize(12)
.textAlign(TextAlign.Center)
.margin({ top: 8 })
.padding({ bottom: 15 })
}.width(80).height(102)
})
}
}
.width(this.rate * 100 + '%')
.height(222)
.padding({ top: 16 })
.backgroundColor('#FFFFFF')
.borderRadius(16)
this.slider()
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
}
```
# 延伸能力
延伸能力是指容器组件内的子组件,按照其在列表中的先后顺序,随容器组件尺寸变化显示或隐藏。它可以根据显示区域的尺寸,显示不同数量的元素。
延伸能力通常有两种实现方式:
- 通过[List组件](../../reference/arkui-ts/ts-container-list.md)实现。
- 通过[Scroll组件](../../reference/arkui-ts/ts-container-scroll.md)配合[Row组件](../../reference/arkui-ts/ts-container-row.md)[Column组件](../../reference/arkui-ts/ts-container-column.md)实现。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> List、Row或Column组件中子节点的在页面显示时就已经全部完成了布局计算及渲染,只不过受限于父容器尺寸,用户只能看到一部分。随着父容器尺寸增大,用户可以看到的子节点数目也相应的增加。用户还可以通过手指滑动触发列表滑动,查看被隐藏的子节点。
## 示例:
当父容器的尺寸发生改变时,页面中显示的图标数量随之发生改变。
分别通过List组件实现及通过Scroll组件配合Row组件实现。
![zh-cn_image_0000001245295918](figures/zh-cn_image_0000001245295918.gif)
(1)通过List组件实现。
```ts
@Entry
@Component
struct ExtensionCapabilitySample1 {
@State rate: number = 0.60;
const appList: number [] = [0, 1, 2, 3, 4, 5, 6, 7];
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.rate * 100, min: 8, max: 60, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.height(50)
.onChange((value: number) => {
this.rate = value / 100;
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Row({ space: 10 }) {
// 通过List组件实现隐藏能力
List({ space: 10 }) {
ForEach(this.appList, (item) => {
ListItem() {
Column() {
Image($r("app.media.icon")).width(48).height(48).margin({ top: 8 })
Text('App name')
.width(64)
.height(30)
.lineHeight(15)
.fontSize(12)
.textAlign(TextAlign.Center)
.margin({ top: 8 })
.padding({ bottom: 15 })
}.width(80).height(102)
}.width(80).height(102)
})
}
.padding({ top: 16, left: 10 })
.listDirection(Axis.Horizontal)
.width('100%')
.height(118)
.borderRadius(16)
.backgroundColor(Color.White)
}
.width(this.rate * 100 + '%')
this.slider()
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
}
```
(2)通过Scroll组件配合Row组件实现。
```ts
@Entry
@Component
struct ExtensionCapabilitySample2 {
private scroller: Scroller = new Scroller()
@State rate: number = 0.60;
@State appList: number [] = [0, 1, 2, 3, 4, 5, 6, 7];
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.rate * 100, min: 8, max: 60, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.height(50)
.onChange((value: number) => {
this.rate = value / 100;
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
// 通过Scroll和Row组件实现隐藏能力
Scroll(this.scroller) {
Row({ space: 10 }) {
ForEach(this.appList, () => {
Column() {
Image($r("app.media.icon")).width(48).height(48).margin({ top: 8 })
Text('App name')
.width(64)
.height(30)
.lineHeight(15)
.fontSize(12)
.textAlign(TextAlign.Center)
.margin({ top: 8 })
.padding({ bottom: 15 })
}.width(80).height(102)
})
}
.padding({ top: 16, left: 10 })
.height(118)
.borderRadius(16)
.backgroundColor(Color.White)
}
.scrollable(ScrollDirection.Horizontal)
.width(this.rate * 100 + '%')
this.slider()
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
}
```
# 隐藏能力
隐藏能力是指容器组件内的子组件,按照其预设的显示优先级,随容器组件尺寸变化显示或隐藏,其中相同显示优先级的子组件同时显示或隐藏。它是一种比较高级的布局方式,常用于分辨率变化较大,且不同分辨率下显示内容有所差异的场景。主要思想是通过增加或减少显示内容,来保持最佳的显示效果。
隐藏能力通过设置**布局优先级**(displayPriority属性)来控制显隐,当布局主轴方向剩余尺寸不足以满足全部元素时,按照布局优先级大小,从小到大依次隐藏,直到容器能够完整显示剩余元素。具有相同布局优先级的元素将同时显示或者隐藏。
可以访问[布局约束](../../reference/arkui-ts/ts-universal-attributes-layout-constraints.md),了解displayPriority属性的详细信息。
## 示例:
父容器尺寸发生变化时,其子元素按照预设的优先级显示或隐藏。
![zh-cn_image_0000001245136646](figures/zh-cn_image_0000001245136646.gif)
```ts
@Entry
@Component
struct HiddenCapabilitySample {
@State rate: number = 0.45;
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.rate * 100, min: 10, max: 45, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.height(50)
.onChange((value: number) => {
this.rate = value / 100;
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ direction: FlexDirection.Column,
justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Center }) {
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Image($r("app.media.favorite"))
.width(48)
.height(48)
.objectFit(ImageFit.Contain)
.margin({ left: 12, right: 12 })
.displayPriority(1) // 布局优先级
Image($r("app.media.down"))
.width(48)
.height(48)
.objectFit(ImageFit.Contain)
.margin({ left: 12, right: 12 })
.displayPriority(2) // 布局优先级
Image($r("app.media.pause"))
.width(48)
.height(48)
.objectFit(ImageFit.Contain)
.margin({ left: 12, right: 12 })
.displayPriority(3) // 布局优先级
Image($r("app.media.next"))
.width(48)
.height(48)
.objectFit(ImageFit.Contain)
.margin({ left: 12, right: 12 })
.displayPriority(2) // 布局优先级
Image($r("app.media.list"))
.width(48)
.height(48)
.objectFit(ImageFit.Contain)
.margin({ left: 12, right: 12 })
.displayPriority(1) // 布局优先级
}
.width(this.rate * 100 + '%')
.height(96)
.borderRadius(16)
.backgroundColor('#FFFFFF')
this.slider()
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
}
```
# 自适应布局简介
多设备间最大的差异是屏幕分辨率,差异分辨率适配离不开自适应布局的能力。针对常见的开发场景,方舟开发框架提炼了七种自适应布局能力。这些布局可以独立使用,也可多种布局叠加使用。
| 自适应布局类别 | 自适应布局能力 | 使用场景 |
| -------- | -------- | -------- |
| 自适应拉伸 | [拉伸能力](adaptive-layout-stretching.md) | 容器组件尺寸发生变化时,增加或减小的空间**全部分配**给容器组件内**指定区域**。 |
| [均分能力](adaptive-layout-equalization.md) | 容器组件尺寸发生变化时,增加或减小的空间**均匀分配**给容器组件内**所有空白区域**。 ||
| 自适应缩放 | [占比能力](adaptive-layout-proportion.md) | 子组件的宽高**按照预设的比例**,随容器组件发生变化。 |
| [缩放能力](adaptive-layout-scaling.md) | 子组件的宽高**按照预设的比例**,随容器组件发生变化,且变化过程中子组件的**宽高比不变**。 ||
| 自适应延伸 | [延伸能力](adaptive-layout-extension.md) | 容器组件内的子组件,按照其**在列表中的先后顺序**,随容器组件尺寸变化显示或隐藏。 |
| [隐藏能力](adaptive-layout-hiding.md) | 容器组件内的子组件,按照其**预设的显示优先级**,随容器组件尺寸变化显示或隐藏。**相同显示优先级的子组件同时显示或隐藏**。 ||
| 自适应折行 | [折行能力](adaptive-layout-wrapping.md) | 容器组件尺寸发生变化时,如果布局方向尺寸不足以显示完整内容,**自动换行**。 |
下面我们依次介绍这几种自适应布局能力。
# 占比能力
占比能力是指子组件的宽高按照预设的比例,随父容器组件发生变化。
占比能力通常有两种实现方式:
- 将子组件的宽高设置为父组件宽高的百分比,详见[尺寸设置](../../reference/arkui-ts/ts-universal-attributes-size.md)[长度类型](../../ui/ts-types.md#长度类型)
- 通过layoutWeight属性配置互为兄弟关系的组件在父容器主轴方向的布局权重,详见[尺寸设置](../../reference/arkui-ts/ts-universal-attributes-size.md)
- 当父容器尺寸确定时,其子组件按照开发者配置的权重比例分配父容器中主轴方向的空间。
- 仅当父容器是Row、Colomn或者Flex时,layoutWeight属性才会生效。
- 设置layoutWeight属性后,组件本身的尺寸会失效。比如同时设置了.width('40%')和.layoutWeight(1),那么只有.layoutWeight(1)会生效。
layoutWeight存在使用限制,所以实际使用过程中大多通过将子组件宽高设置为父组件的百分比来实现占比能力。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 占比能力在实际开发中使用的非常广泛,可以通过很多不同的方式实现占比能力,如还可以通过[Grid组件](../../reference/arkui-ts/ts-container-grid.md)的columnsTemplate属性设置网格容器中列的数量及其宽度比例,或通过配置子组件在栅格(本章后文将详细介绍栅格系统)中占据不同的列数来实现占比能力。本小节仅介绍最基础和常用的实现方式,局限性较大或比非常小众的实现方式,本文不再展开介绍。
## 示例:
简单的播放控制栏,其中“上一首”、“播放/暂停”、“下一首”的layoutWeight属性都设置为1,因此它们按照“1:1:1”的比例均分父容器主轴方向的空间。
将三个按钮的.layoutWeight(1)分别替换为.width('33%')、.width('34%')、.width('33%'),也可以实现与当前同样的显示效果。
![zh-cn_image_0000001292374353](figures/zh-cn_image_0000001292374353.gif)
```ts
@Entry
@Component
struct ProportionCapabilitySample {
@State rate: number = 0.5;
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: 100, min: 25, max: 50, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.height(50)
.onChange((value: number) => {
this.rate = value / 100;
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Column() {
Row() {
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Image($r("app.media.down"))
.width(48)
.height(48)
}
.height(96)
.layoutWeight(1) // 设置子组件在父容器主轴方向的布局权重
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Image($r("app.media.pause"))
.width(48)
.height(48)
}
.height(96)
.layoutWeight(1) // 设置子组件在父容器主轴方向的布局权重
.backgroundColor('#66F1CCB8')
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Image($r("app.media.next"))
.width(48)
.height(48)
}
.height(96)
.layoutWeight(1) // 设置子组件在父容器主轴方向的布局权重
}
.width(this.rate * 100 + '%')
.height(96)
.borderRadius(16)
.backgroundColor('#FFFFFF')
}
this.slider()
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
}
```
# 缩放能力
缩放能力是指子组件的宽高按照预设的比例,随容器组件发生变化,且变化过程中子组件的宽高比不变。
缩放能力通过使用百分比布局配合**固定宽高比**(aspectRatio属性)实现当容器尺寸发生变化时,内容自适应调整。
可以访问[布局约束](../../reference/arkui-ts/ts-universal-attributes-layout-constraints.md),了解aspectRatio属性的详细信息。
## 示例:
为方便查看效果,示例中特意给Column组件加了边框。可以看到Column组件随着其Flex父组件尺寸变化而缩放的过程中,始终保持预设的宽高比,其中的图片也始终正常显示。
![zh-cn_image_0000001245614634](figures/zh-cn_image_0000001245614634.gif)
```ts
@Entry
@Component
struct ScaleCapabilitySample {
@State width: number = 400;
@State height: number = 400;
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.width, min: 100, max: 400, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.height(50)
.onChange((value: number) => {
this.width = value;
})
.position({ x: '20%', y: '80%' })
Slider({ value: this.height, min: 100, max: 400, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.height(50)
.onChange((value: number) => {
this.height = value;
})
.position({ x: '20%', y: '87%' })
}
build() {
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Column() {
Image($r("app.media.illustrator")).width('100%').height('100%')
}
.aspectRatio(1) // 固定宽高比
.border({ width: 2, color: "#66F1CCB8"}) // 边框,仅用于展示效果
}
.backgroundColor("#FFFFFF")
.height(this.width)
.width(this.height)
this.slider()
}.width('100%')
.height('100%')
.backgroundColor("#F1F3F5")
}
}
```
# 拉伸能力
拉伸能力是指容器组件尺寸发生变化时,增加或减小的空间全部分配给容器组件内指定区域。
拉伸能力通常通过Flex布局的flexGrow和flexShrink属性实现,详见[Flex布局](../../reference/arkui-ts/ts-universal-attributes-flex-layout.md)
- flexGrow:仅当父容器宽度大于所有子组件宽度的总和时,该属性生效。配置了此属性的子组件,按照比例拉伸,分配父容器的多余空间。
- flexShrink:仅当父容器宽度小于所有子组件宽度的总和时,该属性生效。配置了此属性的子组件,按照比例收缩,分配父容器的不足空间。
特别的,当开发者期望将父容器的剩余空间全部分配给某空白区域时,也可以通过Blank组件实现。注意仅当父组件为Row\Column\Flex组件时,Blank组件才会生效,详见[Blank组件](../../reference/arkui-ts/ts-basic-components-blank.md)
## 示例1:
本示例中的页面由中间的内容区(包含一张图片)以及两侧的留白区组成。
中间内容区的宽度设置为400vp,同时将flexGrow属性设置为1,flexShrink属性设置为0。
两侧留白区的宽度设置为150vp,同时将flexGrow属性设置为0,flexShrink属性设置为1。
因此父容器的基准尺寸是700vp(150vp+400vp+150vp)。
当父容器的尺寸大于700vp时,父容器中多余的空间全部分配给中间内容区。
当父容器的尺寸小于700vp时,左右两侧的留白区按照“1:1”的比例收缩(即平均分配父容器的不足空间)。
![zh-cn_image_0000001245613530](figures/zh-cn_image_0000001245613530.gif)
```ts
@Entry
@Component
struct FlexibleCapabilitySample1 {
@State width: number = 402;
// 底部滑块,可以通过拖拽滑块改变容器尺寸。
@Builder slider() {
Slider({ value: this.width, min: 402, max: 1000, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.onChange((value: number) => {
this.width = value;
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Center }) {
Column() {
Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Center }) {
// 通过flexGrow和flexShink属性,将多余的空间全部分配给图片,将不足的控件全部分配给两侧空白区域。
Row().width(150).height(400).backgroundColor('#FFFFFF')
.flexGrow(0).flexShrink(1)
Image($r("app.media.illustrator")).width(400).height(400)
.objectFit(ImageFit.Contain)
.backgroundColor("#66F1CCB8")
.flexGrow(1).flexShrink(0)
Row().width(150).height(400).backgroundColor('#FFFFFF')
.flexGrow(0).flexShrink(1)
}.width(this.width)
}
this.slider()
}.width('100%').height('100%').backgroundColor('#F1F3F5')
}
}
```
## 示例2:
文字和开关的尺寸固定,仅有中间空白区域(Blank组件)随父容器尺寸变化而伸缩。
![zh-cn_image_0000001266042114](figures/zh-cn_image_0000001266042114.gif)
```ts
@Entry
@Component
struct FlexibleCapabilitySample2 {
@State rate: number = 0.8;
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.rate * 100, min: 30, max: 80, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.onChange((value: number) => {
this.rate = value / 100;
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Center }) {
Column() {
Row() {
Text('飞行模式')
.fontSize(16)
.width(135)
.height(22)
.fontWeight(FontWeight.Medium)
.lineHeight(22)
Blank() // 通过Blank组件实现拉伸能力
Toggle({ type: ToggleType.Switch })
.width(36)
.height(20)
}
.height(55)
.borderRadius(12)
.padding({ left: 13, right: 13 })
.backgroundColor('#FFFFFF')
.width(this.rate * 100 + '%')
}
this.slider()
}.width('100%').height('100%').backgroundColor('#F1F3F5')
}
}
```
# 折行能力
折行能力是指容器组件尺寸发生变化,当布局方向尺寸不足以显示完整内容时自动换行。它常用于横竖屏适配或默认设备向平板切换的场景。
折行能力通过使用 **Flex折行布局** (将warp属性设置为FlexWrap.Wrap)实现,当横向布局尺寸不足以完整显示内容元素时,通过折行的方式,将元素显示在下方。
可以访问[Flex组件](../../reference/arkui-ts/ts-container-flex.md),了解Flex组件的详细用法。
## 示例:
父容器中的图片尺寸固定,当父容器尺寸发生变化,其中的内容做自适应换行。
![zh-cn_image_0000001292215677](figures/zh-cn_image_0000001292215677.gif)
```ts
@Entry
@Component
struct WrapCapabilitySample {
@State rate: number = 0.7;
const imageList: Resource [] = [
$r('app.media.flexWrap1'),
$r('app.media.flexWrap2'),
$r('app.media.flexWrap3'),
$r('app.media.flexWrap4'),
$r('app.media.flexWrap5'),
$r('app.media.flexWrap6')
];
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.rate * 100, min: 50, max: 70, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.onChange((value: number) => {
this.rate = value / 100;
})
.position({ x: '20%', y: '87%' })
}
build() {
Flex({ justifyContent: FlexAlign.Center, direction: FlexDirection.Column }) {
Column() {
// 通过Flex组件warp参数实现自适应折行
Flex({
direction: FlexDirection.Row,
alignItems: ItemAlign.Center,
justifyContent: FlexAlign.Center,
wrap: FlexWrap.Wrap
}) {
ForEach(this.imageList, (item) => {
Image(item).width(183).height(138).padding(10)
})
}
.backgroundColor('#FFFFFF')
.padding(20)
.width(this.rate * 100 + '%')
.borderRadius(16)
}
.width('100%')
this.slider()
}.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
}
```
# 自适应布局
针对常见的开发场景,方舟开发框架提炼了七种自适应布局能力,这些布局可以独立使用,也可多种布局叠加使用。
| 自适应布局类别 | 自适应布局能力 | 使用场景 | 实现方式 |
| -------- | -------- | -------- | -------- |
| 自适应拉伸 | [拉伸能力](#拉伸能力) | 容器组件尺寸发生变化时,增加或减小的空间**全部分配**给容器组件内**指定区域**。 | [Flex布局](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-flex-layout.md)的flexGrow和flexShrink属性 |
| | [均分能力](#均分能力) | 容器组件尺寸发生变化时,增加或减小的空间**均匀分配**给容器组件内**所有空白区域**。 | [Row组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-row.md)[Column组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-column.md)[Flex组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-flex.md)的justifyContent属性设置为FlexAlign.SpaceEvenly |
| 自适应缩放 | [占比能力](#占比能力) | 子组件的宽或高**按照预设的比例**,随容器组件发生变化。 | 基于通用属性的两种实现方式:<br/>-&nbsp;将子组件的宽高设置为父组件宽高的百分比<br/>-&nbsp;layoutWeight属性 |
| | [缩放能力](#缩放能力) | 子组件的宽高**按照预设的比例**,随容器组件发生变化,且变化过程中子组件的**宽高比不变**。 | [布局约束](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-layout-constraints.md)的aspectRatio属性 |
| 自适应延伸 | [延伸能力](#延伸能力) | 容器组件内的子组件,按照其**在列表中的先后顺序**,随容器组件尺寸变化显示或隐藏。 | 基于容器组件的两种实现方式:<br/>-&nbsp;通过[List组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md)实现<br/>-&nbsp;通过[Scroll组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-scroll.md)配合[Row组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-row.md)[Column组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-column.md)实现 |
| | [隐藏能力](#隐藏能力) | 容器组件内的子组件,按照其**预设的显示优先级**,随容器组件尺寸变化显示或隐藏。**相同显示优先级的子组件同时显示或隐藏**。 | [布局约束](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-layout-constraints.md)的displayPriority属性 |
| 自适应折行 | [折行能力](#折行能力) | 容器组件尺寸发生变化时,如果布局方向尺寸不足以显示完整内容,**自动换行**。 | [Flex组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-flex.md)的wrap属性设置为FlexWrap.Wrap |
下面我们依次介绍这几种自适应布局能力。
## 拉伸能力
拉伸能力是指容器组件尺寸发生变化时,增加或减小的空间全部分配给容器组件内指定区域。
拉伸能力通常通过[Flex布局](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-flex-layout.md)中的flexGrow和flexShrink属性实现,flexGrow和flexShink属性常与flexBasis属性搭配使用,故将这三个属性放在一起介绍。
| 属性 | 类型 | 默认值 | 描述 |
| -------- | -------- | -------- | -------- |
| flexGrow | number | 0 | 仅当父容器宽度大于所有子组件宽度的总和时,该属性生效。配置了此属性的子组件,按照比例拉伸,分配父容器的多余空间。 |
| flexShrink | number | 1 | 仅当父容器宽度小于所有子组件宽度的总和时,该属性生效。配置了此属性的子组件,按照比例收缩,分配父容器的不足空间。 |
| flexBasis | 'auto'&nbsp;\|&nbsp;[Length](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-types.md#length) | 'auto' | 设置组件在Flex容器中主轴方向上基准尺寸。'auto'意味着使用组件原始的尺寸,不做修改。<br/>flexBasis属性不是必须的,通过width或height也可以达到同样的效果。当flexBasis属性与width或height发生冲突时,以flexBasis属性为准。 |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 开发者期望将父容器的剩余空间全部分配给某空白区域时,也可以通过[Blank组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-blank.md)实现。注意仅当父组件为Row\Column\Flex组件时,Blank组件才会生效。
>
> - 类Web开发范式也是通过flex-grow和flex-shrink实现拉伸能力,同时也支持配置flex-basis,详见[通用样式](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-common-styles.md)。
>
> - 类Web开发范式没有提供blank组件,但可以通过div组件模拟blank组件的行为,如“&lt;div style='flex-grow: 1; flex-shrink: 0; flex-basis: 0'&gt;&lt;/div&gt;”。
**示例1**
本示例中的页面由中间的内容区(包含一张图片)以及两侧的留白区组成,各区域的属性配置如下。
* 中间内容区的宽度设置为400vp,同时将flexGrow属性设置为1,flexShrink属性设置为0。
* 两侧留白区的宽度设置为150vp,同时将flexGrow属性设置为0,flexShrink属性设置为1。
由上可知,父容器的基准尺寸是700vp(150vp+400vp+150vp)。
可以通过拖动底部的滑动条改变父容器的尺寸,查看布局变化。
* 当父容器的尺寸大于700vp时,父容器中多余的空间全部分配给中间内容区。
* 当父容器的尺寸小于700vp时,左右两侧的留白区按照“1:1”的比例收缩(即平均分配父容器的不足空间)。
![zh-cn_image_0000001335796258](figures/zh-cn_image_0000001335796258.gif)
```
@Entry
@Component
struct FlexibleCapabilitySample1 {
@State containerWidth: number = 402
// 底部滑块,可以通过拖拽滑块改变容器尺寸。
@Builder slider() {
Slider({ value: this.containerWidth, min: 402, max: 1000, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.onChange((value: number) => {
this.containerWidth = value;
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Center }) {
Column() {
Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Center }) {
// 通过flexGrow和flexShink属性,将多余的空间全部分配给图片,将不足的控件全部分配给两侧空白区域。
Row().width(150).height(400).backgroundColor('#FFFFFF')
.flexGrow(0).flexShrink(1)
Image($r("app.media.illustrator")).width(400).height(400)
.objectFit(ImageFit.Contain)
.backgroundColor("#66F1CCB8")
.flexGrow(1).flexShrink(0)
Row().width(150).height(400).backgroundColor('#FFFFFF')
.flexGrow(0).flexShrink(1)
}.width(this.containerWidth)
}
this.slider()
}.width('100%').height('100%').backgroundColor('#F1F3F5')
}
}
```
**示例2**
文字和开关的尺寸固定,仅有中间空白区域(Blank组件)随父容器尺寸变化而伸缩。
![zh-cn_image_0000001335316714](figures/zh-cn_image_0000001335316714.gif)
```
@Entry
@Component
struct FlexibleCapabilitySample2 {
@State rate: number = 0.8
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.rate * 100, min: 30, max: 80, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.onChange((value: number) => {
this.rate = value / 100;
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Center }) {
Column() {
Row() {
Text('飞行模式')
.fontSize(16)
.width(135)
.height(22)
.fontWeight(FontWeight.Medium)
.lineHeight(22)
Blank() // 通过Blank组件实现拉伸能力
Toggle({ type: ToggleType.Switch })
.width(36)
.height(20)
}
.height(55)
.borderRadius(12)
.padding({ left: 13, right: 13 })
.backgroundColor('#FFFFFF')
.width(this.rate * 100 + '%')
}
this.slider()
}.width('100%').height('100%').backgroundColor('#F1F3F5')
}
}
```
## 均分能力
均分能力是指容器组件尺寸发生变化时,增加或减小的空间均匀分配给容器组件内所有空白区域。它常用于内容数量固定、均分显示的场景,比如工具栏、底部菜单栏等。
均分能力可以通过将[Row组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-row.md)[Column组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-column.md)[Flex组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-flex.md)的justifyContent属性设置为FlexAlign.SpaceEvenly实现,即子元素在父容器主轴方向等间距布局,相邻元素之间的间距、第一个元素与行首的间距、最后一个元素到行尾的间距都完全一样。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 均分能力还可以通过其它方式实现,如使用[Grid网格组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-grid.md)或在每个组件间添加Blank组件等。
>
> - 类Web开发范式中,通过将[div组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-container-div.md)的justify-content属性设置为space-evenly来实现均分布局。
**示例:**
父容器尺寸变化过程中,图标及文字的尺寸不变,图标间的间距及图标离左右边缘的距离同时均等改变。
![zh-cn_image_0000001335477142](figures/zh-cn_image_0000001335477142.gif)
```
@Entry
@Component
struct EquipartitionCapabilitySample {
const list: number [] = [0, 1, 2, 3]
@State rate: number = 0.6
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.rate * 100, min: 30, max: 60, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.onChange((value: number) => {
this.rate = value / 100
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Column() {
// 均匀分配父容器主轴方向的剩余空间
Flex({ justifyContent: FlexAlign.SpaceEvenly }) {
ForEach(this.list, (item) => {
Column() {
Image($r("app.media.icon")).width(48).height(48).margin({ top: 8 })
Text('App name')
.width(64)
.height(30)
.lineHeight(15)
.fontSize(12)
.textAlign(TextAlign.Center)
.margin({ top: 8 })
.padding({ bottom: 15 })
}.width(80).height(102)
})
}
// 均匀分配父容器主轴方向的剩余空间
Flex({ justifyContent: FlexAlign.SpaceEvenly }) {
ForEach(this.list, (item) => {
Column() {
Image($r("app.media.icon")).width(48).height(48).margin({ top: 8 })
Text('App name')
.width(64)
.height(30)
.lineHeight(15)
.fontSize(12)
.textAlign(TextAlign.Center)
.margin({ top: 8 })
.padding({ bottom: 15 })
}.width(80).height(102)
})
}
}
.width(this.rate * 100 + '%')
.height(222)
.padding({ top: 16 })
.backgroundColor('#FFFFFF')
.borderRadius(16)
this.slider()
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
}
```
## 占比能力
占比能力是指子组件的宽高按照预设的比例,随父容器组件发生变化。
占比能力通常有两种实现方式:
- 将子组件的宽高设置为父组件宽高的百分比,详见[尺寸设置](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-size.md)[长度类型](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-types.md#length)
- 通过layoutWeight属性配置互为兄弟关系的组件在父容器主轴方向的布局权重,详见[尺寸设置](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-size.md)
- 当父容器尺寸确定时,其子组件按照开发者配置的权重比例分配父容器中主轴方向的空间。
- 仅当父容器是Row、Colomn或者Flex时,layoutWeight属性才会生效。
- 设置layoutWeight属性后,组件本身的尺寸会失效。比如同时设置了.width('40%')和.layoutWeight(1),那么只有.layoutWeight(1)会生效。
layoutWeight存在使用限制,所以实际使用过程中大多通过将子组件宽高设置为父组件的百分比来实现占比能力。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 占比能力在实际开发中使用的非常广泛,可以通过很多不同的方式实现占比能力,如还可以通过[Grid组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-grid.md)的columnsTemplate属性设置网格容器中列的数量及其宽度比例,或通过配置子组件在栅格(本章后文将详细介绍栅格系统)中占据不同的列数来实现占比能力。本小节仅介绍最基础和常用的实现方式,局限性较大或比非常小众的实现方式,本文不做展开介绍。
>
> - 类Web开发范式同样支持以百分比的形式设置组件的宽高,详见[通用样式](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-common-styles.md)中关于width和height的介绍以及[长度类型介绍](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-appendix-types.md#%E9%95%BF%E5%BA%A6%E7%B1%BB%E5%9E%8B)。
>
> - 与声明式开发范式中的layoutWeight属性类似,类Web开发范式提供了[flex-weight样式](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-common-atomic-layout.md#%E5%8D%A0%E6%AF%94%E8%83%BD%E5%8A%9B)用于配置互为兄弟关系的组件在父容器主轴方向的布局权重。
**示例:**
简单的播放控制栏,其中“上一首”、“播放/暂停”、“下一首”的layoutWeight属性都设置为1,因此它们按照“1:1:1”的比例均分父容器主轴方向的空间。
将三个按钮的.layoutWeight(1)分别替换为.width('33%')、.width('34%')、.width('33%'),也可以实现与当前同样的显示效果。
![zh-cn_image_0000001385757965](figures/zh-cn_image_0000001385757965.gif)
```
@Entry
@Component
struct ProportionCapabilitySample {
@State rate: number = 0.5
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: 100, min: 25, max: 50, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.height(50)
.onChange((value: number) => {
this.rate = value / 100
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Column() {
Row() {
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Image($r("app.media.down"))
.width(48)
.height(48)
}
.height(96)
.layoutWeight(1) // 设置子组件在父容器主轴方向的布局权重
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Image($r("app.media.pause"))
.width(48)
.height(48)
}
.height(96)
.layoutWeight(1) // 设置子组件在父容器主轴方向的布局权重
.backgroundColor('#66F1CCB8')
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Image($r("app.media.next"))
.width(48)
.height(48)
}
.height(96)
.layoutWeight(1) // 设置子组件在父容器主轴方向的布局权重
}
.width(this.rate * 100 + '%')
.height(96)
.borderRadius(16)
.backgroundColor('#FFFFFF')
}
this.slider()
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
}
```
## 缩放能力
缩放能力是指子组件的宽高按照预设的比例,随容器组件发生变化,且变化过程中子组件的宽高比不变。
缩放能力通过使用百分比布局配合**固定宽高比**(aspectRatio属性)实现当容器尺寸发生变化时,内容自适应调整。
可以访问[布局约束](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-layout-constraints.md),了解aspectRatio属性的详细信息。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 类Web开发范式同样提供了[aspect-ratio样式](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-common-atomic-layout.md#%E5%9B%BA%E5%AE%9A%E6%AF%94%E4%BE%8B),用于固定组件的宽高比。
**示例:**
为方便查看效果,示例中特意给Column组件加了边框。可以看到Column组件随着其Flex父组件尺寸变化而缩放的过程中,始终保持预设的宽高比,其中的图片也始终正常显示。
![zh-cn_image_0000001335640862](figures/zh-cn_image_0000001335640862.gif)
```
@Entry
@Component
struct ScaleCapabilitySample {
@State sliderWidth: number = 400
@State sliderHeight: number = 400
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.sliderWidth, min: 100, max: 400, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.height(50)
.onChange((value: number) => {
this.sliderWidth = value;
})
.position({ x: '20%', y: '80%' })
Slider({ value: this.sliderHeight, min: 100, max: 400, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.height(50)
.onChange((value: number) => {
this.sliderHeight = value
})
.position({ x: '20%', y: '87%' })
}
build() {
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Column() {
Image($r("app.media.illustrator")).width('100%').height('100%')
}
.aspectRatio(1) // 固定宽高比
.border({ width: 2, color: "#66F1CCB8"}) // 边框,仅用于展示效果
}
.backgroundColor("#FFFFFF")
.height(this.sliderWidth)
.width(this.sliderHeight)
this.slider()
}.width('100%')
.height('100%')
.backgroundColor("#F1F3F5")
}
}
```
## 延伸能力
延伸能力是指容器组件内的子组件,按照其在列表中的先后顺序,随容器组件尺寸变化显示或隐藏。它可以根据显示区域的尺寸,显示不同数量的元素。
延伸能力通常有两种实现方式:
- 通过[List组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md)实现。
- 通过[Scroll组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-scroll.md)配合[Row组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-row.md)[Column组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-column.md)实现。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - List、Row或Column组件中子节点的在页面显示时就已经全部完成了布局计算及渲染,只不过受限于父容器尺寸,用户只能看到一部分。随着父容器尺寸增大,用户可以看到的子节点数目也相应的增加。用户还可以通过手指滑动触发列表滑动,查看被隐藏的子节点。
>
> - 类Web开发范式同样可以使用[list组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-container-list.md)实现延伸能力。
>
> - 类Web开发范式没有提供scroll组件,但可以将[div组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-container-div.md)的overflow样式设置为scroll(即div组件主轴方向上子元素的尺寸超过div组件本身的尺寸时进行滚动显示)来模拟scroll组件的行为。
**示例:**
当父容器的尺寸发生改变时,页面中显示的图标数量随之发生改变。
分别通过List组件实现及通过Scroll组件配合Row组件实现。
![zh-cn_image_0000001335641246](figures/zh-cn_image_0000001335641246.gif)
(1)通过List组件实现。
```
@Entry
@Component
struct ExtensionCapabilitySample1 {
@State rate: number = 0.60
const appList: number [] = [0, 1, 2, 3, 4, 5, 6, 7]
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.rate * 100, min: 8, max: 60, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.height(50)
.onChange((value: number) => {
this.rate = value / 100
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Row({ space: 10 }) {
// 通过List组件实现隐藏能力
List({ space: 10 }) {
ForEach(this.appList, (item) => {
ListItem() {
Column() {
Image($r("app.media.icon")).width(48).height(48).margin({ top: 8 })
Text('App name')
.width(64)
.height(30)
.lineHeight(15)
.fontSize(12)
.textAlign(TextAlign.Center)
.margin({ top: 8 })
.padding({ bottom: 15 })
}.width(80).height(102)
}.width(80).height(102)
})
}
.padding({ top: 16, left: 10 })
.listDirection(Axis.Horizontal)
.width('100%')
.height(118)
.borderRadius(16)
.backgroundColor(Color.White)
}
.width(this.rate * 100 + '%')
this.slider()
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
}
```
(2)通过Scroll组件配合Row组件实现。
```
@Entry
@Component
struct ExtensionCapabilitySample2 {
private scroller: Scroller = new Scroller()
@State rate: number = 0.60
@State appList: number [] = [0, 1, 2, 3, 4, 5, 6, 7]
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.rate * 100, min: 8, max: 60, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.height(50)
.onChange((value: number) => {
this.rate = value / 100;
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
// 通过Scroll和Row组件实现隐藏能力
Scroll(this.scroller) {
Row({ space: 10 }) {
ForEach(this.appList, () => {
Column() {
Image($r("app.media.icon")).width(48).height(48).margin({ top: 8 })
Text('App name')
.width(64)
.height(30)
.lineHeight(15)
.fontSize(12)
.textAlign(TextAlign.Center)
.margin({ top: 8 })
.padding({ bottom: 15 })
}.width(80).height(102)
})
}
.padding({ top: 16, left: 10 })
.height(118)
.borderRadius(16)
.backgroundColor(Color.White)
}
.scrollable(ScrollDirection.Horizontal)
.width(this.rate * 100 + '%')
this.slider()
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
}
```
## 隐藏能力
隐藏能力是指容器组件内的子组件,按照其预设的显示优先级,随容器组件尺寸变化显示或隐藏,其中相同显示优先级的子组件同时显示或隐藏。它是一种比较高级的布局方式,常用于分辨率变化较大,且不同分辨率下显示内容有所差异的场景。主要思想是通过增加或减少显示内容,来保持最佳的显示效果。
隐藏能力通过设置**布局优先级**(displayPriority属性)来控制显隐,当布局主轴方向剩余尺寸不足以满足全部元素时,按照布局优先级大小,从小到大依次隐藏,直到容器能够完整显示剩余元素。具有相同布局优先级的元素将同时显示或者隐藏。
可以访问[布局约束](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-layout-constraints.md),了解displayPriority属性的详细信息。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 类Web开发范式同样支持[display-index样式](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-common-atomic-layout.md#%E9%9A%90%E8%97%8F%E8%83%BD%E5%8A%9B),用于设置布局优先级。
**示例:**
父容器尺寸发生变化时,其子元素按照预设的优先级显示或隐藏。
![zh-cn_image_0000001335485154](figures/zh-cn_image_0000001335485154.gif)
```
@Entry
@Component
struct HiddenCapabilitySample {
@State rate: number = 0.45
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.rate * 100, min: 10, max: 45, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.height(50)
.onChange((value: number) => {
this.rate = value / 100
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ direction: FlexDirection.Column,
justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Center }) {
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Image($r("app.media.favorite"))
.width(48)
.height(48)
.objectFit(ImageFit.Contain)
.margin({ left: 12, right: 12 })
.displayPriority(1) // 布局优先级
Image($r("app.media.down"))
.width(48)
.height(48)
.objectFit(ImageFit.Contain)
.margin({ left: 12, right: 12 })
.displayPriority(2) // 布局优先级
Image($r("app.media.pause"))
.width(48)
.height(48)
.objectFit(ImageFit.Contain)
.margin({ left: 12, right: 12 })
.displayPriority(3) // 布局优先级
Image($r("app.media.next"))
.width(48)
.height(48)
.objectFit(ImageFit.Contain)
.margin({ left: 12, right: 12 })
.displayPriority(2) // 布局优先级
Image($r("app.media.list"))
.width(48)
.height(48)
.objectFit(ImageFit.Contain)
.margin({ left: 12, right: 12 })
.displayPriority(1) // 布局优先级
}
.width(this.rate * 100 + '%')
.height(96)
.borderRadius(16)
.backgroundColor('#FFFFFF')
this.slider()
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
}
```
## 折行能力
折行能力是指容器组件尺寸发生变化,当布局方向尺寸不足以显示完整内容时自动换行。它常用于横竖屏适配或默认设备向平板切换的场景。
折行能力通过使用 **Flex折行布局** (将wrap属性设置为FlexWrap.Wrap)实现,当横向布局尺寸不足以完整显示内容元素时,通过折行的方式,将元素显示在下方。
可以访问[Flex组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-flex.md),了解Flex组件的详细用法。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 类Web开发范式通过将[div组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-container-div.md)的flex-warp样式设置为wrap来使用折行能力。
**示例:**
父容器中的图片尺寸固定,当父容器尺寸发生变化,其中的内容做自适应换行。
![zh-cn_image_0000001385645821](figures/zh-cn_image_0000001385645821.gif)
```
@Entry
@Component
struct WrapCapabilitySample {
@State rate: number = 0.7
const imageList: Resource [] = [
$r('app.media.flexWrap1'),
$r('app.media.flexWrap2'),
$r('app.media.flexWrap3'),
$r('app.media.flexWrap4'),
$r('app.media.flexWrap5'),
$r('app.media.flexWrap6')
]
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.rate * 100, min: 50, max: 70, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.onChange((value: number) => {
this.rate = value / 100
})
.position({ x: '20%', y: '87%' })
}
build() {
Flex({ justifyContent: FlexAlign.Center, direction: FlexDirection.Column }) {
Column() {
// 通过Flex组件warp参数实现自适应折行
Flex({
direction: FlexDirection.Row,
alignItems: ItemAlign.Center,
justifyContent: FlexAlign.Center,
wrap: FlexWrap.Wrap
}) {
ForEach(this.imageList, (item) => {
Image(item).width(183).height(138).padding(10)
})
}
.backgroundColor('#FFFFFF')
.padding(20)
.width(this.rate * 100 + '%')
.borderRadius(16)
}
.width('100%')
this.slider()
}.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
}
```
# 应用市场首页
本小节将以应用市场首页为例,介绍如何使用自适应布局能力和响应式布局能力适配不同尺寸窗口。本示例已经在[OpenHarmony应用示例](https://gitee.com/openharmony/applications_app_samples/tree/master/MultiDeviceAppDev/AppMarket)中开源,读者可以根据需要自行下载源码并运行及查看效果。
## 页面设计
一个典型的应用市场首页的UX设计如下所示。
| sm | md | lg |
| -------- | -------- | -------- |
| ![zh-cn_image_0000001328579522](figures/zh-cn_image_0000001328579522.png) | ![zh-cn_image_0000001328259918](figures/zh-cn_image_0000001328259918.png) | ![zh-cn_image_0000001379179861](figures/zh-cn_image_0000001379179861.png) |
观察应用市场首页的页面设计,不同断点下的页面设计有较多相似的地方。
据此,我们可以将页面分拆为多个组成部分。
1. 底部/侧边导航栏
2. 标题栏与搜索栏
3. 运营横幅
4. 快捷入口
5. 精品应用
| sm | md | lg |
| -------- | -------- | -------- |
| ![zh-cn_image_0000001379299533](figures/zh-cn_image_0000001379299533.png) | ![zh-cn_image_0000001328259922](figures/zh-cn_image_0000001328259922.png) | ![zh-cn_image_0000001379179865](figures/zh-cn_image_0000001379179865.png) |
接下来我们逐一分析各部分的实现。
## 底部/侧边导航栏
在sm和md断点下,导航栏在底部;在lg断点下,导航栏在左侧。可以通过[Tab组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-tabs.md)的barPosition和vertical属性控制TabBar的位置,同时还可以通过barWidth和barHeight属性控制TabBar的尺寸。
```
@Entry
@Component
struct Index {
...
build() {
// 设置TabBar在主轴方向起始或结尾位置
Tabs({ barPosition: this.currentBreakpoint === "lg" ? BarPosition.Start : BarPosition.End }) {
// 首页
TabContent() {
Home()
}.tabBar(this.tabItem1)
TabContent() {}.tabBar(this.tabItem2)
TabContent() {}.tabBar(this.tabItem3)
TabContent() {}.tabBar(this.tabItem4)
TabContent() {}.tabBar(this.tabItem5)
}
.backgroundColor('#F1F3F5')
.barMode(BarMode.Fixed)
.barWidth(this.currentBreakpoint === "lg" ? 96 : '100%')
.barHeight(this.currentBreakpoint === "lg" ? '60%' : 56)
// 设置TabBar放置在水平或垂直方向
.vertical(this.currentBreakpoint === "lg")
}
}
```
另外在sm及lg断点下,TabBar中各个Item的图标和文字是按照垂直方向排布的,在md断点下,TabBar中各个Item的图标和文字是按照水平方向排布的。
```
@Component
export default struct TabBarItem {
...
build() {
if (this.currentBreakpoint !== 'md' ) {
// sm及lg断点下,tabBarItem中的图标和文字垂直排布
Column() {
...
}.justifyContent(FlexAlign.Center).height('100%').width('100%')
} else {
// md断点下,tabBarItem中的图标和文字水平排布
Row() {
....
}.justifyContent(FlexAlign.Center).height('100%').width('100%')
}
}
}
```
## 标题栏与搜索栏
标题栏和搜索栏,在sm和md断点下分两行显示,在lg断点下单行显示,可以通过栅格实现。在sm和md断点下,标题栏和搜索栏占满12列,此时会自动换行显示。在lg断点下,标题栏占8列而搜索栏占4列,此时标题栏和搜索栏在同一行中显示。
| | sm/md | lg |
| -------- | -------- | -------- |
| 效果图 | ![zh-cn_image_0000001379385785](figures/zh-cn_image_0000001379385785.png) | ![zh-cn_image_0000001379464977](figures/zh-cn_image_0000001379464977.jpg) |
| 栅格布局图 | ![zh-cn_image_0000001379464981](figures/zh-cn_image_0000001379464981.png) | ![zh-cn_image_0000001328745102](figures/zh-cn_image_0000001328745102.png) |
```
@Component
export default struct IndexHeader {
...
build() {
// 借助栅格实现标题栏和搜索栏在不同断点下的不同布局效果。
GridRow() {
GridCol({ span: { xs: 12, lg: 8 } }) {
this.titleBar()
}
GridCol({ span: { xs: 12, lg: 4 } }) {
this.searchBar()
}
}
.width('100%')
}
}
```
## 运营横幅
不同断点下的运营横幅,sm断点下显示一张图片,md断点下显示两张图片,lg断点下显示三张图片。可以通过[Swiper组件的displayCount属性](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-swiper.md)实现目标效果。
```
@Component
export default struct IndexSwiper {
...
@Builder swiperItem(imageSrc) {
Image(imageSrc)
.width('100%')
.aspectRatio(2.5)
.objectFit(ImageFit.Fill)
}
build() {
Swiper() {
this.swiperItem($r('app.media.ic_public_swiper1'))
this.swiperItem($r('app.media.ic_public_swiper2'))
this.swiperItem($r('app.media.ic_public_swiper3'))
...
}
.autoPlay(true)
.indicator(false)
.itemSpace(10)
// 配置不同断点下运行横幅中展示的图片数量
.displayCount(this.currentBreakpoint === 'sm' ? 1 : (this.currentBreakpoint === 'md' ? 2 : 3))
.width('100%')
.padding({ left: 12, right: 12, bottom: 16, top: 16 })
}
}
```
## 快捷入口
在不同的断点下,快捷入口的5个图标始终均匀排布,这是典型的均分能力使用场景。
```
@Component
@Component
export default struct IndexEntrance {
build() {
// 将justifyContent参数配置为FlexAlign.SpaceEvenly实现均分布局
Row() {
ForEach(entranceIcons, (icon: AllIcons) => {
// 各快捷入口的图标及名称
Column() { ... }
})
}
.width('100%')
.height(64)
.justifyContent(FlexAlign.SpaceEvenly)
.padding({ left: 12, right: 12 })
}
}
```
## 精品应用
随着可用显示区域的增加,精品应用中显示的图标数量也不断增加,这是典型的延伸能力使用场景。精品游戏的实现与精品应用类似,不再展开分析。
```
@Component
@Component
export default struct IndexApps {
...
build() {
Column() {
this.appListHeader()
// 借助List组件能力,实现延伸能力场景
List({ space: this.currentBreakpoint === 'lg' ? 44 : 20}) {
LazyForEach(new MyAppSource(this.apps), app => {
ListItem() {
// 每个应用的图标、名称及安装按钮
this.appListItem(app)
}
}, app => app.id)
}
.width('100%')
.height(this.currentBreakpoint === 'lg' ? 140 : 120)
.listDirection(Axis.Horizontal)
}
.width('100%')
.height(this.currentBreakpoint === 'lg' ? 188 : 164)
.padding({ bottom: 8, left: 12, right: 12 })
}
}
```
## 运行效果
将上述各页面主要部分组合在一起后,即可完成整体页面开发。
```
@Component
struct IndexContent {
...
build() {
List() {
// 运营横幅
ListItem() {
IndexSwiper()
}
// 快捷入口
ListItem() {
IndexEntrance()
}
// 精品应用
ListItem() {
IndexApps({ title: $r('app.string.boutique_application'), apps: appList })
}
// 精品游戏
ListItem() {
IndexApps({ title: $r('app.string.boutique_game'), apps: gameList })
}
}
.width("100%")
}
}
@Component
export default struct Home {
...
build() {
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Start }) {
// 标题栏和搜索栏
IndexHeader()
// 运营横幅、快捷入口、精品应用、精品游戏等
IndexContent()
}
.height('100%')
.backgroundColor("#F1F3F5")
}
}
```
本页面的实际运行效果如下图所示。
| sm | md | lg |
| -------- | -------- | -------- |
| ![zh-cn_image_0000001334345550](figures/zh-cn_image_0000001334345550.jpg) | ![zh-cn_image_0000001385105477](figures/zh-cn_image_0000001385105477.jpg) | ![zh-cn_image_0000001384985569](figures/zh-cn_image_0000001384985569.jpg) |
<!--no_check-->
\ No newline at end of file
# 应用架构设计
- **[应用导航结构设计要求](navigation-design.md)**
- **[应用页面结构设计](page-design.md)**
\ No newline at end of file
# 案例应用
本章从OpenHarmony预置的系统应用中,选择短信应用作为典型的案例,从页面开发和工程结构的角度,介绍"一多"的具体实践。OpenHarmony的产品形态在不断丰富中,当前主要有默认设备和平板两种产品形态,本章的具体实践也将围绕这两种产品形态展开。
## 概览
[短信](https://gitee.com/openharmony/applications_mms/tree/master)是OpenHarmony中预置的系统应用,主要包含信息查看、发送短信、接收短信、短信送达报告、删除短信等功能。在不同类型设备上,短信应用的功能完全相同,故短信应用适合使用[部署模型A](introduction.md#部署模型)(即:不同类型的设备上安装运行相同的HAP包或HAP包组合)。
本案例中,在会话详情页面利用[方舟开发框架](introduction.md#方舟开发框架)提供的“一多”能力,用一套代码同时适配默认设备和平板。
### 工程结构
短信应用的工程结构如下图所示,当前该应用的功能较少,所以直接使用了DevEco Studio创建出的默认工程结构。具体采用何种形式的工程结构,并不影响应用的开发。但是使用推荐的工程结构,目录结构更清晰,拓展性也更好。
短信应用UI相关的逻辑集中在views和pages两个目录,分别存放公共组件及页面。当前短信应用主要包含如下页面:
- 信息列表页面:首页,展示信息列表。
- 通知信息列表页面:将通知类信息集中在一起展示,与信息列表页面类似。
- 会话详情页面:展示与某联系人的所有信息往来。
- 报告详情页面:信息发送报告的详情页面。
- 设置页面:消息设置页面,如是否展示送达报告等。
```
/Mms/
├── doc # 资料
├── entry
│ └── src
│ └── main
│ ├── resources # 资源配置文件存放目录
│ ├── config.json # 全局配置文件
│ └── ets # ets代码目录
│ ├── ServiceAbility # 后台常驻服务
│ └── default # 业务代码目录
│ ├── data # 自定义数据类型
│ ├── model # 对接数据库
│ ├── pages # 所有页面
│ │ ├── conversation # 会话详情页面
│ │ ├── conversationlist # 信息列表页面
│ │ ├── index # 初始页面
│ │ ├── info_msg # 通知信息列表页面
│ │ ├── query_report # 报告详情页面
│ │ └── settings # 设置页面
│ ├── service # 业务逻辑
│ ├── utils # 工具类
│ ├── views # 自定义组件
│ └── app.ets # 应用生命周期
├── signs # 签名
└── LICENSE
```
短信应用在开发阶段,采用了一层工程结构。由于功能较为简单,所以并没有规划共用的feature和common目录,仅采用了一层product目录。
- 业务形态层(product)
该目录采用IDE工程默认创建的entry目录,开发者可根据需要在创建Module时自行更改该目录名。不同产品形态,编译出相同的短信HAP包。
## 会话详情页面
### 页面结构
| 默认设备 | 平板 |
| -------- | -------- |
| ![overview_phone](figures/overview_phone.png) | ![overview_tablet](figures/overview_tablet.png) |
会话详情页面在默认设备和平板上的样式如上图所示,会话详情页面可以划分为三个部分:
| 页面组成 | 介绍 |
| -------- | -------- |
| 顶部标题栏 | ![zh-cn_image_0000001335699774](figures/zh-cn_image_0000001335699774.jpg) |
| 信息列表 | ![zh-cn_image_0000001386060209](figures/zh-cn_image_0000001386060209.jpg) |
| 底部输入栏 | ![zh-cn_image_0000001386179873](figures/zh-cn_image_0000001386179873.jpg) |
接下来我们详细介绍各部分的实现。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 为了方便理解,我们对会话详情页面做了一定的精简,本小节仅介绍会话详情页面最基础的实现。
### 顶部标题栏
| 默认设备 | 平板 |
| -------- | -------- |
| ![zh-cn_image_0000001335539986](figures/zh-cn_image_0000001335539986.jpg) | ![top_title_tablet](figures/top_title_tablet.png) |
顶部标题栏是一个简单的行布局,包含返回图标、联系人头像、联系人姓名和号码、拨号图标、设置图标共5个元素。其中,联系人姓名和号码以列布局的形式放在一起。
在默认设备和平板上,顶部标题栏的组件结构是相同的,仅联系人姓名和号码与拨号图标的间距不同。回顾方舟开发框架一多能力介绍,这个场景可以借助Blank组件使用拉伸能力。
我们先实现联系人姓名和号码,用Flex组件作为父容器,其包含两个Text子组件,分别用于存放联系人姓名和号码。Flex组件的属性设置如下:
- direction: FlexDirection.Column:子组件在Flex容器上以列的方式排布,即主轴是垂直方向。
- justifyContent: FlexAlign.Center:子组件在Flex容器主轴(垂直方向)上居中对齐。
- alignItems: ItemAlign.Start:子组件在Flex容器交叉轴(水平方向)上首部对齐。
可以查看[Flex组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-flex.md)[Text组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-text.md)了解这两个组件各个属性的含义及详细用法。
| 默认设备 | 平板 |
| -------- | -------- |
| ![contact_details_phone](figures/contact_details_phone.png) | ![contact_details_tablet](figures/contact_details_tablet.png) |
```
@Component
struct TopArea {
build() {
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Start}) {
Text('张三').fontSize(16).fontColor("#182431")
Text('+123 4567 8901').fontSize(14).fontColor("#66182431")
}
}
}
```
接下来我们通过width属性和height属性设置四个图标的宽高(详见[尺寸设置](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-size.md)),并将它们与联系人姓名和电话以及Blank组件一起放到Flex父容器中。为了便于查看效果,对顶部标题栏设置了淡蓝色的背景色。
| 默认设备 | 平板 |
| -------- | -------- |
| ![top_title_blank_phone](figures/top_title_blank_phone.png) | ![top_title_blank_tablet](figures/top_title_blank_tablet.png) |
```
@Component
struct TopArea {
build() {
Flex({ alignItems: ItemAlign.Center }) {
Image($r('app.media.back'))
.width(24)
.height(24)
Image($r('app.media.contact'))
.width(40)
.height(40)
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Start}) {
Text('张三').fontSize(16).fontColor("#182431")
Text('+123 4567 8901').fontSize(14).fontColor("#66182431")
}
Blank() // 拉伸能力
Image($r("app.media.call"))
.width(24)
.height(24)
Image($r('app.media.dots'))
.width(24)
.height(24)
}
.width('100%')
.height(56)
.backgroundColor('#87CEFA') // 顶部标题栏背景色,仅用于开发测试
}
}
```
当前标题栏中子组件的布局同预期还有些差异,接下来通过margin属性,设置各个元素的左右间距(详见[尺寸设置](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-size.md))。如下图所示,最终顶部工具栏在默认设备和平板上都可以达到预期显示效果。
| 默认设备 | 平板 |
| -------- | -------- |
| ![top_title_done_phone](figures/top_title_done_phone.png) | ![top_title_done_tablet](figures/top_title_done_tablet.png) |
```
@Component
struct TopArea {
build() {
Flex({ alignItems: ItemAlign.Center }) {
Image($r('app.media.back'))
.width(24)
.height(24)
.margin({ left:24 }) // 设置间距
Image($r('app.media.contact'))
.width(40)
.height(40)
.margin({ left:16, right:16 }) // 设置间距
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Start}) {
Text('张三').fontSize(16).fontColor("#182431")
Text('+123 4567 8901').fontSize(14).fontColor("#66182431")
}
Blank()
Image($r("app.media.call"))
.width(24)
.height(24)
Image($r('app.media.dots'))
.width(24)
.height(24)
.margin({ left:16, right:24 }) // 设置间距
}
.width('100%')
.height(56)
.backgroundColor('#87CEFA') // 顶部标题栏背景色,仅用于开发测试
}
}
```
### 底部输入栏
有了顶部工具栏的开发经验,可以发现底部输入栏的结构更为简单,它同样以Flex组件作为父容器,同时包含文本输入框(请访问[文本输入组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-textarea.md)查看详细介绍)和消息发送图标两个子节点。
![zh-cn_image_0000001335380378](figures/zh-cn_image_0000001335380378.jpg)
为了便于查看的效果,我们同样给底部输入栏设置了淡蓝色到背景色。注意这里有一个特殊的地方,我们给TextArea设置了flexGrow(1)属性。flexGrow属性仅在父组件是Flex组件时生效,表示Flex容器的剩余空间分配给此属性所在的组件的比例,flexGrow(1)表示父容器的剩余空间全部分配给此组件,详见[Flex布局](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-flex-layout.md)
| 默认设备 | 平板 |
| -------- | -------- |
| ![bottom_input_phone](figures/bottom_input_phone.png) | ![bottom_input_tablet](figures/bottom_input_tablet.png) |
```
@Component
struct BottomArea {
build() {
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
TextArea({ placeholder:'短信' })
.placeholderColor("#99000000")
.caretColor("#007DFF")
.backgroundColor("#F1F3F5")
.borderRadius(20)
.height(40)
.flexGrow(1) // 将父容器的剩余空间全部分配给此组件
Image($r("app.media.send"))
.height(36)
.width(36)
.opacity(0.4)
.margin({ left:12 })
}
.height(72)
.width('100%')
.padding({ left:24, right:24, bottom:8, top:8 })
.backgroundColor('#87CEFA') // 底部输入栏背景色,仅用于开发测试
}
}
```
### 信息列表
观察信息列表区域,可以发现它是由一个个消息气泡组成的,另外消息气泡在默认设备和平板上的布局有差异。本小节将围绕如下两个主题介绍如何实现消息列表。
- 如何实现自定义消息气泡组件。
- 如何在默认设备和平板上自适应布局。
| 默认设备 | 平板 |
| -------- | -------- |
| ![zh-cn_image_0000001386180233](figures/zh-cn_image_0000001386180233.jpg) | ![message_list_tablet](figures/message_list_tablet.png) |
**消息气泡**
先做一个最简单的消息气泡,通过borderRadius属性可以设置边框的圆角半径(详见[边框设置](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-border.md))。
| 默认设备 | 平板 |
| -------- | -------- |
| ![message_bubble_basic_phone](figures/message_bubble_basic_phone.png) | ![message_bubble_basic_tablet](figures/message_bubble_basic_tablet.png) |
```
@Component
struct MessageBubble {
private content: string = "OpenHarmony"
build() {
Column() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) {
Text(this.content)
.fontSize(16)
.lineHeight(21)
.padding({ left: 12, right: 12, top: 8, bottom: 8 })
.backgroundColor("#C0EBDF")
.borderRadius(24)
.fontColor("#182431")
}.width('100%')
}
.margin({left: 24, right: 24 })
.backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试
}
}
```
注意这个简单的消息气泡,左上角(或右上角)的样式,与实际期望不符。我们先修改发送消息右上角的样式,接收消息左上角的实现与之类似。
[Stack组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-stack.md)是一个堆叠容器,其子组件按照轴方向依次堆叠,后一个子组件覆盖前一个子组件。通过其alignContent接口,可以设置子组件在容器内的对齐方式,如alignContent: Alignment.TopStart代表子组件从左上角对齐。
| 默认设备 | 平板 |
| -------- | -------- |
| ![message_bubble_radius_phone](figures/message_bubble_radius_phone.png) | ![message_bubble_radius_tablet](figures/message_bubble_radius_tablet.png) |
```
@Component
struct MessageBubble {
private content: string = "OpenHarmony"
private time: string = "今天 上午 10:35"
build() {
Column() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) {
Stack({ alignContent: Alignment.TopEnd }) { // 在左上角堆叠一个小色块
Column()
.backgroundColor("#C0EBDF")
.borderRadius(4)
.width(24)
.height(24)
Text(this.content)
.fontSize(16)
.lineHeight(21)
.padding({ left: 12, right: 12, top: 8, bottom: 8 })
.backgroundColor("#C0EBDF")
.borderRadius(24)
.fontColor("#182431")
}
}.width('100%')
}
.margin({left: 24, right: 24 })
.backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试
}
}
```
接下来我们在消息气泡下方加上时间显示,如下图所示,一个消息气泡自定义组件就基本完成了。
| 默认设备 | 平板 |
| -------- | -------- |
| ![message_bubble_recv_phone](figures/message_bubble_recv_phone.png) | ![message_bubble_recv_tablet](figures/message_bubble_recv_tablet.png) |
```
@Component
struct MessageBubble {
private content: string = "OpenHarmony"
private time: string = "上午 10:35"
build() {
Column() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) {
Stack({ alignContent: Alignment.TopEnd }) {
Column()
.backgroundColor("#C0EBDF")
.borderRadius(4)
.width(24)
.height(24)
Text(this.content)
.fontSize(16)
.lineHeight(21)
.padding({ left: 12, right: 12, top: 8, bottom: 8 })
.backgroundColor("#C0EBDF")
.borderRadius(24)
.fontColor("#182431")
}
}.width('100%')
// 在消息气泡底部增加时间显示
Flex({ alignItems: ItemAlign.Center, direction: FlexDirection.Row,
justifyContent: FlexAlign.End}) {
Text(this.time)
.textAlign(TextAlign.Start)
.fontSize(10)
.lineHeight(13)
.fontColor("#99182431")
}.width('100%').margin({ left: 12, right: 0 })
}
.margin({left: 24, right: 24 })
.backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试
}
}
```
发送出的消息和接收到的消息的消息气泡结构基本一致,可以通过增加一个标志位,让两种消息共用MessageBubble这个自定义组件,代码如下所示。将这个标志位设置true,可以查看接收消息的效果。
| 默认设备 | 平板 |
| -------- | -------- |
| ![message_bubble_send_phone](figures/message_bubble_send_phone.png) | ![message_bubble_send_tablet](figures/message_bubble_send_tablet.png) |
```
@Component
struct MessageBubble {
private isReceived:boolean = false // 通过标志位,判断是发送or接收场景,进而使用不同的样式
private content:string = "OpenHarmony"
private time:string = "今天 10:00"
build() {
Column() {
Flex({ justifyContent:this.isReceived? FlexAlign.Start: FlexAlign.End,
alignItems: ItemAlign.Center }) {
Stack({ alignContent:this.isReceived? Alignment.TopStart: Alignment.TopEnd }) {
Column()
.backgroundColor(this.isReceived?"#FFFFFF":"#C0EBDF")
.borderRadius(4)
.width(24)
.height(24)
Text(this.content)
.fontSize(16)
.lineHeight(21)
.padding({ left:12, right:12, top:8, bottom:8 })
.backgroundColor(this.isReceived?"#FFFFFF":"#C0EBDF")
.borderRadius(24)
.fontColor("#182431")
}
}.width('100%')
Flex({ alignItems: ItemAlign.Center, direction: FlexDirection.Row,
justifyContent:this.isReceived? FlexAlign.Start: FlexAlign.End }) {
Text(this.time)
.textAlign(TextAlign.Start)
.fontSize(10)
.lineHeight(13)
.fontColor("#99182431")
}.width('100%')
.margin({ left:this.isReceived?12:0, right:this.isReceived?0:12 })
}
.margin({left:24, right:24 })
.backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试
}
}
```
**栅格布局**
回顾方舟开发框架一多能力,消息气泡在默认设备和平板上布局不同,可以借助栅格布局来解决。为了方便测试,我们预定义一个全局数组。
```
const globalMessageList:any[] = [
{
'time':'上午 10:20',
'content':'项目介绍',
'isReceived':false
},
{
'time':'上午 10:28',
'content':'OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及运营的开源项目,目标是面向全场景、全连接、全智能时代,基于开源的方式,搭建一个智能终端设备操作系统的框架和平台,促进万物互联产业的繁荣发展。',
'isReceived':false
},{
'time':'上午 10:32',
'content':'技术架构',
'isReceived':true
},
{
'time':'上午 10:35',
'content':'OpenHarmony整体遵从分层设计,从下向上依次为:内核层、系统服务层、框架层和应用层。系统功能按照“系统 > 子系统 > 组件”逐级展开,在多设备部署场景下,支持根据实际需求裁剪某些非必要的组件。',
'isReceived':true
}
]
```
结合[栅格组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-gridcontainer.md)的定义,考虑我们当前的实际场景,GridRow的各参数设置如下。
- columns:栅格组件中的列数,当前场景默认12列即可。
- gutter:栅格布局列间距,当前场景未使用该参数,默认设置为0即可。
- margin: 栅格布局两侧间距,在开发消息气泡组件时,已经设置了左右间距,故该属性也默认配置为0。
栅格中仅包含我们自定义的消息气泡组件,该组件在各断点上的参数配置如下。
| 断点 | 窗口宽度(vp) | 栅格总列数 | 消息气泡占用的列数 | 接收场景偏移的列数 | 发送场景偏移的列数 |
| -------- | -------- | -------- | -------- | -------- | -------- |
| sm | [320,&nbsp;520) | 12 | 12 | 0 | 0 |
| md | [520,&nbsp;840) | 12 | 8 | 0 | 4 |
| lg | [840,&nbsp;+∞) | 12 | 8 | 0 | 4 |
| 默认设备 | 平板 |
| -------- | -------- |
| ![message_list_phone](figures/message_list_phone.png) | ![message_list_tablet](figures/message_list_tablet.png) |
```
@Component
export default struct MessageItem {
private isReceived: boolean
private content: string
private time: string
build() {
GridRow() {
GridCol({span: {sm: 12, md: 8, lg: 8},
offset: {sm: 0, md: this.isReceived? 0 : 4, lg: this.isReceived? 0 : 4}}) {
Flex({ justifyContent: FlexAlign.End, alignItems: ItemAlign.End }) {
MessageBubble({
isReceived: this.isReceived,
content: this.content,
time: this.time
})
}
}
}
}
}
@Entry
@Component
struct Conversation {
build() {
Column() { // 验证效果
MessageItem({
isReceived: globalMessageList[1].isReceived,
content: globalMessageList[1].content,
time: globalMessageList[1].time
})
MessageItem({
isReceived: globalMessageList[3].isReceived,
content: globalMessageList[3].content,
time: globalMessageList[3].time
})
}.backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试
}
}
```
### 组合成型
现在会话详情页面的顶部标题栏、信息列表及底部输入栏都已经准备完毕,将这三部分组合起来即可得到完整的页面。
- 通过[Flex组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-flex.md)将三个部分组合起来,注意justifyContent: FlexAlign.SpaceBetween配置项是将Flex组件中的元素按照主轴方向均匀分配,其中第一个元素与顶部对齐,最后一个元素与底部对齐。
- 通过[List组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md)[ForEach语法](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/ts-rending-control-syntax-foreach.md),显示整个消息列表。
| 默认设备 | 平板 |
| -------- | -------- |
| ![overview_phone](figures/overview_phone.png) | ![overview_tablet](figures/overview_tablet.png) |
```
@Entry
@Component
struct Conversation {
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start,
justifyContent: FlexAlign.SpaceBetween }) {
Column() {
TopArea() // 顶部标题栏
List() { // 消息列表
ForEach(globalMessageList, (item, index) => {
ListItem() {
MessageItem({
isReceived: item.isReceived,
content: item.content,
time: item.time
})
})
}
.listDirection(Axis.Vertical)
.edgeEffect(EdgeEffect.Spring)
}
BottomArea() // 底部输入栏
}
.backgroundColor("#F1F3F5")
.width('100%')
.height('100%')
}
}
```
## 总结
短信应用在默认设备和平板上的功能完全相同,因此选择了部署模型A。借助方舟开发框架一多能力,短信应用实现了在默认设备和平板上共用同一份代码,同时自然也共用安装包。
在实际开发过程中,会话详情页面需要从底层做数据交互,同时还要支持信息选择、信息删除、信息发送状态、输入框与输入法联动等等功能,会比本小节中介绍的基础版本复杂很多。读者如果对这部分感兴趣,可以访问[短信应用开源代码仓](https://gitee.com/openharmony/applications_mms/tree/master),了解会话详情页面的详细实现。
# 桌面应用
[桌面](https://gitee.com/openharmony/applications_launcher)是OpenHarmony中预置的系统应用,它是系统人机交互的首要入口。
## 应用功能
桌面提供了如下功能:
- 万能卡片:包括卡片的呼出和关闭、卡片管理、卡片拖动、卡片移除等。
- 任务中心:展示后台运行任务的快照。
- 大文件夹:包括大文件基础展示、将应用拖入及移出大文件夹等。
- 应用中心:展示全量桌面应用列表。
- 图标管理:图标显示、长按图标显示菜单列表等。
- 布局管理:对不同的设备、横竖屏、分辨率等做布局自适应。
- 桌面设置:设置桌面布局方案。
- 手势导航:允许用户用手势导航替代传统的三键导航。
- 应用启动:启动应用、应用启动动效等。
- 键鼠适配:支持鼠标及键盘。
- 快捷栏(Smart Dock):底部快捷栏,显示常用应用列表、支持添加应用快捷方式及删除等。
部分功能场景设计图如下所示。
| 功能点 | 默认设备 | 平板 |
| -------- | -------- | -------- |
| 万能卡片 | ![zh-cn_image_0000001267293008](figures/zh-cn_image_0000001267293008.jpg) | ![zh-cn_image_0000001267932928](figures/zh-cn_image_0000001267932928.jpg) |
| 任务中心 | ![zh-cn_image_0000001315932969](figures/zh-cn_image_0000001315932969.jpg) | ![zh-cn_image_0000001316932917](figures/zh-cn_image_0000001316932917.jpg) |
| 快捷栏 | ![zh-cn_image_0000001315453085](figures/zh-cn_image_0000001315453085.jpg) | ![zh-cn_image_0000001315732933](figures/zh-cn_image_0000001315732933.jpg) |
| 大文件夹 | ![zh-cn_image_0000001267532988](figures/zh-cn_image_0000001267532988.jpg) | ![zh-cn_image_0000001266893124](figures/zh-cn_image_0000001266893124.jpg) |
| 应用中心 | NA | ![zh-cn_image_0000001267293016](figures/zh-cn_image_0000001267293016.jpg) |
| 键鼠适配 | NA | ![zh-cn_image_0000001267932936](figures/zh-cn_image_0000001267932936.jpg) |
| 桌面设置 | ![zh-cn_image_0000001315932977](figures/zh-cn_image_0000001315932977.jpg) | ![zh-cn_image_0000001316932929](figures/zh-cn_image_0000001316932929.jpg) |
## 部署模型
如前所述,为保证最佳的体验效果,桌面应用根据默认设备和平板的特性,做了深入定制。
- 不同设备桌面应用的特性规格有差异。
- 平板有应用中心功能,平板通过快捷栏任务中心图标进入任务中心,才能看到全量应用。默认设备直接在桌面上显示全量应用,没有应用中心功能。
- 默认设备不需要适配键鼠输入。
- 同一特性,在不同设备上页面跳转逻辑有差异。
默认设备和平板的万能卡片管理页面完全不同,默认设备上是跳转到新的页面进行卡片管理操作,而平板上是直接在原有页面上弹出Dailog窗口进行卡片管理操作。
因此,桌面最终选择了[部署模型B](introduction.md#部署模型),即默认设备和平板上部署不同的HAP包。
## 工程结构
```
/applications
├── common # 公共模块目录
│ └── src
│ └── main
│ └── ets
│ └── default
│ ├── base # 公共presenter层代码目录
│ ├── bean # 公共数据对象
│ ├── cache # 缓存目录
│ ├── configs # 应用配置对象目录
│ ├── constants # 应用常量对象目录
│ ├── manager # manager代码目录
│ ├── model # Model层代码目录
│ ├── settings # settings配置项
│ ├── uicomponents # 自定义组件目录
│ └── utils # 工具类代码目录
├── feature # feature层模块目录
│ ├── appcenter # 应用中心模块目录
│ ├── bigfolder # 大文件夹模块目录
│ ├── form # 卡片模块目录
│ ├── gesturenavigation # 桌面设置模块目录
│ ├── launcherlayout # 桌面布局计算模块目录
│ ├── pagedesktop # 桌面设置模块目录
│ ├── recents # 最近任务模块目录
│ ├── settings # 桌面设置模块目录
│ └── smartdock # dock栏模块目录
└── product # 产品层模块目录
├── pad # 平板目录
└── phone # 默认设备目录
```
桌面应用在开发阶段,采用了三层工程结构。默认设备和平板共用feature和common目录中的代码,仅在product目录中各自有部分独立代码。
- 业务形态层(product)
包含不同产品形态的桌面。含桌面窗口、个性化业务、组件的配置以及个性化资源包。不同产品形态,编译出不同的Launcher的HAP包,各产品按需部署。
- 公共特性层(feature)
抽象的公共特性组件集合,可以被product层不同形态的桌面所引用,并且在product层上做一些定制化的配置。
- 功能能力层(common)
基础能力集,每个桌面形态都必须要依赖的模块。该层不可被分割,方便后续架构拓展和演进。
## 总结
本小节主要仅从工程结构角度介绍桌面应用,读者如果对其具体实现感兴趣,可以访问[桌面应用开源代码仓](https://gitee.com/openharmony/applications_launcher)了解详情。桌面应用在默认设备和平板上功能有较大差异,因此最终选择了部署模型B。虽然在默认设备和平板上是不同的安装包,但二者依然公用了非常多的代码。经统计,**共用代码占比在90%左右**。在后续拓展其它设备类型时,依然可以使用此部分公共代码。这既可以提高多设备场景开发效率,同时也可以降低后期的维护成本。
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
**基于触控的交互** **基于触控的交互**
很多设备都拥有支持多点触控的屏幕,允许用户使用手指和/或手写笔进行交互。它们与屏幕的接触状态、数量以及运动行为被识别成触控手势和操作,可以支持多种交互功能和体验(例如点击、滑动、缩放、旋转)。在多数情况下,应将触控交互作为用户首要的交互方式。 很多设备的屏幕都支持多点触控,允许用户通过手指或手写笔进行交互。它们与屏幕的接触状态、数量以及运动行为被识别成触控手势和操作,可以支持多种交互功能和体验(例如点击、滑动、缩放、旋转)。在多数情况下,应将触控交互作为用户首要的交互方式。
以下是基础的手势操作: 以下是基础的手势操作:
......
# 自适应布局 # 自适应布局
自适应布局是通过设定元素与外部容器的相对关系实现的。当外部容器大小、位置等发生变化时,元素即可以根据相对关系自动变化以适应外部环境的变化。通常自适应布局能根据vp/px变化进行无级连续的变化。 自适应布局是通过设定元素与外部容器的相对关系实现的。当外部容器大小、位置等发生变化时,元素即可以根据相对关系自动变化以适应外部环境的变化。通常自适应布局能根据vp/px变化进行无级连续的变化。
## 自适应拉伸 ## 自适应拉伸
某单个内容或某组内容的显示宽度不是固定值,而是通过相对参照物的方式来确定其显示宽度。当参照物的宽度发生变化时,内容或内容间距的宽度随之发生自适应拉伸。 某单个内容或某组内容的显示宽度不是固定值,而是通过相对参照物的方式来确定其显示宽度。当参照物的宽度发生变化时,内容或内容间距的宽度随之发生自适应拉伸。
左右拉伸:例如,列表开关组合中,在窗口宽度变化时,开关控件固定宽度并相对列表的右边缘位置固定,整个组合与文本宽度均自适应变化。 左右拉伸:例如,列表开关组合中,在窗口宽度变化时,开关控件固定宽度并相对列表的右边缘位置固定,整个组合与文本宽度均自适应变化。
![zh-cn_image_0000001258762686](figures/zh-cn_image_0000001258762686.gif) ![拉伸能力](figures/拉伸能力.gif)
均分拉伸:例如,在图标型网格中,当窗口宽度变化时,入口图标间距与图标离左右边缘间距同时均等变化。 均分拉伸:例如,在图标型网格中,当窗口宽度变化时,入口图标间距与图标离左右边缘间距同时均等变化。
![zh-cn_image_0000001291556325](figures/zh-cn_image_0000001291556325.gif) ![均分能力](figures/均分能力.gif)
自适应拉伸适用于文字、普通按钮、间距等展示宽度灵活,对宽高比不敏感的内容和内容组合。 自适应拉伸适用于文字、普通按钮、间距等展示宽度灵活,对宽高比不敏感的内容和内容组合。
当可能出现的拉伸宽度不足以显示默认内容时,应根据场景选择优先保证内容完整或者优先保证其他内容的屏效,并进行截断或换行等组合适配。 当可能出现的拉伸宽度不足以显示默认内容时,应根据场景选择优先保证内容完整或者优先保证其他内容的屏效,并进行截断或换行等组合适配。
![zh-cn_image_0000001245276368](figures/zh-cn_image_0000001245276368.png) ![拉伸注意场景](figures/拉伸注意场景.png)
## 自适应缩放 ## 自适应缩放
组件的显示大小是固定比例,通过相对参照物的方式来确定其宽或高。当参照物的大小发生变化时,元素的大小随之发生自适应缩放。 组件的显示大小是固定比例,通过相对参照物的方式来确定其宽或高。当参照物的大小发生变化时,元素的大小随之发生自适应缩放。
完整缩放:例如,在宽度或高度变化时,时钟始终保证表盘完整展示并根据较短边决定宽高。 完整缩放:例如,在宽度或高度变化时,时钟始终保证表盘完整展示并根据较短边决定宽高。
![zh-cn_image_0000001291675753](figures/zh-cn_image_0000001291675753.gif) ![zh-cn_image_0000001291675753](figures/zh-cn_image_0000001291675753.gif)
占比缩放:例如,带主体和背景的插画,画面内容根据宽度变化裁切,根据高度变化按50%比例缩放。 占比缩放:例如,带主体和背景的插画,画面内容根据宽度变化裁切,根据高度变化按50%比例缩放。
![zh-cn_image_0000001245116688](figures/zh-cn_image_0000001245116688.gif) ![缩放案例](figures/缩放案例.gif)
自适应缩放适用于图片、圆形按钮、banner、反应真实物体形状的图像等必须保证宽高比的内容。 自适应缩放适用于图片、圆形按钮、banner、反应真实物体形状的图像等必须保证宽高比的内容。
不推荐将所有元素同时缩放、或某内容放大过大超过屏幕50%。这将导致获取信息量不增反减,不符合用户预期。 不推荐将所有元素同时缩放、或某内容放大过大超过屏幕50%。这将导致获取信息量不增反减,不符合用户预期。
![zh-cn_image_0000001292842113](figures/zh-cn_image_0000001292842113.gif) ![4.3-2](figures/4.3-2.png)
## 自适应延伸 ## 自适应延伸
组件的显示数量不是固定的,而是通过相对参照物的方式来确定其显示数量。当参照物的宽度发生变化时,组件随之发生自适应延伸显示更多数量。 组件的显示数量不是固定的,而是通过相对参照物的方式来确定其显示数量。当参照物的宽度发生变化时,组件随之发生自适应延伸显示更多数量。
同功能内容延伸:例如,子页签和可滑动宫格在默认宽度下通过露出最后内容,提示右方有更多入口,在宽度变化时,可在每个元素宽度不变、保持滑动交互时显示更多数量。 同功能内容延伸:例如,子页签和可滑动宫格在默认宽度下通过露出最后内容,提示右方有更多入口,在宽度变化时,可在每个元素宽度不变、保持滑动交互时显示更多数量。
![zh-cn_image_0000001291556369](figures/zh-cn_image_0000001291556369.gif) ![延长能力](figures/延长能力.gif)
不同功能内容延伸或隐藏:例如,默认处于同一排的不同音乐播放按钮优先级不同,在宽度变化时可延伸或隐藏低优先级的按钮,最大化适应不同窗口尺寸。 不同功能内容延伸或隐藏:例如,默认处于同一排的不同音乐播放按钮优先级不同,在宽度变化时可延伸或隐藏低优先级的按钮,最大化适应不同窗口尺寸。
![zh-cn_image_0000001245276416](figures/zh-cn_image_0000001245276416.gif) ![隐藏能力](figures/隐藏能力.gif)
自适应延伸/隐藏适用于页签、操作块、推荐栏目等具有相同交互层级且有更多数据可以填充的内容。 自适应延伸/隐藏适用于页签、操作块、推荐栏目等具有相同交互层级且有更多数据可以填充的内容。
注意:需要判断因隐藏而不展示的内容对功能完整性是否有影响,并考虑通过滑动或“更多”按钮提供查看使用该内容的方式。 注意:需要判断因隐藏而不展示的内容对功能完整性是否有影响,并考虑通过滑动或“更多”按钮提供查看使用该内容的方式。
## 自适应折行 ## 自适应折行
定义了折行能力的组件,可以根据组件容器的可用空间,体现纵向布局或者横向布局。 定义了折行能力的组件,可以根据组件容器的可用空间,体现纵向布局或者横向布局。
例如,在宽度足够时,操作块位于同一行,在宽度变小时,可根据内容能显示的宽度纵向排布。 例如,在宽度足够时,操作块位于同一行,在宽度变小时,可根据内容能显示的宽度纵向排布。
![zh-cn_image_0000001291675805](figures/zh-cn_image_0000001291675805.png) ![折行案例分镜](figures/折行案例分镜.png)
自适应折行适用于页签、操作块、内容流等具有相同交互层级,且希望保证类型和数量完整性的内容。 自适应折行适用于页签、操作块、内容流等具有相同交互层级,且希望保证类型和数量完整性的内容。
自适应布局对应OpenHarmony系统提供的自适应布局能力中的拉伸、均分、缩放、占比、延伸、隐藏、折行。自适应布局能力详见本文“[自适应布局](adaptive-layout-intro.md)”。 自适应布局对应OpenHarmony系统提供的自适应布局能力中的拉伸、均分、缩放、占比、延伸、隐藏、折行。自适应布局能力详见本文“[自适应布局](adaptive-layout.md)”相关介绍。
# 设计自检表 # 设计自检表
设计自检表详细列举出了在全场景设备设计和开发过程中应当注意的设计规则,这将帮助应用减少用户舆情且提升用户体验的一致性。 设计自检表详细列举出了在全场景设备设计和开发过程中应当注意的设计规则,这将帮助应用减少用户舆情且提升用户体验的一致性。
自检表的要求范围分为“必选”与“推荐”两类。必选类一般为已总结出的较优解决方案或效果,表示相关设计需要按照此原则统一执行;推荐类指可能受应用品牌风格或业务特殊性影响,可适量做出修改。 自检表的要求范围分为“必选”与“推荐”两类。必选类一般为已总结出的较优解决方案或效果,表示相关设计需要按照此原则统一执行;推荐类指可能受应用品牌风格或业务特殊性影响,可适量做出修改。
请参考以下表格范围内提出的要求对应用进行检查。
请参考以下表格范围内提出的要求对应用进行检查。
| **类型** | **条目** | **说明** |
| -------- | ------------------ | ------------------------------------------------------------ | | **类型** | **条目** | **说明** |
| 应用架构 | 导航结构 | 保证同一应用/服务在各设备上导航结构一致。 | | -------- | ------------------ | ------------------------------------------------------------ |
| | 界面框架 | 尽量使用推荐的常用界面架构,以更好达到一多效果。 | | 应用架构 | 导航结构 | 在各设备上页面导航结构保持一致(同时出多个设备的UX设计)。 |
| 布局 | 自适应布局 | 关注布局标注是否逻辑合理,是否具备自适应能力。保证在不同尺寸和分辨率的设备上能够无错位/不截断/不变形地正常显示。 | | 布局 | 拉通设计 | 拉通各设备的布局设计,保证在不同尺寸和分辨率的设备上能够无错位/不截断/不变形/不过多空白(50%以上)/不过于拥挤(间距小于16vp,明显截断)/无大图大字体地正常显示。 |
| | 响应式布局 | 关注布局是否更有效利用屏幕控件,是否具备响应式能力。保证在不同尺寸和分辨率的设备上不过多空白(50%以上)/不过于拥挤(间距小于16vp,明显截断)。 | | | 响应式设计 | 栅格布局只能占N列以及N列内部的Gutter,不包含N列两侧的Gutter。 |
| | 页面结构 | 尽量使用推荐的常用页面结构,以更好达到一多效果。 | | | 响应式设计 | 明确标注使用什么类型的栅格、给出在不同断点下栅格三要素取值。 |
| | 页面结构优化 | 在通用能力不适用业务诉求时,进行页面特殊优化,保证在具体设备上的使用体验。 | | | 响应式设计 | 按容器去对齐栅格,而不是内部子元素对齐栅格。 |
| 人机交互 | 输入方式 | 需保证在各设备上完整支持触摸、鼠标、触控、键盘、遥控器、摇杆等交互方式,并符合标准定义。 | | | 响应式设计 | 栅格除了页面布局设计外,在做局部栅格设计时,需要通过明显方式如颜色等进行标注区分,避免混淆。 |
| | 交互归一 | 应使用系统提供的控件以达到一致的交互体验。如有定制,需保证在各场景下,不同输入设备上的操作与指南要求一致。需特别注意鼠标行为。 | | | 响应式设计 | 禁止出现标注了栅格但实际没有通过栅格进行布局设计,避免混淆。 |
| 视觉风格 | 单位 | 用于界面布局的单位应全部使用vp。只针对严格控制元素尺寸的场景使用px。 | | | 自适应设计 | 非栅格设计场景下,明确标注自适应布局能力。自适应布局能力有:拉伸、均分、占比、缩放、延伸、隐藏、折行。 |
| | 色彩 | 用于色彩的赋值应使用分层参数。推荐支持深色模式,需保证界面在系统切换色彩模式时没有识别性问题。 | | 人机交互 | 输入方式 | 需保证在各设备上完整支持触摸、鼠标、触控、键盘、遥控器、摇杆等交互方式,并符合标准定义。 |
| | 字体 | 尽量使用fp为文字大小单位,需要响应系统大字体模式,确保系统调节字体大小后,界面字体能响应变化大小,并且界面布局没有出现布局错乱问题。 | | | 交互归一 | 应使用系统提供的控件以达到一致的交互体验。如有定制,需保证在各场景下,不同输入设备上的操作与指南要求一致。需特别注意鼠标行为。 |
| 视觉风格 | 单位 | 用于界面布局的单位应全部使用vp。只针对严格控制元素尺寸的场景使用px。 |
| | 色彩 | 用于色彩的赋值应使用分层参数。推荐支持深色模式,需保证界面在系统切换色彩模式时没有识别性问题。 |
| | 字体 | 使用fp为文字大小单位,需要响应系统大字体模式,确保系统调节字体大小后,界面字体能响应变化大小,并且界面布局没有出现布局错乱问题。 |
| 多态控件 | 支持常用的控件状态 | 确保控件不同状态下的视觉效果没有缺失。控件的常用状态有:正常态、不可用态、点击态、获焦态、激活态、悬停态。 | | 多态控件 | 支持常用的控件状态 | 确保控件不同状态下的视觉效果没有缺失。控件的常用状态有:正常态、不可用态、点击态、获焦态、激活态、悬停态。 |
\ No newline at end of file
# 设计交付
## 概述
为了将UX设计详尽准确地实现并传递给开发者,设计师需向开发者提供必要的设计交付件,包括但不限于:应用规格说明、交互流程、视觉效果、视觉标注、视觉规格说明、切图资源、动效参数资源、音效资源等内容。
面向多设备多尺寸的应用UX设计交付件,以完整说明界面布局与视觉设计为主要目的,至少应包含:效果图、标注图、规格说明和切图资源。
下面将分别介绍不同交付内容的用途与规范。
![4.8-交付4件套](figures/4.8-交付4件套.png)
## 效果图
效果图是表达UX设计的关键内容,用于直观呈现目标体验的静态效果,并作为开发者与测试工程师的实现与验收依据。效果图一般为jpg或png格式。
在优秀的设计交付件中,针对不同前置条件下,各交互流程所途经的每个界面都应匹配效果图。对于大量重复使用的组件元素,如弹窗和即时反馈,亦可配合规格统一说明,不做过多重复设计。
在多设备设计中,为了清晰表达设计效果,设计师仍需要针对不同尺寸的关键界面提供符合规范的效果图。关键界面包括且不限于:
- 应用的首页
- 可以从首页直接进入的各二级界面
- 核心使用流程途经的各界面
- 能体现多数界面的自适应与响应式规格的典型界面
不同尺寸的效果图,至少应包含小设备、中设备、大设备。根据业务涉及的设备特点,可补充超小尺寸效果,及不同设备的横竖屏效果,提前充分验证并优化UX设计体现的差异性、一致性、灵活性、兼容性。
对应不同设备效果图的设计画板尺寸推荐如下:
| 设备类型 | 屏幕宽度 | 画板尺寸(vp) |
| -------- | -------- | -------- |
| 超小设备 | [0,&nbsp;320) | 240\*320 |
| 小设备 | [320,&nbsp;520) | 360\*780 |
| 中设备 | [520,&nbsp;840) | 677\*763 |
| 大设备 | [840,&nbsp;+) | 1280\*800 |
多设备效果示意图
![4.8-效果示意图](figures/4.8-效果示意图.png)
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 画板尺寸为不同宽度断点下的典型设备屏幕尺寸,可根据业务具体针对的设备选择其他画板尺寸。
>
> - 画板尺寸以vp为单位提供,根据实际设计所需精度,可统一把设计文档中所有画板设置为1倍或多倍的px尺寸。
>
> - 当效果图需要展示一屏以上的内容,如列表内容较长时,建议保持宽度不变并增加画板高度以容纳更多内容。
## 标注图
标注图是向开发者传递界面上每个元素详细属性,以指导代码完整实现UX设计的图像化文档。界面元素的属性包括:色彩、尺寸、字体、圆角、间距、阴影、模糊、缩放、所用的组件、自适应布局、响应式布局等。标注图一般为jpg或png格式。
在优秀的设计交付件中,不同类型属性的标注文本大小一致、色彩不一、互不重叠,并与效果图内容在视觉上良好区隔。标注图数量与关键界面效果图一一对应,如遇到较复杂的界面,为了更清晰说明规格,也有多张标注图对应一张效果图的情况。
随着设计与开发工具的演进,一些业界工具支持界面元素属性的自动识别并创建标注,也可导出支持动态展示标注的效果图文档,一般为html格式。OpenHarmony应用的设计交付同样可以借助这些工具作为标注图的补充内容,但必选的分层参数仍需设计师专门确认并手动完成标注。
除了尺寸、间距等强依赖于业务具体设计的参数,色彩、字体、圆角、阴影、模糊等属性应尽可能使用分层参数完成标注。
标注示意图
![4.8-标注图](figures/4.8-标注图.png)
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 如遇到分层参数覆盖不到的属性值,可按照具体设计效果标注。此时必须详细考虑不同场景下该元素的效果。
## 规格说明
规格说明是一份专门编写的文档,用于更完整清晰地说明界面间的通用元素与变化规则,一般为pdf格式。规格说明不是UX设计交付件中的必选项,但它能帮助设计师节省很多重复性工作,帮助开发者快速理解UX设计规格,在面向多设备的应用设计交付中非常推荐。
在多设备设计中,规格说明常用于并排展示同一界面在不同尺寸下的效果,并说明栅格变化规则。
一多规范栅格图
![4.8-栅格标注](figures/4.8-栅格标注.png)
## 切图资源
包含在设计效果中的素材,如图标、图片、序列帧等,应根据实际需要输出为合适的格式提供开发者置入界面内。
为了更好在多设备上根据设备dpi展示清晰的图像,一分优秀的应用应含有多套同名的切图资源,它们分别存放在mdpi、ldpi、xldpi、xxldpi的文件夹目录下,最终会存放到应用资源包的同名路径中。
多套同名切图文件夹示意图
![4.8-切图资源对应文件夹](figures/4.8-切图资源对应文件夹.png)
图标资源可以是png、jpg、webp、svg等格式。推荐在多设备设计中使用svg图标资源,因为能充分利用矢量图片体积较小、可以自由缩放且不出现锯齿、可根据色彩参数实时赋色的特点,仅用一套资源即可满足复杂场景的UX规范。如使用其他位图格式如png、jpg、webp,则需分别交付各dpi下的切图资源,以达到边缘像素清晰的体验。
图片资源可以是png、jpg、webp等格式。与图标资源类似,一般应提供各dpi下的图片资源。在不同dpi下对边缘像素要求不高的图片如背景图,则推荐按照更高dpi提供一张资源复用到各dpi,以减少应用包大小。
在多设备设计中,图片也可根据设计效果,在不同宽度断点使用同一个资源,或分别交付:
- 当图片所在组件接口提供的缩放显示机制满足UX设计效果,可以用同一个资源
- 当图片所在组件接口提供的缩放显示机制不满足、且不可通过简单的自定义规则实现UX效果,则推荐使用不同资源
夜晚单张适配多设备宽度示意图
![4.8-夜晚单张适配多设备](figures/4.8-夜晚单张适配多设备.png)
晴天多张适配多设备宽度示意图
![4.8-晴天多张适配](figures/4.8-晴天多张适配.png)
# 栅格系统 # 栅格系统
栅格系统是一个多设备下通用的辅助定位系统,适用于应用窗口的整体布局,也支持界面局部内容使用。栅格系统由 Margin,Gutter,Column 三个属性构成。Margin是相对屏幕、窗口等父容器左右边缘的距离,决定了内容可展示的整体宽度;Gutter是每个Column的间距,决定内容间的紧密程度; Column是内容的占位元素,其数量决定了内容的布局复杂度。Margin大小、Gutter大小、Column数量综合决定Column的具体宽度。 栅格系统是一个多设备下通用的辅助定位系统,适用于应用窗口的整体布局,也支持界面局部内容使用。栅格系统由 Margin,Gutter,Column 三个属性构成。Margin是相对屏幕、窗口等父容器左右边缘的距离,决定了内容可展示的整体宽度;Gutter是每个Column的间距,决定内容间的紧密程度; Column是内容的占位元素,其数量决定了内容的布局复杂度。Margin大小、Gutter大小、Column数量综合决定Column的具体宽度。
通过栅格系统进行布局,可以更好达到多设备下布局的一致性。 通过栅格系统进行布局,可以更好达到多设备下布局的一致性。
![zh-cn_image_0000001224173302](figures/zh-cn_image_0000001224173302.png) ![zh-cn_image_0000001224173302](figures/zh-cn_image_0000001224173302.png)
Margin、Gutter的大小、Column的数量均可自定义,界面内容跟据Column的边缘定位。通过采用不同数值调整内容信息量和紧密程度,一般推荐使用4或8的倍数。例如Margin 32vp、Gutter 16vp、Column数量为4,或Margin 40vp、Gutter 24vp、Column数量为8。 Margin、Gutter的大小、Column的数量均可自定义,界面内容跟据Column的边缘定位。通过采用不同数值调整内容信息量和紧密程度,一般推荐使用4或8的倍数。例如Margin 32vp、Gutter 16vp、Column数量为4,或Margin 40vp、Gutter 24vp、Column数量为8。
![zh-cn_image_0000001305734113](figures/zh-cn_image_0000001305734113.png) ![栅格系统例](figures/栅格系统例.png)
栅格系统对应OpenHarmony系统提供的布局能力中的栅格布局,详见本文 “[栅格布局](responsive-layout.md#栅格布局)”相关介绍。
# 交互事件归一 # 交互事件归一
本章节描述了在多种交互任务或场景下,应用在触屏上和其它常用的输入方式(例如鼠标、触摸板、键盘)上分别对应的正确的交互规则。**设计师和开发者应保证在当前输入方式下应用能够以正确的、符合用户习惯的交互规则进行响应。** 本章节描述了在多种交互任务或场景下,应用在触屏上和其它常用的输入方式(例如鼠标、触摸板、键盘)上分别对应的正确的交互规则。**设计师和开发者应保证在当前输入方式下应用能够以正确的、符合用户习惯的交互规则进行响应。**
![zh-cn_image_0000001224333656](figures/zh-cn_image_0000001224333656.png) ![zh-cn_image_0000001224333656](figures/zh-cn_image_0000001224333656.png)
## 打开/切换对象 ## 打开/切换对象
用户通过点击某个元素触发功能、访问新页面、或改变自身状态。 用户通过点击某个元素触发功能、访问新页面、或改变自身状态。
| **输入方式** | **交互行为** | **示意** | | **输入方式** | **交互行为** | **示意** |
| -------- | -------- | -------- | | -------- | -------- | -------- |
| 触屏 | 单指单击 | ![zh-cn_image_0000001280472681](figures/zh-cn_image_0000001280472681.png) | | 触屏 | 单指单击 | ![zh-cn_image_0000001280472681](figures/zh-cn_image_0000001280472681.png) |
| 鼠标 | 左键单击&nbsp;/&nbsp;左键双击 | ![zh-cn_image_0000001236472600](figures/zh-cn_image_0000001236472600.png) | | 鼠标 | 左键单击&nbsp;/&nbsp;左键双击 | ![zh-cn_image_0000001236472600](figures/zh-cn_image_0000001236472600.png) |
| 触摸板 | 单指单击&nbsp;/&nbsp;单指双击 | ![zh-cn_image_0000001280232265](figures/zh-cn_image_0000001280232265.png) | | 触摸板 | 单指单击&nbsp;/&nbsp;单指双击 | ![zh-cn_image_0000001280232265](figures/zh-cn_image_0000001280232265.png) |
| 键盘 | 移动焦点到对象上后按下Enter键 | ![zh-cn_image_0000001280472701](figures/zh-cn_image_0000001280472701.png) | | 键盘 | 移动焦点到对象上后按下Enter键 | ![zh-cn_image_0000001280472701](figures/zh-cn_image_0000001280472701.png) |
一般地,触屏手指的按下/抬起行为对应于光标的按下/抬起行为。 一般地,触屏手指的按下/抬起行为对应于光标的按下/抬起行为。
在一些特殊场景,可能会存在使用鼠标/触摸板双击打开对象的交互方案,例如电脑模式下打开桌面应用或文件。此类情况需由应用单独特殊处理,且同一功能不能同时支持单击和双击两种交互方式。 在一些特殊场景,可能会存在使用鼠标/触摸板双击打开对象的交互方案,例如电脑模式下打开桌面应用或文件。此类情况需由应用单独特殊处理,且同一功能不能同时支持单击和双击两种交互方式。
## 显示菜单 ## 显示菜单
某个元素上显示弹出菜单或快捷方式菜单。 某个元素上显示弹出菜单或快捷方式菜单。
![zh-cn_image_0000001268533753](figures/zh-cn_image_0000001268533753.jpg) ![zh-cn_image_0000001268533753](figures/zh-cn_image_0000001268533753.jpg)
| **输入方式** | **交互行为** | | **输入方式** | **交互行为** |
| -------- | -------- | | -------- | -------- |
| 触屏 | 单指长按 | | 触屏 | 单指长按 |
| 鼠标 | 右键单击(与PC一致)/&nbsp;左键长按(保留触屏习惯) | | 鼠标 | 右键单击(与PC一致)/&nbsp;左键长按(保留触屏习惯) |
| 触摸板 | 双指轻单击/重单击(与PC一致)/&nbsp;单指重长按(保留触屏习惯) | | 触摸板 | 双指轻单击/重单击(与PC一致)/&nbsp;单指重长按(保留触屏习惯) |
| 键盘 | (无通用操作) | | 键盘 | (无通用操作) |
这里的菜单指的是广义的菜单,即用于展示用户可执行的操作的临时性弹出窗口。 这里的菜单指的是广义的菜单,即用于展示用户可执行的操作的临时性弹出窗口。
凡是在触屏上通过长按显示的菜单,都需要支持鼠标右键单击和触摸板双指单击的触发方式。 凡是在触屏上通过长按显示的菜单,都需要支持鼠标右键单击和触摸板双指单击的触发方式。
## 拖拽对象 ## 拖拽对象
直接指向某个元素并移动到界面其他位置 直接指向某个元素并移动到界面其他位置
![zh-cn_image_0000001268653953](figures/zh-cn_image_0000001268653953.png) ![zh-cn_image_0000001268653953](figures/zh-cn_image_0000001268653953.png)
| **输入方式** | **交互行为** | | **输入方式** | **交互行为** |
| -------- | -------- | | -------- | -------- |
| 触屏 | 长按某对象后触发可拖拽状态,然后移动手指改变对象位置。 | | 触屏 | 长按某对象后触发可拖拽状态,然后移动手指改变对象位置。 |
| 鼠标&nbsp;/&nbsp;触摸板 | 鼠标左键或触摸板单指按下即可拖拽对象(无需长按等待)。 | | 鼠标&nbsp;/&nbsp;触摸板 | 鼠标左键或触摸板单指按下即可拖拽对象(无需长按等待)。 |
| 键盘 | (无通用操作) | | 键盘 | (无通用操作) |
# 布局基础运用案例 # 布局基础运用案例
## 平级导航的复合网格视图 ## 平级导航的复合网格视图
平级导航的复合网格视图常出现在同时展示多种不同内容的界面。 平级导航的复合网格视图常出现在同时展示多种不同内容的界面。
例如,市场类应用作为典型的平级导航,其首页不同板块采用了不同布局能力。 例如,市场类应用作为典型的平级导航,其首页不同板块采用了不同布局能力。
![zh-cn_image_0000001317088945](figures/zh-cn_image_0000001317088945.png) ![一多-布局1](figures/一多-布局1.png)
- 标题栏与搜索栏:因元素单一、位置固定在顶部,因此适合采用自适应拉伸,并在大尺寸界面中从纵排变为横排,充分利用顶部区域。 - 标题栏与搜索栏:因元素单一、位置固定在顶部,因此适合采用自适应拉伸,并在大尺寸界面中从纵排变为横排,充分利用顶部区域。
- 运营横幅:在小设备上默认为多张轮播展示,随宽度变化采用自适应缩放,在中尺寸界面通过重复布局变为并排多张。 - 运营横幅:在小设备上默认为多张轮播展示,随宽度变化采用自适应缩放,在中尺寸界面通过重复布局变为并排多张。
- 图标型网格:对于数量固定、且子内容重要程度相同的网格,需保证完全展示,可采用均分拉伸。对于数量不限的网格,则采用自适应延伸,在更大宽度上展示更多数量。 - 图标型网格:对于数量固定、且子内容重要程度相同的网格,需保证完全展示,可采用均分拉伸。对于数量不限的网格,则采用自适应延伸,在更大宽度上展示更多数量。
- 底部导航栏:导航类控件本身综合了均分和折行,在宽度变化时能占用均等宽度并在足够宽度下并排,当在大尺寸界面中,挪移到左边,使不同页签距离更近、同时符合视觉走向。 - 底部导航栏:导航类控件本身综合了均分和折行,在宽度变化时能占用均等宽度并在足够宽度下并排,当在大尺寸界面中,挪移到左边,使不同页签距离更近、同时符合视觉走向。
在横竖屏切换时,也保持了一致的布局能力,实际上完成了大尺寸和中尺寸的切换。 在横竖屏切换时,也保持了一致的布局能力,实际上完成了大尺寸和中尺寸的切换。
![zh-cn_image_0000001317328797](figures/zh-cn_image_0000001317328797.png) ![一多-布局2](figures/一多-布局2.png)
当界面出现在智慧屏上,虽然同是大尺寸界面,为了符合设备样式和遥控器交互规则,搜索栏转化为图标入口,导航栏挪移到页面上部。 当界面出现在智慧屏上,虽然同是大尺寸界面,为了符合设备样式和遥控器交互规则,搜索栏转化为图标入口,导航栏挪移到页面上部。
![zh-cn_image_0000001268448854](figures/zh-cn_image_0000001268448854.png) ![一多-布局3](figures/一多-布局3.png)
## 层级导航的列表视图 ## 层级导航的列表视图
层级导航的列表视图常出现在多类简单信息并列或多入口业务入口的界面。 层级导航的列表视图常出现在多类简单信息并列或多入口业务入口的界面。
例如,设置类应用作为典型的层级导航,其列表控件采用自适应拉伸。 例如,设置类应用作为典型的层级导航,其列表控件采用自适应拉伸。
![zh-cn_image_0000001268128998](figures/zh-cn_image_0000001268128998.png) ![布局基础案例-层级导航-设置](figures/布局基础案例-层级导航-设置.png)
在中尺寸设备中,为避免中间区域空白过大,采用缩进布局,大尺寸设备中,为充分利用横向空间,建议采用栅格系统形成分栏效果,并让列表元素在各自区域保持拉伸。 在中尺寸设备中,为避免中间区域空白过大,采用缩进布局,大尺寸设备中,为充分利用横向空间,建议采用栅格系统形成分栏效果,并让列表元素在各自区域保持拉伸。
## 专辑详情页面 ## 专辑详情页面
专辑详情不限于展示音乐内容,也用于展示视频、短视频、电台、书本等内容类合集。 专辑详情不限于展示音乐内容,也用于展示视频、短视频、电台、书本等内容类合集。
例如,歌单类界面作为典型的内容垂类页面,其总体分为标题栏、歌单信息、歌单操作、歌单列表、播放栏几个板块。 例如,歌单类界面作为典型的内容垂类页面,其总体分为标题栏、歌单信息、歌单操作、歌单列表、播放栏几个板块。
- 标题栏:采用自适应拉伸。 - 标题栏:采用自适应拉伸。
- 歌单信息:采用自适应缩放,并在中尺寸界面进行缩进处理使内容呈现协调。 - 歌单信息:采用自适应缩放,并在中尺寸界面进行缩进处理使内容呈现协调。
- 歌单操作:板块内部采用均分拉伸,在小尺寸设备上利用纵向空间、中尺寸设备上挪移到歌单封面右边。 - 歌单操作:板块内部采用均分拉伸,在小尺寸设备上利用纵向空间、中尺寸设备上挪移到歌单封面右边。
- 歌单列表:板块内部采用左右拉伸,在中尺寸设备上可与歌单信息使用相同缩进布局。 - 歌单列表:板块内部采用左右拉伸,在中尺寸设备上可与歌单信息使用相同缩进布局。
- 播放栏:固定在界面底部,保持左右拉伸即可。 - 播放栏:固定在界面底部,保持左右拉伸即可。
![zh-cn_image_0000001268288870](figures/zh-cn_image_0000001268288870.png) ![页面布局-布局基础案例-歌单详情页面布局能力360-800vp](figures/页面布局-布局基础案例-歌单详情页面布局能力360-800vp.png)
在横竖屏切换时,完成了中尺寸和大尺寸的切换。歌单列表板块进行挪移的同时,内部采用了重复布局。 在横竖屏切换时,完成了中尺寸和大尺寸的切换。歌单列表板块进行挪移的同时,内部采用了重复布局。
歌单信息和歌单操作板块因较小宽高比,挪移到上下排布。 歌单信息和歌单操作板块因较小宽高比,挪移到上下排布。
![zh-cn_image_0000001268608782](figures/zh-cn_image_0000001268608782.png) ![页面布局-布局基础案例-歌单详情页面布局能力800-1280vp](figures/页面布局-布局基础案例-歌单详情页面布局能力800-1280vp.png)
当界面出现在智慧屏上,为了符合沉浸简约的设备信息和遥控器交互规则,将部分歌单信息替代原来标题栏的位置,并取消播放栏。同时歌单列表居左,更方便遥控器选择。 当界面出现在智慧屏上,为了符合沉浸简约的设备信息和遥控器交互规则,将部分歌单信息替代原来标题栏的位置,并取消播放栏。同时歌单列表居左,更方便遥控器选择。
![zh-cn_image_0000001317208833](figures/zh-cn_image_0000001317208833.png) ![页面布局-布局基础案例-歌单详情页面布局能力1280-1920vp](figures/页面布局-布局基础案例-歌单详情页面布局能力1280-1920vp.png)
# 多态控件 # 多态控件
为了支持多设备,应用需要能够在不同的设备上运行,控件作为应用的基础组成部分,需要支持不同的设备,且在视觉、交互、动效等表现形式上针对设备进行必要的调整,达到最佳体验。因此,同一控件在不同的设备上会呈现出不同的形态,称为多态控件。 为了支持多设备,应用需要能够在不同的设备上运行,控件作为应用的基础组成部分,需要支持不同的设备,且在视觉、交互、动效等表现形式上针对设备进行必要的调整,达到最佳体验。因此,同一控件在不同的设备上会呈现出不同的形态,称为多态控件。
![zh-cn_image_0000001268129090](figures/zh-cn_image_0000001268129090.png) ![zh-cn_image_0000001268129090](figures/zh-cn_image_0000001268129090.png)
多态控件应该具备以下特点: 多态控件应该具备以下特点:
- 覆盖默认设备、平板,兼顾智慧屏、车机、智能穿戴等终端。 - 覆盖默认设备、平板,兼顾智慧屏、车机、智能穿戴等终端。
- 场景一致性。在对应的使用场景下,其交互、视觉、动效要保持一致,在设计上属性参数保持一致或差异化。 - 场景一致性。在对应的使用场景下,其交互、视觉、动效要保持一致,在设计上属性参数保持一致或差异化。
- 针对设备做优化。多态控件在不同的设备上的呈现应该是该设备下的最佳效果,因此在保证一致性的同时,还需要针对设备的特点进行优化。 - 针对设备做优化。多态控件在不同的设备上的呈现应该是该设备下的最佳效果,因此在保证一致性的同时,还需要针对设备的特点进行优化。
## 控件的状态 ## 控件的状态
- 控件的状态是一种视觉呈现,用于展示控件当前处于何种交互阶段。不同控件的相同状态应该保持一致的视觉风格,且应该清晰可见。 - 控件的状态是一种视觉呈现,用于展示控件当前处于何种交互阶段。不同控件的相同状态应该保持一致的视觉风格,且应该清晰可见。
- 应用可能部署在不同设备上供用户使用,有些设备会支持多种输入方式。例如平板可以连接蓝牙键盘和鼠标来做文字编辑工作,此时控件需要同时满足键盘和鼠标交互,需要支持获焦态和悬停态,如果控件没有支持这两种状态,在使用键盘走焦时或鼠标悬停时,控件就无法通过呈现出相应的状态为用户提供正确的视觉引导。OpenHarmony默认提供多种交互方式的控件实现,方便开发者支持多种输入方式和交互归一。 - 应用可能部署在不同设备上供用户使用,有些设备会支持多种输入方式。例如平板可以连接蓝牙键盘和鼠标来做文字编辑工作,此时控件需要同时满足键盘和鼠标交互,需要支持获焦态和悬停态,如果控件没有支持这两种状态,在使用键盘走焦时或鼠标悬停时,控件就无法通过呈现出相应的状态为用户提供正确的视觉引导。OpenHarmony默认提供多种交互方式的控件实现,方便开发者支持多种输入方式和交互归一。
常见的状态类型: 常见的状态类型:
| | | | | | | |
| -------- | -------- | -------- | | -------- | -------- | -------- |
| ![zh-cn_image_0000001268288974](figures/zh-cn_image_0000001268288974.gif)<br/>**正常态**<br/>表明当前控件可交互。 | ![zh-cn_image_0000001268608890](figures/zh-cn_image_0000001268608890.gif)<br/>**不可用态**<br/>表明当前控件不可交互。一般使用灰显的方式呈现。 | ![zh-cn_image_0000001317208945](figures/zh-cn_image_0000001317208945.gif)<br/>**点击态**<br/>表明当前控件当前处于点击状态。<br/>操作:手指或鼠标按下且未释放。 | | ![zh-cn_image_0000001268288974](figures/zh-cn_image_0000001268288974.gif)<br/>**正常态**<br/>表明当前控件可交互。 | ![zh-cn_image_0000001268608890](figures/zh-cn_image_0000001268608890.gif)<br/>**不可用态**<br/>表明当前控件不可交互。一般使用灰显的方式呈现。 | ![zh-cn_image_0000001317208945](figures/zh-cn_image_0000001317208945.gif)<br/>**点击态**<br/>表明当前控件当前处于点击状态。<br/>操作:手指或鼠标按下且未释放。 |
| ![zh-cn_image_0000001317488873](figures/zh-cn_image_0000001317488873.gif)<br/>**获焦态**<br/>表明当前控件处于焦点状态。操作:<br/>-&nbsp;键盘或遥控器通过方向键将焦点从一个控件移动到另外一个控件。<br/>-&nbsp;通过语音操作,使得控件获得焦点。 | ![zh-cn_image_0000001317089061](figures/zh-cn_image_0000001317089061.gif)<br/>**激活态**<br/>表明当前控件处于激活的状态。用于有多个元素可获焦的控件<br/>操作:焦点处在页签控件的某个页签上时,该页签获焦。点击此页签,该页签被激活。 | ![zh-cn_image_0000001317328893](figures/zh-cn_image_0000001317328893.gif)<br/>**悬停态**<br/>表明当前控件处于鼠标悬停的状态。<br/>操作:将鼠标悬停在控件之上。 | | ![zh-cn_image_0000001317488873](figures/zh-cn_image_0000001317488873.gif)<br/>**获焦态**<br/>表明当前控件处于焦点状态。操作:<br/>-&nbsp;键盘或遥控器通过方向键将焦点从一个控件移动到另外一个控件。<br/>-&nbsp;通过语音操作,使得控件获得焦点。 | ![zh-cn_image_0000001317089061](figures/zh-cn_image_0000001317089061.gif)<br/>**激活态**<br/>表明当前控件处于激活的状态。用于有多个元素可获焦的控件<br/>操作:焦点处在页签控件的某个页签上时,该页签获焦。点击此页签,该页签被激活。 | ![zh-cn_image_0000001317328893](figures/zh-cn_image_0000001317328893.gif)<br/>**悬停态**<br/>表明当前控件处于鼠标悬停的状态。<br/>操作:将鼠标悬停在控件之上。 |
## 弹出框
弹出框是一种模态窗口,在弹出框消失之前,用户无法操作其他界面内容,干扰性比较强。通常用来展示用户当前需要的或用户必须关注的信息或操作,其他情况不建议使用弹出框,可考虑通知等其他非模态窗口。 弹出框的内容通常是不同控件进行组合布局。例如文本(可带格式,如缩进、链接、粗体等)、列表、输入框、网格、图标或图片等,常用于选择或确认信息。
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
**兼容性** **兼容性**
在硬件能力、交互方式、使用场景差异较大的设备上,除了考虑布局位置、内容宽度、横向组件数量,还需支持不同的输入方式、考虑功能架构的调整,避免出现输入不识别、功能不可用、使用困难的问题。 在硬件能力、交互方式、使用场景差异较大的设备上,除了考虑布局位置、内容宽度、横向组件数量,还需支持不同的输入方式、考虑功能架构的调整,避免出现输入不识别、功能不可用、使用困难的问题。
## 设计要点 ## 设计要点
...@@ -35,9 +35,9 @@ ...@@ -35,9 +35,9 @@
例如:默认设备上的底Tab的结构,在Pad上一般使用侧边Tab来代替,在大屏上则是顶部Tab。 例如:默认设备上的底Tab的结构,在Pad上一般使用侧边Tab来代替,在大屏上则是顶部Tab。
![zh-cn_image_0000001317325609](figures/zh-cn_image_0000001317325609.png) ![一多-1-1](figures/一多-1-1.png)
更多应用架构的设计内容,详见:[应用导航结构设计](navigation-design.md)[应用页面结构设计](page-design.md) 更多应用架构的设计内容,详见:[应用架构](architecture-design.md)
### 响应式界面布局 ### 响应式界面布局
...@@ -48,31 +48,31 @@ OpenHarmony 提供了多种布局能力,开发者通过组合运用使内容 ...@@ -48,31 +48,31 @@ OpenHarmony 提供了多种布局能力,开发者通过组合运用使内容
例如:默认设备上的滚动banner,在其他设备上可进行延伸,平板上露出更多banner,大屏上完全显示两张。 例如:默认设备上的滚动banner,在其他设备上可进行延伸,平板上露出更多banner,大屏上完全显示两张。
![zh-cn_image_0000001317485573](figures/zh-cn_image_0000001317485573.png) ![一多-概述-界面布局-banner例图](figures/一多-概述-界面布局-banner例图.png)
在不同类型的设备上,界面的尺寸和比例更为多样,再加上使用上的差异,导致设计上更为复杂。为此,可以考虑使用分栏布局、重复布局、挪移布局、缩进布局,进一步解决内容的显示问题。 在不同类型的设备上,界面的尺寸和比例更为多样,再加上使用上的差异,导致设计上更为复杂。为此,可以考虑使用分栏布局、重复布局、挪移布局、缩进布局,进一步解决内容的显示问题。
例如:默认设备上上下排布的大图与列表,在长宽比例更大的设备上可挪移到左右展示。 例如:默认设备上上下排布的大图与列表,在长宽比例更大的设备上可挪移到左右展示。
![zh-cn_image_0000001268285678](figures/zh-cn_image_0000001268285678.png) ![概述-界面布局-歌单详情高保真](figures/概述-界面布局-歌单详情高保真.png)
更多界面布局的设计内容,详见:[界面布局](layout-design-intro.md) 更多界面布局的设计内容,详见:[界面布局](interface-layout-design.md)
### 交互归一 ### 交互归一
交互归一描述了在多种交互任务或场景下,应用在触屏上和其它常用的输入方式(例如鼠标、触摸板、键盘)上分别对应的正确的交互规则。设计师和开发者应保证在当前输入方式下应用能够以正确的、符合用户习惯的交互规则进行响应。通常情况下,系统已经做好了这些事情,开发者只需正确调用。如果您的操作比较特别,您需要考虑多端上的交互归一,以确保用户体验的一致。 交互归一描述了在多种交互任务或场景下,应用在触屏上和其它常用的输入方式(例如鼠标、触摸板、键盘)上分别对应的正确的交互规则。设计师和开发者应保证在当前输入方式下应用能够以正确的、符合用户习惯的交互规则进行响应。通常情况下,系统已经做好了这些事情,开发者只需正确调用。如果您的操作比较特别,您需要考虑多端上的交互归一,以确保用户体验的一致。
更多交互归一的设计内容,详见:[人机交互](interaction-basics.md) 更多交互归一的设计内容,详见:[人机交互](man-machine-interaction.md)
### 视觉参数化 ### 视觉参数化
通过参数,方便的调整各端的视觉,使得各端具备该设备特有的风格。在OpenHarmony中,边距、圆角、阴影、字体大小等,都可以通过参数来进行调整。 通过参数,方便的调整各端的视觉,使得各端具备该设备特有的风格。在OpenHarmony中,边距、圆角、阴影、字体大小等,都可以通过参数来进行调整。
![zh-cn_image_0000001317085757](figures/zh-cn_image_0000001317085757.png) ![画板copy](figures/画板copy.png)
更多视觉参数化的设计内容,详见:[视觉风格](visual-style-basics.md) 更多视觉参数化的设计内容,详见:[视觉风格](visual-style.md)
### 多态控件 ### 多态控件
...@@ -91,6 +91,6 @@ OpenHarmony默认提供支持多设备的控件,开发者可以直接使用并 ...@@ -91,6 +91,6 @@ OpenHarmony默认提供支持多设备的控件,开发者可以直接使用并
| **以触控为主** | **以键鼠操作为主** | | **以触控为主** | **以键鼠操作为主** |
| -------- | -------- | | -------- | -------- |
| 下拉刷新 | 界面上提供“刷新”图标或适配F5快捷键 | | 下拉刷新 | 界面上提供“刷新”图标或适配F5快捷键 |
| 滑动多选 | 鼠标&nbsp;框选 | | 滑动多选 | 鼠标框选 |
| 下拉关闭 | 界面上提供“关闭”图标 | | 下拉关闭 | 界面上提供“关闭”图标 |
| 长按浮起拖拽 | 鼠标直接拖拽 | | 长按浮起拖拽 | 鼠标直接拖拽 |
# 资源 # 资源
为方便UX设计师以及开发者使用[分层参数](visual-style-basics.md),本文特提供 [OpenHarmony_系统资源分层设计表_V1.0.xlsm](OpenHarmony_系统资源分层设计表_V1.0.xlsm)
为方便UX设计师以及开发者参考使用,本文特提供:
- [分层参数](visual-basics.md)的场景、id、参数详细对照表,[OpenHarmony_系统资源分层设计表_V1.0.xlsm](OpenHarmony_系统资源分层设计表_V1.0.xlsm)
- 符合规范的[设计交付件](design-delivery.md)样例,[OpenHarmony_天气应用UX设计交付件_V1.0.zip](OpenHarmony_天气应用UX设计交付件_V1.0.zip)
系统资源分层设计表列出了当前OpenHarmony中可用系统资源id及其在不同类型设备上的取值,它由六张子表组成,各个子表的含义如下所示。 系统资源分层设计表列出了当前OpenHarmony中可用系统资源id及其在不同类型设备上的取值,它由六张子表组成,各个子表的含义如下所示。
| 表格 | 简介 |
| ------------------ | ------------------------------------------------------------ | | 表格 | 简介 |
| 应用色彩参数 | 在**应用开发**过程中可以使用的**色彩**相关的系统资源。 | | -------- | -------- |
| 应用圆角参数 | 在**应用开发**过程中可以使用的**圆角**相关的系统资源。 | | 应用色彩参数 | 在**应用开发**过程中可以使用的**色彩**相关的系统资源。 |
| 应用字体参数 | 在**应用开发**过程中可以使用的**字体**相关的系统资源。 | | 应用圆角参数 | 在**应用开发**过程中可以使用的**圆角**相关的系统资源。 |
| 应用间距参数 | 在**应用开发**过程中可以使用的**间距**相关的系统资源。 | | 应用字体参数 | 在**应用开发**过程中可以使用的**字体**相关的系统资源。 |
| 服务卡片参数 | 在**服务卡片开发**过程中可以使用的系统资源。 | | 应用间距参数 | 在**应用开发**过程中可以使用的**间距**相关的系统资源。 |
| 服务卡片参数 | 在**服务卡片开发**过程中可以使用的系统资源。 |
| 不透明度数值速查表 | 用于将不透明度在**百分比表示形式****十六进制表示形式**之间快速转换的速查表。 | | 不透明度数值速查表 | 用于将不透明度在**百分比表示形式****十六进制表示形式**之间快速转换的速查表。 |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
>
> - 推荐应用相关系统参数仅在应用开发场景中使用,卡片相关系统参数仅在卡片开发场景中使用。 > - 推荐应用相关系统参数仅在应用开发场景中使用,卡片相关系统参数仅在卡片开发场景中使用。
>
> - 同一系统参数在不同类型的设备上有不同的取值,当前仅提供了系统参数在默认设备上的取值,后续会针对不同设备类型做补充。 > - 同一系统参数在不同类型的设备上有不同的取值,当前仅提供了系统参数在默认设备上的取值,后续会针对不同设备类型做补充。
> - 颜色可以用“RGB”或“ARGB”形式表示,采用“RGB”表示的颜色,完全不透明;采用“ARGB”表示的颜色,其不透明度由“A”(Alpha通道)确定。如“#7FFF0000”代表不透明度为50%的红色,“#FFFF0000”和“#FF0000”都表示不透明度为100%(即完全不透明)的红色。 >
\ No newline at end of file > - 颜色可以用“RGB”或“ARGB”形式表示,采用“RGB”表示的颜色,完全不透明;采用“ARGB”表示的颜色,其不透明度由“A”(Alpha通道)确定。如“\#7FFF0000”代表不透明度为50%的红色,“\#FFFF0000”和“\#FF0000”都表示不透明度为100%(即完全不透明)的红色。
# 响应式布局 # 响应式布局
当基本的自适应布局无法满足多终端上屏幕的体验要求时,我们需要针对不同终端的屏幕特点,设定容器与栅格的关系达到响应式的布局。通常响应式布局能根据栅格断点变化进行有级变化。 当基本的自适应布局无法满足多终端上屏幕的体验要求时,我们需要针对不同终端的屏幕特点,设定容器与栅格的关系达到响应式的布局。通常响应式布局能根据栅格断点变化进行有级变化。
## 栅格断点系统 ## 栅格断点系统
根据设备的水平宽度,OpenHarmony提供了断点系统,覆盖超小、小、中、大 四种屏幕类型,并结合栅格系统默认提供了对应 Column 的数量关系。不同的设备根据自身屏幕水平宽度,在不同的断点范围,系统将自动匹配不同数量的栅格。应用也可针对具体界面自定义栅格。 根据设备的水平宽度,OpenHarmony提供了断点系统,覆盖超小、小、中、大 四种屏幕类型,并结合栅格系统默认提供了对应 Column 的数量关系。不同的设备根据自身屏幕水平宽度,在不同的断点范围,系统将自动匹配不同数量的栅格。应用也可针对具体界面自定义栅格。
![zh-cn_image_0000001305864477](figures/zh-cn_image_0000001305864477.png) ![删格](figures/删格.png)
栅格断点系统与日常使用的设备屏幕类型有一定的对应关系,例如:超小对应智能穿戴设备,小对应默认设备,中对应平板,大对应智慧屏与PC。设计师可面向希望运行的设备进行所属屏幕类型的适配。 栅格断点系统与日常使用的设备屏幕类型有一定的对应关系,例如:超小对应智能穿戴设备,小对应默认设备,中对应平板,大对应智慧屏与PC。设计师可面向希望运行的设备进行所属屏幕类型的适配。
随着智能设备种类的增加,越来越多产品在四种屏幕类型上具备不同的交互能力,如支持触摸的运动相机(小)、仅支持遥杆的手持云台(小-中)、不可移动的智能台灯(中-大)等,需结合具体设备交互进行对应设计,不可一概而论。 随着智能设备种类的增加,越来越多产品在四种屏幕类型上具备不同的交互能力,如支持触摸的运动相机(小)、仅支持遥杆的手持云台(小-中)、不可移动的智能台灯(中-大)等,需结合具体设备交互进行对应设计,不可一概而论。
## 缩进布局 ## 缩进布局
为了在宽屏上内容显示有更好的效果,在不同宽度的设备上进行不同缩进效果。 为了在宽屏上内容显示有更好的效果,在不同宽度的设备上进行不同缩进效果。
![zh-cn_image_0000001264774952](figures/zh-cn_image_0000001264774952.gif) ![缩进布局](figures/缩进布局.gif)
缩进适用于,因宽度明显变大,内容拉伸以后导致屏幕空白内容超过50%,或文本内容过长(每行大于30字),但没有上下级界面可供同时展示或上下级界面不适合同时显示的场景。 缩进适用于,因宽度明显变大,内容拉伸以后导致屏幕空白内容超过50%,或文本内容过长(每行大于30字),但没有上下级界面可供同时展示或上下级界面不适合同时显示的场景。
OpenHarmony提供的默认实现为,当栅格为8column或12column时可以响应6column和8column的缩进布局。 OpenHarmony提供的默认实现为,当栅格为8column或12column时可以响应6column和8column的缩进布局。
## 挪移布局 ## 挪移布局
利用屏幕的宽度优势,将原先的上下布局切换成左右布局。 利用屏幕的宽度优势,将原先的上下布局切换成左右布局。
例如,上下排布的插画和文字,横屏后左右排布。 例如,上下排布的插画和文字,横屏后左右排布。
![zh-cn_image_0000001264296340](figures/zh-cn_image_0000001264296340.gif) ![挪移布局](figures/挪移布局.gif)
挪移布局适用于横竖屏切换,以及类似的宽高比明显变化(大于200%)同时希望保证内容完整的场景。 挪移布局适用于横竖屏切换,以及类似的宽高比明显变化(大于200%)同时希望保证内容完整的场景。
## 重复布局 ## 重复布局
利用屏幕的宽度优势,将相同属性的组件横向并列排布。 利用屏幕的宽度优势,将相同属性的组件横向并列排布。
![zh-cn_image_0000001306203573](figures/zh-cn_image_0000001306203573.gif) ![重复布局](figures/重复布局.gif)
重复布局适用于对宽高比敏感的图片和及组合内容,当内容缩放以后导致原图放大超过150%的场景。 重复布局适用于对宽高比敏感的图片和及组合内容,当内容缩放以后导致原图放大超过150%的场景。
OpenHarmony栅格系统提供的分栏实现为,当栅格为8column或12column时可以将默认4栅格的页面整体进行重复布局。 OpenHarmony栅格系统提供的分栏实现为,当栅格为8column或12column时可以将默认4栅格的页面整体进行重复布局。
响应式布局对应OpenHarmony系统提供的布局能力中的[栅格断点系统](grid-breakpoint.md)[媒体查询](media-query.md),详见本文 “响应式布局”。 响应式布局对应OpenHarmony系统提供的布局能力中的栅格断点系统和媒体查询,详见本文 “[响应式布局](responsive-layout.md)”相关介绍。
# 一多能力的功能开发介绍 # 功能开发的一多能力介绍
应用开发至少包含两部分工作:UI页面开发和底层功能开发(部分需要联网的应用还会涉及服务端开发)。如“打开设备NFC”功能,除了开发页面,还需要调用系统API开启NFC。前面章节主要介绍了如何解决页面适配的问题,本章节主要介绍应用如何解决设备系统能力差异的兼容问题。 应用开发至少包含两部分工作:UI页面开发和底层功能开发(部分需要联网的应用还会涉及服务端开发)。如“打开设备NFC”功能,除了开发页面,还需要调用系统API开启NFC。前面章节主要介绍了如何解决页面适配的问题,本章节主要介绍应用如何解决设备系统能力差异的兼容问题。
我们以一个简单例子说明:一个具有NFC功能的应用,如何兼容运行在有NFC和无NFC系统能力的设备上。 我们以一个简单例子说明:一个具有NFC功能的应用,如何兼容运行在有NFC和无NFC系统能力的设备上。
应用从开发到用户可以使用,一般要经历几个阶段:应用分发和下载-&gt;应用安装-&gt;应用运行,要解决上面提到的兼容问题,一般有如下几种解决思路: 应用从开发到用户可以使用,一般要经历几个阶段:应用分发和下载-&gt;应用安装-&gt;应用运行,要解决上面提到的兼容问题,一般有如下几种解决思路:
1. 分发和下载:有NFC设备的用户才能在应用市场可见该应用,提供用户下载能力。 1. 分发和下载:有NFC设备的用户才能在应用市场可见该应用,提供用户下载能力。
2. 安装:有NFC能力的设备才允许安装该应用。 2. 安装:有NFC能力的设备才允许安装该应用。
3. 运行:在运行阶段通过动态判断方式,在NFC设备上功能运行正常,在无NFC设备上运行不发生Crash。 3. 运行:在运行阶段通过动态判断方式,在NFC设备上功能运行正常,在无NFC设备上运行不发生Crash。
所以,对应的解决方案就有: 所以,对应的解决方案就有:
1. 在分发阶段,核心分发逻辑:上架的应用使用的系统能力是设备系统能力的子集。满足这个条件,用户才能在应用市场看到该应用。 1. 在分发阶段,核心分发逻辑:上架的应用使用的系统能力是设备系统能力的子集。满足这个条件,用户才能在应用市场看到该应用。
2. 在安装阶段,核心安装逻辑:安装的应用调用的系统能力是设备系统能力的子集。满足这个条件,用户才能安装该应用。 2. 在安装阶段,核心安装逻辑:安装的应用调用的系统能力是设备系统能力的子集。满足这个条件,用户才能安装该应用。
3. If/Else的动态逻辑判断。伪代码简单示例如下: 3. If/Else的动态逻辑判断。伪代码简单示例如下:
``` ```
if (该设备有系统能力1) { if (该设备有系统能力1) {
运行系统能力1相关的代码; 运行系统能力1相关的代码;
} else { } else {
提示用户该设备不支持; 提示用户该设备不支持;
} }
``` ```
OpenHarmony支持的设备类型分为两大类: OpenHarmony支持的设备类型分为两大类:
1. 典型设备类型,如默认设备、平板等。系统已经定义好了这些设备的系统能力集合,对应用开发者来说,只需要感知在IDE中创建Module时设备类型的选择,如下图所示: 1. 典型设备类型,如默认设备、平板等。系统已经定义好了这些设备的系统能力集合,对应用开发者来说,只需要感知在IDE中创建Module时设备类型的选择,如下图所示:
![zh-cn_image_0000001267573986](figures/zh-cn_image_0000001267573986.png) ![zh-cn_image_0000001267573986](figures/zh-cn_image_0000001267573986.png)
或者module.json文件中的deviceTypes,如下图所示: 或者module.json文件中的deviceTypes,如下图所示:
![zh-cn_image_0000001266934142](figures/zh-cn_image_0000001266934142.png) ![zh-cn_image_0000001266934142](figures/zh-cn_image_0000001266934142.png)
简单来说,应用开发者基于典型设备类型的应用开发,仅需选择设备类型,系统完成分发或者安装的匹配逻辑。 简单来说,应用开发者基于典型设备类型的应用开发,仅需选择设备类型,系统完成分发或者安装的匹配逻辑。
2. 厂家自定义设备类型。由于厂家提供的系统能力千差万别,OpenHarmony允许厂家自己自定义设备的系统能力,但需要通过标准的格式形成一个ID,称为PCID(产品兼容性标识,Product Compatibility ID),并对外发布这个PCID,一般通过设备认证中心发布。应用开发者如果希望应用可以分发和安装到厂家自定义的设备上,就必须拿到对应的自定义设备PCID,否则就无法声明应用使用或调用的系统能力集(也是通过一个ID表示,称为RPCID,英文全名:Required Product Compatibility ID,中文名:要求的产品兼容性标识)。 2. 厂家自定义设备类型。由于厂家提供的系统能力千差万别,OpenHarmony允许厂家自己自定义设备的系统能力,但需要通过标准的格式形成一个ID,称为PCID(产品兼容性标识,Product Compatibility ID),并对外发布这个PCID,一般通过设备认证中心发布。应用开发者如果希望应用可以分发和安装到厂家自定义的设备上,就必须拿到对应的自定义设备PCID,否则就无法声明应用使用或调用的系统能力集(也是通过一个ID表示,称为RPCID,英文全名:Required Product Compatibility ID,中文名:要求的产品兼容性标识)。
鉴于当前OpenHarmony版本还不具备设备认证中心,本章节仅讨论典型设备类型下多设备应用开发的场景。 鉴于当前OpenHarmony版本还不具备设备认证中心,本章节仅讨论典型设备类型下多设备应用开发的场景。
## 编码时的API联想 ## 编码时的API联想
IDE中提供了API的联想功能,方便开发者使用系统能力。当开发者选择多个设备类型时,API的联想范围就是选择类型设备提供的API的并集,如同时支撑默认设备和平板,API的联想范围就是默认设备和平板支持的API的并集。API的联想效果如下: IDE中提供了API的联想功能,方便开发者使用系统能力。当开发者选择多个设备类型时,API的联想范围就是选择类型设备提供的API的并集,如同时支撑默认设备和平板,API的联想范围就是默认设备和平板支持的API的并集。API的联想效果如下:
![zh-cn_image_0000001267334018](figures/zh-cn_image_0000001267334018.gif) ![Video_20220408101413](figures/Video_20220408101413.gif)
## 动态逻辑判断 ## 动态逻辑判断
开发者可以通过canIUse接口,判断目标设备是否支持某系统能力,进而执行不同的业务逻辑。 开发者可以通过canIUse接口,判断目标设备是否支持某系统能力,进而执行不同的业务逻辑。
``` ```
import geolocation from'@ohos.geolocation'; import geolocation from'@ohos.geolocation';
const isLocationAvailable =canIUse('SystemCapability.Location.Location');
if (isLocationAvailable) { @Entry
console.log('该设备支持位置信息'); @Component
geolocation.getCurrentLocation((location) => { struct Index {
console.log(location.latitude, location.longitude); @State message: string = 'unknown';
}) aboutToAppear() {
} else { if (canIUse('SystemCapability.Location.Location')) {
console.log('该设备不支持位置信息'); geolocation.getCurrentLocation().then((location) => {
} this.message = 'current location: ' + JSON.stringify(location)
``` })
} else {
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** this.message = 'This device does not have the ability to get location.'
> 开发者通过 import 方式导入的模块,若当前设备不支持该模块,import 的结果为 undefined。故开发者在使用 API 时,需要判断其是否存在。 }
}
build() {
Row() {
Text(this.message).fontSize(24)
}
.justifyContent(FlexAlign.Center)
.width('100%')
.height('100%')
}
}
```
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 开发者通过 import 方式导入的模块,若当前设备不支持该模块,import 的结果为 undefined。故开发者在使用 API 时,需要判断其是否存在。
# 常见问题
## 如何查询设备类型
设备类型分为default(默认设备)、tablet、tv、wearable等,有多种查询设备类型的方式。
1. 通过命令行的方式查询设备类型。
通过命令行查询指定系统参数(const.build.characteristics)进而确定设备类型,详见[系统参数介绍](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/subsystems/subsys-boot-init-sysparam.md)
```shell
# 方法一
hdc shell param get "const.build.characteristics"
# 方法二
hdc shell cat /etc/param/ohos.para | grep const.build.characteristic
```
2. 在应用开发过程中查询设备类型。
- 通过js接口查询指定系统参数(const.build.characteristics)进而确定设备类型,详见[系统属性](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-system-parameter.md)
```typescript
import parameter from '@ohos.systemparameter'
@Entry
@Component
struct GetDeviceTypeSample {
@State deviceType: string = 'unknown'
aboutToAppear() {
try {
this.deviceType = parameter.getSync("const.build.characteristics")
} catch(e) {
console.log("getSync unexpected error: " + e)
}
}
build() {
Column() {
Text(this.deviceType).fontSize(24)
}
.width('100%')
.height('100%')
}
}
```
- 通过deviceInfo查询设备类型,deviceInfo中各个字段的含义请参考[设备信息](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-device-info.md)
```typescript
import deviceInfo from'@ohos.deviceInfo'
@Entry
@Component
struct GetDeviceTypeSample {
@State deviceType:string='unknown'
aboutToAppear() {
this.deviceType= deviceInfo.deviceType
}
build() {
Column() {
Text(this.deviceType).fontSize(24)
}
.width('100%')
.height('100%')
}
}
```
## 如何在不同设备上为Ability配置不同的启动模式
应用由一个或多个Ability组成,Ability支持单实例、多实例和指定实例3种[启动模式](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ability/stage-ability.md#%E5%90%AF%E5%8A%A8%E6%A8%A1%E5%BC%8F),启动模式可以在[配置文件(module.json5)](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/stage-structure.md)中通过launchType字段配置。启动模式对应Ability被启动时的行为,对启动模式的详细说明如下:
| 启动模式 | 描述 | 说明 |
| -------- | -------- | -------- |
| standard | 多实例 | 每次startAbility都会启动一个新的实例。 |
| singleton | 单实例 | 系统中最多只可以存在一个实例,startAbility时,如果系统中已存在相应的Ability实例,则复用该实例。 |
| specified | 指定实例 | 运行时由Ability内部业务决定是否创建多实例。 |
默认设备屏幕尺寸较小,采用standard启动模式不仅无法给用户提供便利,反而可能消耗更多系统资源,故通常采用singleton启动模式。平板屏幕尺寸较大且可能支持自由窗口,对于文档编辑、网页浏览等场景,使用standard启动模式可以提升用户体验。
本文中将默认设备和平板等归为同一泛类,推荐同一泛类的设备共用HAP包,同时本文也介绍了如何通过自适应布局能力和响应式布局能力开发出适配不同设备的页面。这里将补充介绍,如何实现Ability在不同设备上以不同的模式启动。
launchType字段配置为specified时,系统会根据AbilityStage的onAcceptWant的返回值确定是否创建新的实例。对于同一个应用,如果key已经存在,则复用该key对应的Ability,如果key不存在则新创建Ability。
可以将配置文件中的launchType字段配置为specified,同时在应用中加入如下代码以实现目标效果。
- 非平板设备,直接将设备类型作为key,保证每次启动的key相同,即以单实例模式运行。
- 平板设备,将设备类型与毫秒级时间戳叠加作为key,保证每次启动的key不同,即以多实例模式运行。
```typescript
// MyAbilityStage.ts
import AbilityStage from "@ohos.application.AbilityStage"
import deviceInfo from'@ohos.deviceInfo'
export default class MyAbilityStage extends AbilityStage {
...
private generateKey(): string {
// 如果是平板,则将设备类型和毫秒级时间戳叠加作为key,保证每次启动的key都不同
if (deviceInfo.deviceType === 'tablet') {
return deviceInfo.deviceType + (new Date()).valueOf()
}
// 如果不是平板,直接以设备类型作为key,每次启动的key相同
return deviceInfo.deviceType
}
onAcceptWant(want) {
return this.generateKey()
}
}
```
## 如何开启自由窗口
开发板上的自由窗口功能默认是关闭的,可以通过如下方式开启自由窗口功能。
```shell
# 取出开发板中的窗口配置文件,并将文件中的<decor enable="false"></decor>修改为<decor enable="true"></decor>
hdc file recv system/etc/window/resources/window_manager_config.xml ./
# 以可读写的模式重新挂载根目录,并更新开发板中的配置文件
hdc shell mount -o rw,remount /
hdc file send window_manager_config.xml system/etc/window/resources/window_manager_config.xml
# 重启开发板,配置生效
hdc shell reboot
```
开发板屏幕较小,通过手指操作窗口较为不便,建议外接鼠标进行操作。
- 鼠标在应用顶部悬停,即可召唤出窗口工具栏。
- 点击窗口工具栏中的缩放按钮(从左到右第二个),即可让应用以自由窗口的模式显示。
- 在自由窗口模式下,可以通过拖动应用窗口的边框或顶角,改变窗口尺寸同时触发应用显示刷新。
在调整窗口尺寸的过程中,窗口尺寸可能超出屏幕尺寸。此时应用显示正常,但受限于屏幕尺寸,在屏幕中只能看到应用部分区域的显示。可以通过移动窗口位置,查看应用其它区域的显示。
| 窗口操作按钮 | 悬浮窗口显示 | 调整窗口尺寸及位置查看不同的效果 |
| -------- | -------- | -------- |
| ![img2](figures/img2.png) | ![img3](figures/img3.png) | ![img4](figures/img4.png) |
## 如何限制自由窗口的尺寸调节范围
自适应布局可以保证窗口尺寸在一定范围内变化时,页面的显示是正常的。当窗口尺寸变化较大时,就需要额外借助响应式布局能力(如断点等)调整页面结构以保证显示正常。通常每个断点都需要开发者精心适配以获得最佳的显示效果,考虑到设计及开发成本等实际因素的限制,应用不可能适配从零到正无穷的所有窗口宽度。
不同设备或不同设备状态,系统默认的自由窗口尺寸的调节范围可能不同。开发者可以在[应用配置文件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/stage-structure.md)中限制应用中各个Ability的自由窗口尺寸调节范围,配置文件中影响自由窗口尺寸调节范围的字段如下表所示。
| 配置文件字段 | 数据类型 | 描述 |
| -------- | -------- | -------- |
| minWindowWidth | 数值 | 标识该ability支持的最小的窗口宽度,&nbsp;宽度单位为vp。 |
| minWindowHeight | 数值 | 标识该ability支持的最小的窗口高度,&nbsp;高度单位为vp。 |
| maxWindowWidth | 数值 | 标识该ability支持的最大的窗口宽度,宽度单位为vp。 |
| maxWindowHeight | 数值 | 标识该ability支持的最大的窗口高度,&nbsp;高度单位为vp。 |
| minWindowRatio | 数值 | 标识该ability支持的最小的宽高比。 |
| maxWindowRatio | 数值 | 标识该ability支持的最大的宽高比。 |
如下所示,通过配置文件分别限制自由窗口的最大和最小尺寸。
```
{
"module": {
...
"abilities": [
{
...
"minWindowWidth": 320,
"minWindowHeight": 240,
"maxWindowWidth": 1440,
"maxWindowHeight": 900,
"minWindowRatio": 0.5,
"maxWindowRatio": 2,
}
]
}
}
```
# 常见问题
## 如何查询设备类型
设备类型分为default(默认设备)、tablet、tv、wearable等,有多种查询设备类型的方式。
1. 通过命令行的方式查询设备类型。
通过命令行查询指定系统参数(const.build.characteristics)进而确定设备类型,详见[系统参数介绍](../../../device-dev/subsystems/subsys-boot-init-sysparam.md)
```bash
# 方法一
hdc shell param get "const.build.characteristics"
# 方法二
hdc shell cat /etc/param/ohos.para | grep const.build.characteristic
```
2. 在应用开发过程中查询设备类型。
- 通过js接口查询指定系统参数(const.build.characteristics)进而确定设备类型,详见[系统属性](../../reference/apis/js-apis-system-parameter.md)
```ts
import parameter from '@ohos.systemParameter'
@Entry
@Component
struct GetDeviceTypeSample {
@State deviceType: string = 'unknown';
aboutToAppear() {
try {
this.deviceType = parameter.getSync("const.build.characteristics");
} catch(e) {
console.log("getSync unexpected error: " + e);
}
}
build() {
Column() {
Text(this.deviceType).fontSize(24)
}
.width('100%')
.height('100%')
}
}
```
- 通过deviceInfo查询设备类型,deviceInfo中各个字段的含义请参考[设备信息](../../reference/apis/js-apis-device-info.md)
```ts
import deviceInfo from'@ohos.deviceInfo'
@Entry
@Component
struct GetDeviceTypeSample {
@State deviceType:string='unknown';
aboutToAppear() {
this.deviceType= deviceInfo.deviceType;
}
build() {
Column() {
Text(this.deviceType).fontSize()
}
.width('100%')
.height('100%')
}
}
```
## 如何查询屏幕/窗口尺寸
在应用开发过程中,为了在不同的设备上取得更好的显示效果,开发者可能需要查询屏幕尺寸或应用显示窗口尺寸。
- 通过display查询显示设备的属性(包括屏幕宽、高和屏幕密度等),详见[屏幕属性](../../reference/apis/js-apis-display.md)
```ts
private aboutToAppear() {
display.getDefaultDisplay()
.then((displayInfo) => {
console.info('Display width: '+ displayInfo.width);
console.info('Display height: '+ displayInfo.height);
console.info('Display density: '+ displayInfo.densityDPI);
})
.catch((error) => {
console.error('Failed to obtain the default display size. Cause: '+JSON.stringify(error));
})
}
```
- 通过window.getTopWindow获取应用窗口,进而查询应用窗口的宽高等,详见[窗口](../../reference/apis/js-apis-window.md)
注意必须在应用创建窗口后才可以拿到窗口对象,window.getTopWindow依赖AbilityContext作为入参,可以在MainAbility中通过this.context拿到AbilityContext对象,详见[Ability开发指导](../../ability/stage-ability.md)。可以在MainAbility的onCreate生命周期中拿到窗口尺寸,如下所示。
```ts
onCreate(want, launchParam) {
window.getTopWindow(this.context)
.then((windowClass) => { return windowClass.getProperties(); })
.then((topWindow) => {
console.info('Window width: '+ topWindow.windowRect.width);
console.info('Window height: '+ topWindow.windowRect.height);
})
.catch((error)=>{
console.error('Failed to obtain the window size. Cause: '+JSON.stringify(error));
})
}
```
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 通过窗口尺寸调整显示更加“可靠”,因为顶部状态栏、三键导航等可能占据部分屏幕空间,另外部分设备上的应用可能以窗口形式显示。
# 前言
本文介绍了“一次开发,多端部署”(后文中简称为“一多”)的定义、目标等,同时从UX设计、工程管理、页面开发、功能开发等角度,端到端的给出了指导,帮助开发者快速开发出适配多种类型设备的应用。在应用开发前,开发者应尽可能全面考虑应用支持多设备的情况,避免在后期加入新的类型设备时对应用架构进行大幅调整。
## 本文面向的读者
本文适合开发OpenHarmony应用的UX设计师及开发人员。当然,也欢迎任何对“一多”感兴趣的读者阅读本文,相信读者们都可以从中获益。
推荐尽量按照章节顺序阅读本文。如果时间有限,按照角色区分,建议至少阅读如下章节:
- UX设计师:第2章、第3章、第4章。
- 开发人员:第2章、第3章、第5章、第6章、第7章。
## 章节概要
应用在需求明确后,开发过程大致分为:应用设计(包含界面UX设计、业务功能设计)-&gt;工程设计和创建-&gt;功能代码实现。本指导也是基于这个流程进行的内容编排。
本文档各章节简介如下:
- 第1章前言说明本文的目的以及本文面向的读者,指引读者更好地阅读。
- 第2章[简介](introduction.md)简短介绍了“一多”的背景、定义、目标、以及用于指导后续开发的一些基础知识。
- 第3章[从一个例子开始](start-with-a-example.md)通过示例介绍“一多”应用的开发过程,让读者对“一多”有个直观认识。
- 第4章[应用UX设计](design-principles.md)介绍了应用UX设计理念。主要阐述了应用设计之初UX设计的原则和要点。该章节主要面向应用的UX设计师。
UX设计原则应该考虑多设备的“差异性” 、“一致性”、“灵活性”和“兼容性”。
UX设计要点则从6个方面阐述如何进行多设备应用设计,分别是“自适应应用架构”、“响应式界面布局”、“交互归一”、“视觉参数化”、“多态控件”和“针对性优化”。
最后,给出设计自检表,用于检查应用UX设计是否合理 。
- 第5章[工程管理](ide-using.md)介绍了从工程角度如何开始开发应用,让读者可以直接上手创建多设备应用的工程,是后面学习“一多”能力的上手基础。
- 第6章[页面开发的一多能力介绍](page-development-intro.md)和第7章[功能开发的一多能力介绍](development-intro.md)介绍了OpenHarmony提供的“一多”能力,其中每个能力都提供了代码示例和UX效果,让读者可以快速学习“一多”能力。
- 第8章[案例应用](case.md)阐述了从应用设计到开发这一过程中如何实践前面章节介绍的设计思路或“一多”能力,让读者可以整体掌握“一多”在应用开发过程中的知识。
- 第9章[常见问题](faq.md)提供了常见的问题(FAQ),方便读者查阅。
本指导在介绍过程中还包括一些“说明”。这些“说明”,表示例外情况或者额外信息的补充。“说明”在文中如下所示:
> **说明:**<br/>此处承载说明内容。
# 栅格断点系统
栅格断点系统定义了不同水平宽度设备对应的Column数量关系,形成了一套断点规则定义。其以水平值作为断点依据,不同的设备根据自身当前水平宽度值在不同断点范围内的情况,显示不同数量的栅格数。
![zh-cn_image_0000001292375365](figures/zh-cn_image_0000001292375365.png)
| 水平宽度&nbsp;(vp) | SizeType类型 | Columns数量 | 默认Margin | 默认Gutter | 典型设备 |
| -------- | -------- | -------- | -------- | -------- | -------- |
| [0,&nbsp;320) | XS | 2 | 12vp | 12vp | 智能穿戴 |
| [320,&nbsp;600) | SM | 4 | 24vp | 24vp | 默认设备 |
| [600,&nbsp;840) | MD | 8 | 32vp | 24vp | 智慧屏、竖屏状态的平板等 |
| [840,&nbsp;+∞) | LG | 12 | 48vp | 24vp | 车机、横屏状态的平板等 |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 请访问[栅格布局](../../ui/ui-ts-layout-grid-container.md),了解栅格布局更详细的介绍。
>
> - 声明式开发范式,请访问[GridContainer组件](../../reference/arkui-ts/ts-container-gridcontainer.md)及[栅格设置](../../reference/arkui-ts/ts-universal-attributes-grid.md),了解栅格布局的详细用法。
>
> - 类Web开发范式,通过[grid-container](../../reference/arkui-js/js-components-grid-container.md)、 [grid-row](../../reference/arkui-js/js-components-grid-row.md)、[grid-col](../../reference/arkui-js/js-components-grid-col.md)组件来实现栅格布局,请访问相应的链接了解其详细用法。
## 示例
- 默认设备屏幕宽度为360vp,属于SizeType.SM类型设备,Column数量为4。根据示例代码配置,在该设备上,Left占1列,Center占2列,Right占1列。
- 平板屏幕宽度为1024vp,属于SizeType.LG类型设备,Column数量为12。根据示例代码配置,在该设备上,Left占2列,Center占7列,Right占3列。
![zh-cn_image_0000001245456434](figures/zh-cn_image_0000001245456434.jpg)
```ts
@Entry
@Component
struct GridContainerExample1 {
build(){
GridContainer() {
Row({}) {
Row() {
Text('Left').fontSize(25)
}
.useSizeType({
xs: { span:1, offset:0 }, sm: { span:1, offset:0 },
md: { span:1, offset:0 }, lg: { span:2, offset:0 }
})
.height("100%")
.backgroundColor(0x66bbb2cb)
Row() {
Text('Center').fontSize(25)
}
.useSizeType({
xs: { span:1, offset:0 }, sm: { span:2, offset:1 },
md: { span:5, offset:1 }, lg: { span:7, offset:2 }
})
.height("100%")
.backgroundColor(0x66b6c5d1)
Row() {
Text('Right').fontSize(25)
}
.useSizeType({
xs: { span:1, offset:0 }, sm: { span:1, offset:3 },
md: { span:2, offset:6 }, lg: { span:3, offset:9 }
})
.height("100%")
.backgroundColor(0x66bbb2cb)
}
.height(200)
}
.backgroundColor(0xf1f3f5)
.margin({ top:10 })
}
}
```
## 相关实例
针对栅格断点系统开发,有以下相关实例可供参考:
- [`Weather`:一多天气(eTS)(API9)](https://gitee.com/openharmony/applications_app_samples/tree/master/MultiDeviceAppDev/Weather)
\ No newline at end of file
# IDE使用 # 工程管理
DevEco Studio的基本使用,请参考[DevEco Studio使用指南](../../quick-start/deveco-studio-user-guide-for-openharmony.md)。本章主要介绍如何使用DevEco Studio进行多设备应用开发。 DevEco Studio的基本使用,请参考[DevEco Studio使用指南](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/deveco-studio-user-guide-for-openharmony.md)。本章主要介绍如何使用DevEco Studio进行多设备应用开发。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 本章的内容基于[DevEco Studio 3.0 Beta3](https://developer.harmonyos.com/cn/develop/deveco-studio#download_beta_openharmony)版本进行介绍,如您使用DevEco Studio其它版本,可能存在文档与产品功能界面、操作不一致的情况,请以实际功能界面为准。 > 本章的内容基于[DevEco Studio 3.0 Beta3](https://developer.harmonyos.com/cn/develop/deveco-studio#download_beta_openharmony)版本进行介绍,如您使用DevEco Studio其它版本,可能存在文档与产品功能界面、操作不一致的情况,请以实际功能界面为准。
## 工程创建 ## 工程创建
参考[创建OpenHarmony工程](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-create-new-project-0000001263280423),先创建出最基本的项目工程。可以看到DevEco Studio创建出的默认工程,仅包含一个的entry类型的模块。 参考[创建OpenHarmony工程](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-create-new-project-0000001263280423),先创建出最基本的项目工程。可以看到DevEco Studio创建出的默认工程,仅包含一个的entry类型的模块。
![zh-cn_image_0000001267274204](figures/zh-cn_image_0000001267274204.jpg) ![zh-cn_image_0000001267274204](figures/zh-cn_image_0000001267274204.jpg)
而在本文“[工程结构](introduction.md#部署模型)”小节中,推荐开发者采用common、features、product三层工程结构,这样在一个应用工程内可以更容易、清晰地管理多个设备的模块。工程结构示例如下所示: 如果直接使用如下所示的平级目录进行模块管理,工程逻辑结构较混乱且模块间的依赖关系不够清晰,不利于开发及后期维护。
``` ```
/application /application
├── common # 公共特性目录 ├── common
├── feature1
├── features # 功能模块目录 ├── feature2
│ ├── feature1 # 子功能 ├── featureN
│ ├── feature2 # 子功能2 ├── wearable
│ └── ... # 子功能n ├── default
└── productN
└── product # 产品层目录 ```
├── wearable # 智能穿戴泛类目录
├── default # 默认设备泛类目录 更推荐使用本文[部署模型](introduction.md#部署模型)小节中介绍的common、features、product三层工程结构。工程结构示例如下所示:
└── ...
```
```
当然开发者也可以使用平级的目录进行模块管理,只是看上去会显得有点“杂乱”,工程结构示例如下所示: /application
├── common # 公共特性目录
``` ├── features # 功能模块目录
/application │ ├── feature1 # 子功能
├── common │ ├── feature2 # 子功能2
├── feature1 │ └── ... # 子功能n
├── feature2
├── featureN └── product # 产品层目录
├── wearable ├── wearable # 智能穿戴泛类目录
├── default ├── default # 默认设备泛类目录
└── productN └── ...
``` ```
接下来将依次介绍如何新建Module、修改配置文件以及调整目录,以实现“一多”推荐的“三层工程结构”。
## 新建Module
参考[开发OpenHarmony npm包](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-development-npm-package-0000001222578434),新建三个npm模块,分别命名为common、feature1、feature2。参考[添加/删除Module](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-adding-deleting-module-0000001218760594),新建一个entry类型的模块,假设命名为“wearable”(仅仅为了说明某一类产品)。示例如下: ## 新建Module
![zh-cn_image_0000001315434285](figures/zh-cn_image_0000001315434285.png) 参考[开发OpenHarmony npm包](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-development-npm-package-0000001222578434),新建三个npm模块,分别命名为common、feature1、feature2。参考[添加/删除Module](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-adding-deleting-module-0000001218760594),新建一个entry类型的模块,假设命名为“wearable”(仅仅为了说明某一类产品)。示例如下:
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** ![zh-cn_image_0000001315434285](figures/zh-cn_image_0000001315434285.png)
> - 在一个工程中同一个设备类型只支持一个Entry类型的模块。
> > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 当前的DevEco Studio(3.0 Beta3版本)在创建工程时,设备类型仅能选择phone和tablet,默认该模块已经选择了entry类型,那么在创建wearable这个模块,只能选择feature类型。 > - 在一个工程中同一个设备类型只支持一个Entry类型的模块。
> >
> - 在下一个小节,我们将介绍如何修改Module的配置,包括Module的类型以及其支持的设备类型等。 > - 当前的DevEco Studio(3.0 Beta3版本)在创建工程时,设备类型仅能选择phone和tablet,默认该模块已经选择了entry类型,那么在创建wearable这个模块,只能选择feature类型。
>
> - 在下一个小节,我们将介绍如何修改Module的配置,包括Module的类型以及其支持的设备类型等。
## 修改Module配置
## 修改Module配置
### 修改Module名称
修改创建工程时默认的entry模块名称。在该模块上点击鼠标右键,依次选择”Refactor -&gt; Rename”,将名称修改为default。 ### 修改Module名称
![zh-cn_image_0000001315914185](figures/zh-cn_image_0000001315914185.jpg) 修改创建工程时默认的entry模块名称。在该模块上点击鼠标右键,依次选择”Refactor -&gt; Rename”,将名称修改为default。
![zh-cn_image_0000001315914185](figures/zh-cn_image_0000001315914185.jpg)
### 修改Module类型及其设备类型
通过修改每个模块中的配置文件(module.json5)对模块进行配置,配置文件中各字段含义详见[配置文件说明](../../quick-start/stage-structure.md) ### 修改Module类型及其设备类型
- 将default模块的deviceTypes配置为["phone", "tablet"],同时将其type字段配置为entry。 通过修改每个模块中的配置文件(module.json5)对模块进行配置,配置文件中各字段含义详见[配置文件说明](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/stage-structure.md)
即default模块编译出的hap包在默认设备和平板上安装和运行。
- 将default模块的deviceTypes配置为["phone", "tablet"],同时将其type字段配置为entry。
![zh-cn_image_0000001267914116](figures/zh-cn_image_0000001267914116.png) 即default模块编译出的hap包在默认设备和平板上安装和运行。
- 将wearable模块的deviceTypes配置为["wearable"],同时将其type字段配置为entry。 ![zh-cn_image_0000001267914116](figures/zh-cn_image_0000001267914116.png)
即wearable模块编译出的hap包仅在智能穿戴设备上安装和运行。
- 将wearable模块的deviceTypes配置为["wearable"],同时将其type字段配置为entry。
![zh-cn_image_0000001267514192](figures/zh-cn_image_0000001267514192.png) 即wearable模块编译出的hap包仅在智能穿戴设备上安装和运行。
![zh-cn_image_0000001267514192](figures/zh-cn_image_0000001267514192.png)
## 调整目录结构
调整目录结构 ## 调整目录结构
在工程根目录(MyApplication)上点击鼠标右键,依次选择“New -&gt; Directory”新建子目录。创建product和features两个子目录。 调整目录结构
![zh-cn_image_0000001266874320](figures/zh-cn_image_0000001266874320.png) 在工程根目录(MyApplication)上点击鼠标右键,依次选择“New -&gt; Directory”新建子目录。创建product和features两个子目录。
用鼠标左键将default目录拖拽到新建的product目录中,在IDE弹出的确认窗口中,点击“Refactor”即可。 ![zh-cn_image_0000001266874320](figures/zh-cn_image_0000001266874320.png)
![zh-cn_image_0000001315714137](figures/zh-cn_image_0000001315714137.jpg) 用鼠标左键将default目录拖拽到新建的product目录中,在IDE弹出的确认窗口中,点击“Refactor”即可。
按照同样的步骤,将wearable目录放到product目录中,将feature1和feature2放到features目录中。 ![zh-cn_image_0000001315714137](figures/zh-cn_image_0000001315714137.jpg)
![zh-cn_image_0000001316914105](figures/zh-cn_image_0000001316914105.png) 按照同样的步骤,将wearable目录放到product目录中,将feature1和feature2放到features目录中。
![zh-cn_image_0000001316914105](figures/zh-cn_image_0000001316914105.png)
## 修改依赖关系
回顾之前小节中关于“工程结构”的介绍,我们推荐在common目录中存放基础公共代码,features目录中存放相对独立的功能模块代码,product目录中存放完全独立的产品代码。这样在product目录中依赖features和common中的公共代码来实现功能,可以最大程度实现代码复用。 ## 修改依赖关系
配置依赖关系可以通过修改模块中的package.json文件。如下图所示,通过修改default模块中的package.json文件,使其可以使用common、feature1和feature2模块中的代码。更多详情参考[配置OpenHarmony npm包依赖](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-development-npm-package-0000001252769386#section89674298391) 回顾之前小节中关于“工程结构”的介绍,我们推荐在common目录中存放基础公共代码,features目录中存放相对独立的功能模块代码,product目录中存放完全独立的产品代码。这样在product目录中依赖features和common中的公共代码来实现功能,可以最大程度实现代码复用。
![zh-cn_image_0000001267274208](figures/zh-cn_image_0000001267274208.png) 配置依赖关系可以通过修改模块中的package.json文件。如下图所示,通过修改default模块中的package.json文件,使其可以使用common、feature1和feature2模块中的代码。更多详情参考[配置OpenHarmony npm包依赖](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-development-npm-package-0000001252769386#section89674298391)
同样的,修改feature1和feature2模块中的package.json文件,使其可以使用common模块中的代码。 ![zh-cn_image_0000001267274208](figures/zh-cn_image_0000001267274208.png)
修改package.json文件后,一定要点击右上角的“Sync Now”,否则改动不会生效! 同样的,修改feature1和feature2模块中的package.json文件,使其可以使用common模块中的代码。
修改package.json文件后,一定要点击右上角的“Sync Now”,否则改动不会生效!
## 引用npm包中的代码
[开发OpenHarmony npm包](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-development-npm-package-0000001252769386)中,仅介绍了如何使用npm包中的页面和资源,本小节以例子的形式补充介绍如何使用npm包中的类和函数。 ## 引用npm包中的代码
示例如下: [开发OpenHarmony npm包](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-development-npm-package-0000001252769386)中,仅介绍了如何使用npm包中的页面和资源,本小节以例子的形式补充介绍如何使用npm包中的类和函数。
- 在common模块中新增ComplexNumber类,用于表征复数(数学概念,由实部和虚部组成),该类包含toString()方法,将复数转换为字符形式。 示例如下:
- 在common模块中新增Add函数,用于计算并返回两个数字的和。 - 在common模块中新增ComplexNumber类,用于表征复数(数学概念,由实部和虚部组成),该类包含toString()方法,将复数转换为字符形式。
- 在default模块中,使用common模块新增的ComplexNumber类和Add函数。 - 在common模块中新增Add函数,用于计算并返回两个数字的和。
1. 在”common/src/main/ets”目录中,按照需要新增文件和自定义类和函数。 - 在default模块中,使用common模块新增的ComplexNumber类和Add函数。
![zh-cn_image_0000001315434289](figures/zh-cn_image_0000001315434289.png)
1. 在”common/src/main/ets”目录中,按照需要新增文件和自定义类和函数。
2. 在”common/index.ets”文件中,申明需要export的类、函数的名称及在当前模块中的位置,否则其它模块无法使用。 ![zh-cn_image_0000001315434289](figures/zh-cn_image_0000001315434289.png)
![zh-cn_image_0000001315914189](figures/zh-cn_image_0000001315914189.png)
2. 在”common/index.ets”文件中,申明需要export的类、函数的名称及在当前模块中的位置,否则其它模块无法使用。
3. 在default模块中import和使用这些类和函数。注意提前在default模块的package.json文件中配置对common模块的依赖关系。 ![zh-cn_image_0000001315914189](figures/zh-cn_image_0000001315914189.png)
![zh-cn_image_0000001267914120](figures/zh-cn_image_0000001267914120.png)
3. 在default模块中import和使用这些类和函数。注意提前在default模块的package.json文件中配置对common模块的依赖关系。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** ![zh-cn_image_0000001267914120](figures/zh-cn_image_0000001267914120.png)
> 如果需要将npm包发布供其他开发者使用,当前npm包可发布到npm官方中心仓和OpenHarmony npm专用仓,具体可参考[发布OpenHarmony npm包](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-development-npm-package-0000001222578434#section663116411397)。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 如果需要将npm包发布供其他开发者使用,当前npm包可发布到npm官方中心仓和OpenHarmony npm专用仓,具体可参考[发布OpenHarmony npm包](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-development-npm-package-0000001222578434#section663116411397)。
## 总结
本章主要介绍了如何实现推荐的工程结构,以便更好的进行多设备应用开发。 ## 总结
关于IDE的基本使用,比如如何进行编译构建、如何签名、如何使用预览器等,[DevEco Studio使用指南](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-deveco-studio-overview-0000001263280421)中已经有非常详尽的介绍,本文不再重复介绍。 本章主要介绍了如何实现推荐的工程结构,以便更好的进行多设备应用开发。
关于IDE的基本使用,比如如何进行编译构建、如何签名、如何使用预览器等,[DevEco Studio使用指南](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-deveco-studio-overview-0000001263280421)中已经有非常详尽的介绍,本文不再重复介绍。
# 交互基础 # 交互基础
在全场景的数字体验中,越来越多类型的智能终端设备分布在用户的日常生活中,可交互的用户界面广泛存在于默认设备、平板、PC、智能穿戴设备、智慧屏、车机、虚拟现实(VR)和增强现实(AR)等设备上。应用可能在多种设备上运行或在单一设备上被用户通过多种输入方式操控,也可能在多种距离上被用户操控。这需要其用户界面能够识别和支持不同的交互场景,以便用户以习惯的、舒适的方法与其进行交互。 在全场景的数字体验中,越来越多类型的智能终端设备分布在用户的日常生活中,可交互的用户界面广泛存在于默认设备、平板、PC、智能穿戴设备、智慧屏、车机、虚拟现实(VR)和增强现实(AR)等设备上。应用可能在多种设备上运行或在单一设备上被用户通过多种输入方式操控,也可能在多种距离上被用户操控。这需要其用户界面能够识别和支持不同的交互场景,以便用户以习惯的、舒适的方法与其进行交互。
![zh-cn_image_0000001224293580](figures/zh-cn_image_0000001224293580.png) ![zh-cn_image_0000001224293580](figures/zh-cn_image_0000001224293580.png)
## 输入方式 ## 输入方式
典型的输入方式包括但不限于触屏上手指/手写笔等直接交互、鼠标/触摸板/键盘/表冠/遥控器/车机摇杆/旋钮/手柄/隔空手势等间接交互、以及语音交互。 典型的输入方式包括但不限于触屏上手指/手写笔等直接交互、鼠标/触摸板/键盘/表冠/遥控器/车机摇杆/旋钮/手柄/隔空手势等间接交互、以及语音交互。
设计和开发应用时,**设计师和开发者应考虑到应用具有使用多种输入方式的可能性**,并实现相应的功能,保证在当前输入方式下应用能够以正确的、符合用户习惯的方式进行响应。 设计和开发应用时,**设计师和开发者应考虑到应用具有使用多种输入方式的可能性**,并实现相应的功能,保证在当前输入方式下应用能够以正确的、符合用户习惯的方式进行响应。
## 交互距离 ## 交互距离
典型的设备交互距离包括但不限于15cm(智能穿戴设备)、30cm(默认设备)、60cm(桌面设备)、260cm(大屏),具体距离会在用户使用过程中产生一定范围的变化。 典型的设备交互距离包括但不限于15cm(智能穿戴设备)、30cm(默认设备)、60cm(桌面设备)、260cm(大屏),具体距离会在用户使用过程中产生一定范围的变化。
设计和开发应用时,设计师和开发者应考虑到多种距离下使用的可能性,保证界面元素的大小、展示信息的密度符合用户的预期。 设计和开发应用时,设计师和开发者应考虑到多种距离下使用的可能性,保证界面元素的大小、展示信息的密度符合用户的预期。
![zh-cn_image_0000001313720673](figures/zh-cn_image_0000001313720673.png) ![位图 21](figures/位图21.png)
# 交互归一 # 交互归一
对于不同类型的智能设备,用户可能有不同的交互方式,如通过触摸屏、鼠标、触控板等。如果针对不同的交互方式单独做适配,会增加开发工作量同时产生大量重复代码。为解决这一问题,我们统一了各种交互方式的API,即实现了**交互归一** 对于不同类型的智能设备,用户可能有不同的交互方式,如通过触摸屏、鼠标、触控板等。如果针对不同的交互方式单独做适配,会增加开发工作量同时产生大量重复代码。为解决这一问题,我们统一了各种交互方式的API,即实现了**交互归一**
## 基础输入 ## 基础输入
常见的基础输入方式及其在各输入设备上的表现如下图所示。 常见的基础输入方式及其在各输入设备上的表现如下图所示。
![zh-cn_image_0000001313602309](figures/zh-cn_image_0000001313602309.jpg) ![basic_guester](figures/basic_guester.jpg)
基础输入对应的开发接口,以及当前支持情况如下表所示。 基础输入对应的开发接口,以及当前支持情况如下表所示。
| 输入 | 开发接口 | 触控屏 | 鼠标 | 触控板 | | 输入 | 开发接口 | 触控屏 | 鼠标 | 触控板 |
| -------- | -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- | -------- |
| 点击 | [onClick](../../reference/arkui-ts/ts-universal-events-click.md) | √ | √ | √ | | 点击 | [onClick](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-events-click.md) | √ | √ | √ |
| 长按 | [LongPressGesture](../../reference/arkui-ts/ts-basic-gestures-longpressgesture.md) | √ | √ | × | | 长按 | [LongPressGesture](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-gestures-longpressgesture.md) | √ | √ | × |
| 双击 | [TapGesture](../../reference/arkui-ts/ts-basic-gestures-tapgesture.md) | √ | √ | √ | | 双击 | [TapGesture](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-gestures-tapgesture.md) | √ | √ | √ |
| 轻扫 | [SwipeGesture](../../reference/arkui-ts/ts-basic-gestures-swipegesture.md) | √ | √ | √ | | 轻扫 | [SwipeGesture](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-gestures-swipegesture.md) | √ | √ | √ |
| 滚动及平移 | [PanGesture](../../reference/arkui-ts/ts-basic-gestures-pangesture.md) | √ | √ | √ | | 滚动及平移 | [PanGesture](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-gestures-pangesture.md) | √ | √ | √ |
| 缩放 | [PinchGesture](../../reference/arkui-ts/ts-basic-gestures-pinchgesture.md) | √ | √ | √ | | 缩放 | [PinchGesture](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-gestures-pinchgesture.md) | √ | √ | √ |
| 旋转 | [RotationGesture](../../reference/arkui-ts/ts-basic-gestures-rotationgesture.md) | √ | NA | √ | | 旋转 | [RotationGesture](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-gestures-rotationgesture.md) | √ | NA | √ |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 点击事件(onClick)其实是点击手势(TapGesture)的一个特殊场景(单指单次点击)。该场景使用的非常广泛,为了方便开发者使用及符合传统开发习惯,所以专门提供了开发接口。 > - 点击事件(onClick)其实是点击手势(TapGesture)的一个特殊场景(单指单次点击)。该场景使用的非常广泛,为了方便开发者使用及符合传统开发习惯,所以专门提供了开发接口。
> >
> - 触控板支持长按输入的功能正在开发中。 > - 触控板支持长按输入的功能正在开发中。
## 拖拽事件 ## 拖拽事件
拖拽是应用开发中经常碰到的场景。拖拽发生在两个组件之间,它不是简单的单次输入,而是一个”过程”,通常包含如下步骤(以将组件A拖拽到组件B中为例)。 拖拽是应用开发中经常碰到的场景。拖拽发生在两个组件之间,它不是简单的单次输入,而是一个”过程”,通常包含如下步骤(以将组件A拖拽到组件B中为例)。
- 长按或点击组件A,触发拖拽。 - 长按或点击组件A,触发拖拽。
- 保持按压或点击,持续将组件A向组件B拖拽。 - 保持按压或点击,持续将组件A向组件B拖拽。
- 抵达组件B中,释放按压点击,完成拖拽。 - 抵达组件B中,释放按压点击,完成拖拽。
- 也可以在未抵达组件B的中途,释放按压点击,取消拖拽。 - 也可以在未抵达组件B的中途,释放按压点击,取消拖拽。
一个完整的拖拽事件,包含多个拖拽子事件,如下表所示(请访问拖拽事件了解详细用法)。当前触控屏和鼠标的拖拽事件已经实现”交互归一”,对触控屏的支持正在开发中。 一个完整的拖拽事件,包含多个拖拽子事件,如下表所示(请访问拖拽事件了解详细用法)。当前触控屏和鼠标的拖拽事件已经实现”交互归一”,对触控屏的支持正在开发中。
| 名称 | 功能描述 | | 名称 | 功能描述 |
| -------- | -------- | | -------- | -------- |
| onDragStart | 绑定A组件,触控屏长按/鼠标左键按下后移动触发 | | onDragStart | 绑定A组件,触控屏长按/鼠标左键按下后移动触发 |
| onDragEnter | 绑定B组件,触控屏手指、鼠标移动进入B组件瞬间触发 | | onDragEnter | 绑定B组件,触控屏手指、鼠标移动进入B组件瞬间触发 |
| onDragMove | 绑定B组件,触控屏手指、鼠标在B组件内移动触发 | | onDragMove | 绑定B组件,触控屏手指、鼠标在B组件内移动触发 |
| onDragLeave | 绑定B组件,触控屏手指、鼠标移动退出B组件瞬间触发 | | onDragLeave | 绑定B组件,触控屏手指、鼠标移动退出B组件瞬间触发 |
| onDrop | 绑定B组件,在B组件内,触控屏手指抬起、鼠标左键松开时触发 | | onDrop | 绑定B组件,在B组件内,触控屏手指抬起、鼠标左键松开时触发 |
# 概述 # 概述
布局不是静态固定的,当显示环境发生变化时,如横竖屏切换、调节字体大小、应用分屏,要及时调整内容的布局方式以适应变化。本章提供了布局基础的概念和介绍。详见[布局基础](layout-grid.md) 布局不是静态固定的,当显示环境发生变化时,如横竖屏切换、调节字体大小、应用分屏,要及时调整内容的布局方式以适应变化。本章提供了布局基础的概念和介绍。详见[布局基础](design-grid.md)
了解布局的基础概念后,通过调用栅格系统、自适应布局和响应式布局能力就可以让内容更好地适配显示环境的变化。综合运用布局基础能力,可实现常用页面结构的多设备适配。详见[布局基础运用案例](layout-design-cases.md) 了解布局的基础概念后,通过调用栅格系统、自适应布局和响应式布局能力就可以让内容更好地适配显示环境的变化。综合运用布局基础能力,可实现常用页面结构的多设备适配。详见[布局基础运用案例](design-layout-cases.md)
# 界面布局
- **[概述](interface-layout-design-intro.md)**
- **[布局基础](layout-design-basics.md)**
- **[布局基础运用案例](design-layout-cases.md)**
\ No newline at end of file
# 简介 # 简介
## 背景 ## 背景
随着终端设备形态日益多样化,分布式技术逐渐打破单一硬件边界,一个应用或服务,可以在不同的硬件设备之间随意调用、互助共享,让用户享受无缝的全场景体验。而作为应用开发者,广泛的设备类型也能为应用带来广大的潜在用户群体。但是如果一个应用需要在多个设备上提供同样的内容,则需要适配不同的屏幕尺寸和硬件,开发成本较高。OpenHarmony 系统面向多终端提供了“一多”的能力,让开发者可以基于一种设计,高效构建多端可运行的应用。 随着终端设备形态日益多样化,分布式技术逐渐打破单一硬件边界,一个应用或服务,可以在不同的硬件设备之间随意调用、互助共享,让用户享受无缝的全场景体验。而作为应用开发者,广泛的设备类型也能为应用带来广大的潜在用户群体。但是如果一个应用需要在多个设备上提供同样的内容,则需要适配不同的屏幕尺寸和硬件,开发成本较高。OpenHarmony 系统面向多终端提供了“一次开发,多端部署”(后文中简称为“一多”)的能力,让开发者可以基于一种设计,高效构建多端可运行的应用。
![zh-cn_image_0000001267340890](figures/zh-cn_image_0000001267340890.jpg) ![zh-cn_image_0000001267340890](figures/zh-cn_image_0000001267340890.jpg)
## 定义及目标 ## 定义及目标
**定义**:一套代码工程,一次开发上架,多端按需部署。 **定义**:一套代码工程,一次开发上架,多端按需部署。
**目标**:支撑开发者快速高效开发多设备(“多种终端设备形态”的简称)应用,实现对不同设备兼容的同时提供跨设备的流转、迁移和协同的分布式体验。 **目标**:支撑开发者快速高效的开发支持多种终端设备形态的应用,实现对不同设备兼容的同时,提供跨设备的流转、迁移和协同的分布式体验。
![zh-cn_image_0000001315500981](figures/zh-cn_image_0000001315500981.jpg) ![multi_device](figures/multi_device.jpg)
为了实现“已整改”的目标,需要解决两个基础问题: 为了实现“一多”的目标,需要解决两个基础问题:
- 不同设备间的屏幕尺寸、色彩风格等存在差异,页面如何适配。 - 不同设备间的屏幕尺寸、色彩风格等存在差异,页面如何适配。
- 不同设备的系统能力有差异,如智能穿戴设备是否具备GPS、智慧屏是否具备摄像头等,功能如何兼容。 - 不同设备的系统能力有差异,如智能穿戴设备是否具备定位能力、智慧屏是否具备摄像头等,功能如何兼容。
从第3章开始将从UX设计、系统能力等角度,详尽的解答上述问题。 从第4章开始将从UX设计、系统能力等角度,详尽的解答上述问题。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
## 基础知识 > - 应用开发不仅包含应用页面开发,还包括应用后端功能开发以及服务器端开发等。
>
为了更好的阅读后面的章节,本小节主要介绍了一些基础知识,方便读者理解内容。 > - 本文旨在指导开发者如何在OpenHarmony系统中开发“一多”应用,服务器端开发不在本文探讨范围内。
### 应用程序包结构 ## 基础知识
OpenHarmony 的应用以APP Pack (Application Package) 形式发布,它是由一个或多个HAP包以及描述每个HAP属性的pack.info文件组成。 为了更好的阅读后面的章节,本小节主要介绍了一些基础知识,方便读者理解内容。
HAP是OpenHarmony的安装包,一个HAP在工程目录中对应一个Module,由Module编译而来,可分为entry和feature两种类型的HAP。
### 应用程序包结构
- **entry**:应用的主模块包。一个APP中,对于同一设备类型,可以有一个或多个entry类型的HAP,来支持该设备类型中不同规格(如API版本、屏幕规格等)的具体设备。
OpenHarmony 的应用以APP Pack (Application Package) 形式发布,它是由一个或多个HAP包以及描述每个HAP包属性的pack.info文件组成。
- **feature**:应用的动态特性模块包。一个APP Pack可以包含零个、一个或多个feature类型的HAP。
HAP包是OpenHarmony的安装包,一个HAP在工程目录中对应一个Module,由Module编译而来,可分为entry和feature两种类型的HAP。
![zh-cn_image_0000001266965046](figures/zh-cn_image_0000001266965046.png)
- **entry**:应用的主模块包。一个APP中,对于同一设备类型,可以有一个或多个entry类型的HAP,来支持该设备类型中不同规格(如API版本、屏幕规格等)的具体设备。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - Module是开发者开发的相对独立的功能模块,由代码、资源、第三方库及应用配置文件组成,属于IDE开发视图的概念。Module分为entry、feature及har三种类型,相应的可以编译生成entry类型的HAP包、feature类型的HAP包,以及HAR包。 - **feature**:应用的动态特性模块包。一个APP Pack可以包含零个、一个或多个feature类型的HAP。
>
> - 如果需要了解应用程序包结构更多详情,可以查看[包结构说明](../..//quick-start/package-structure.md)。 ![zh-cn_image_0000001266965046](figures/zh-cn_image_0000001266965046.png)
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
### 方舟开发框架 > - Module是开发者开发的相对独立的功能模块,由代码、资源、第三方库及应用配置文件组成,属于IDE开发视图的概念。Module分为entry、feature及har三种类型,相应的可以编译生成entry类型的HAP包、feature类型的HAP包,以及har包。
>
OpenHarmony提供了方舟开发框架(简称:ArkUI),提供开发者进行应用UI开发时所必须的能力。 > - 如果需要了解应用程序包结构更多详情,可以查看[包结构说明](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/package-structure.md)。
方舟开发框架提供了两种开发范式,分别是基于JS扩展的类Web开发范式(简称为“类Web开发范式”)和基于TS扩展的声明式开发范式(简称为“声明式开发范式”)。
### 方舟开发框架
- **类Web开发范式**:采用经典的HML、CSS、JavaScript三段式开发方式。使用HML标签文件进行布局搭建,使用CSS文件进行样式描述,使用JavaScript文件进行逻辑处理。UI组件与数据之间通过单向数据绑定的方式建立关联,当数据发生变化时,UI界面自动触发更新。此种开发方式,更接近Web前端开发者的使用习惯,快速将已有的Web应用改造成方舟开发框架应用。主要适用于界面较为简单的中小型应用开发。
OpenHarmony提供了方舟开发框架(简称:ArkUI),提供开发者进行应用UI开发时所必须的能力。
- **声明式开发范式**:采用TS语言并进行声明式UI语法扩展,从组件、动效和状态管理三个维度提供了UI绘制能力。UI开发更接近自然语义的编程方式,让开发者直观地描述UI界面,不必关心框架如何实现UI绘制和渲染,实现极简高效开发。同时,选用有类型标注的TS语言,引入编译期的类型校验,更适用大型的应用开发。
方舟开发框架提供了两种开发范式,分别是基于JS扩展的类Web开发范式(后文中简称为“类Web开发范式”)和基于TS扩展的声明式开发范式(后文中简称为“声明式开发范式”)。
两种开发范式的对比如下。
- **类Web开发范式**:采用经典的HML、CSS、JavaScript三段式开发方式。使用HML标签文件进行布局搭建,使用CSS文件进行样式描述,使用JavaScript文件进行逻辑处理。UI组件与数据之间通过单向数据绑定的方式建立关联,当数据发生变化时,UI界面自动触发更新。此种开发方式,更接近Web前端开发者的使用习惯,快速将已有的Web应用改造成方舟开发框架应用。主要适用于界面较为简单的中小型应用开发。
| **开发范式名称** | **语言生态** | **UI更新方式** | **适用场景** | **适用人群** |
| -------- | -------- | -------- | -------- | -------- | - **声明式开发范式**:采用TS语言并进行声明式UI语法扩展,从组件、动效和状态管理三个维度提供了UI绘制能力。UI开发更接近自然语义的编程方式,让开发者直观地描述UI界面,不必关心框架如何实现UI绘制和渲染,实现极简高效开发。同时,选用有类型标注的TS语言,引入编译期的类型校验,更适用大型的应用开发。
| 类Web开发范式 | JS语言 | 数据驱动更新 | 界面较为简单的类小程序应用和卡片 | Web前端开发人员 |
| 声明式开发范式 | 扩展的TS语言(eTS) | 数据驱动更新 | 复杂度较大、团队合作度较高的程序 | 移动系统应用开发人员、系统应用开发人员 | 两种开发范式的对比如下。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** | **开发范式名称** | **语言生态** | **UI更新方式** | **适用场景** | **适用人群** |
> - 声明式开发范式占用内存更少,**更推荐开发者选用声明式开发范式来搭建应用UI界面**。 | -------- | -------- | -------- | -------- | -------- |
> | 类Web开发范式 | JS语言 | 数据驱动更新 | 界面较为简单的类小程序应用和卡片 | Web前端开发人员 |
> - 可以查看[方舟开发框架概述](../../ui/arkui-overview.md),了解方舟开发框架更多详情。 | 声明式开发范式 | 扩展的TS语言(eTS) | 数据驱动更新 | 复杂度较大、团队合作度较高的程序 | 移动系统应用开发人员、系统应用开发人员 |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
### 部署模型 > - 声明式开发范式占用内存更少,**更推荐开发者选用声明式开发范式来搭建应用UI界面**。
>
我们既可以在不同类型的设备上部署相同的HAP包,也可以在不同类型的设备上部署不同的HAP包。 > - 可以查看[方舟开发框架概述](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/arkui-overview.md),了解方舟开发框架更多详情。
“一多”有两种部署模型:
### 部署模型
- **部署模型A**:不同类型的设备上按照一定的工程结构组织方式,通过一次编译生成**相同**的HAP包(或HAP包组合)。
“一多”有两种部署模型:
- **部署模型B**:不同类型的设备上按照一定的工程结构组织方式,通过一次编译生成**不同**的HAP包(或HAP包组合)。
- **部署模型A**:不同类型的设备上按照一定的工程结构组织方式,通过一次编译生成**相同**的HAP包(或HAP包组合)。
建议开发者从设备类型及应用功能两个维度,结合具体的业务场景,考虑选择哪种部署模型。但不管采用哪种部署模型,都应该采用一次编译。
- **部署模型B**:不同类型的设备上按照一定的工程结构组织方式,通过一次编译生成**不同**的HAP包(或HAP包组合)。
**设备类型**
建议开发者从设备类型及应用功能两个维度,结合具体的业务场景,考虑选择哪种部署模型。但不管采用哪种部署模型,都应该采用一次编译。
从屏幕尺寸、交互方式及使用距离三个维度考虑,我们将常用的设备分为三大泛类:
- 默认设备、平板 **设备类型**
- 车机、智慧屏 从屏幕尺寸、交互方式及使用距离三个维度考虑,我们将常用的设备分为三大泛类:
- 默认设备、平板
- 智能穿戴
- 车机、智慧屏
对于相同泛类的设备,优先选择部署模型A,对于不同泛类设备,优先选择部署B。
- 智能穿戴
**应用功能**
对于相同泛类的设备,优先选择部署模型A,对于不同泛类设备,优先选择部署模型B。
- 方舟开发框架提供了丰富的多设备适配能力,相同泛类的设备通常总是可以使用部署模型。部署模型A需要的开发和维护工作量更小,而且可以保证不同类型设备上体验的一致性。
**应用功能**
- 仅当同一泛类不同类型设备上规划的功能差异非常大时,才推荐使用部署模型B,如默认设备和平板分别交给两个团队设计、开发和维护等。
- 方舟开发框架提供了丰富的多设备适配能力,相同泛类的设备通常总是可以使用部署模型A。部署模型A需要的开发和维护工作量更小,而且可以保证不同类型设备上体验的一致性。
一般应用在不同设备上选择部署模型的思路如下:
- 仅当同一泛类不同类型设备上规划的功能差异非常大时,才推荐使用部署模型B,如默认设备和平板分别交给两个团队设计、开发和维护等。
![zh-cn_image_0000001317848113](figures/zh-cn_image_0000001317848113.png)
一般应用在不同设备上选择部署模型的思路如下:
(备注:页面导航是用于应用内页面之间的跳转。例如默认设备设备上PageA跳转到PageB,Pad设备上也是PageA跳转到PageB,两种设备因为屏幕大小不同,默认设备上PageB是覆盖显示在PageA上的,Pad设备上PageB是在PageA的右边并且同时显示,但因为都是PageA跳转到PageB,那么我们认为它们的页面导航逻辑相同。)
![zh-cn_image_0000001400300617](figures/zh-cn_image_0000001400300617.png)
**工程结构**
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
部署模型不同,往往代码工程结构也不同。 > 页面导航逻辑是指应用内页面之间的跳转关系。假设默认设备上页面A跳转到页面B,平板设备上也是页面A跳转到页面B。因为两种设备屏幕大小不同,默认设备上页面B是覆盖显示在页面A上的,平板设备上页面B是在页面A的右边并且同时显示,但因为都是页面A跳转到页面B,那么我们认为它们的页面导航逻辑相同。
部署模型A对应的代码工程结构抽象后一般如下所示: **工程结构**
“一多”推荐在应用开发过程中使用如下的“三层工程结构”。
```
/application - common:公共特性目录,如工具类、公共配置等。
├── common # 可选。公共特性目录, har类型的module
├── features # 可选。功能模块目录 - features:功能模块目录,存放应用中相对独立的各个功能的实现(包括该功能相关的UI代码及业务逻辑代码),如帐户管理等。
│ ├── feature1 # 子功能1, har类型的module
│ ├── feature2 # 子功能2, har类型的module - product:产品层目录,通过引用common和feature目录中代码的方式做功能和特性的集成,同时也作为主入口。
│ └── ...
└── product # 必选。产品层目录, entry类型的module,编译后为hap包 > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
``` > features层可横向调用和依赖common层能力;product层不可横向调用,可依赖features层和common层,且不能有反向依赖。
部署模型B对应的代码工程结构抽象后一般如下所示: 部署模型不同,相应的代码工程结构也有差异。部署模型A和部署模型B的主要差异点集中在product层:
- 部署模型A可以直接在product目录中做功能和特性集成。
```
/application - 部署模型B需要在product目录下再建一级子目录,在不同的子目录中对不同的产品做差异化的功能和特性集成。
├── common # 可选。公共特性目录, har类型的module
├── features # 可选。功能模块目录 部署模型A对应的代码工程结构抽象后一般如下所示:
│ ├── feature1 # 子功能1, har类型的module
│ ├── feature2 # 子功能2, har类型的module
│ └── ... ```
└── product # 必选。产品层目录 /application
├── wearable # 智能穿戴泛类目录, entry类型的module,编译后为hap包 ├── common # 可选。公共特性目录, har类型的module
├── default # 默认设备泛类目录, entry类型的module,编译后为hap包 ├── features # 可选。功能模块目录
└── ... │ ├── feature1 # 子功能1, har类型的module
``` │ ├── feature2 # 子功能2, har类型的module
│ └── ...
- common:公共特性目录,如工具类、公共配置等。 └── product # 必选。产品层目录, entry类型的module,编译后为hap包
```
- features:功能模块目录,存放应用中相对独立的各个功能的实现(包括该功能相关的UI代码及业务逻辑代码),如账户管理等。
部署模型B对应的代码工程结构抽象后一般如下所示:
- product:产品层目录,通过引用common和feature目录中代码的方式做功能和特性的集成,同时也作为主入口。**这一层是两个部署模型主要差异点**,部署模型A可以直接在product目录中做功能和特性集成,部署模型B则需要在product目录下再建一级子目录,在不同的子目录中对不同的产品做差异化的功能和特性集成。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** ```
/application
> 无论是用部署模型A还是部署模型B,在开发阶段,都应考虑**不同类型设备间最大程度的复用代码**,以减少开发及后续维护的工作量。 ├── common # 可选。公共特性目录, har类型的module
├── features # 可选。功能模块目录
│ ├── feature1 # 子功能1, har类型的module
│ ├── feature2 # 子功能2, har类型的module
│ └── ...
└── product # 必选。产品层目录
├── wearable # 智能穿戴泛类目录, entry类型的module,编译后为hap包
├── default # 默认设备泛类目录, entry类型的module,编译后为hap包
└── ...
```
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 无论是用部署模型A还是部署模型B,在开发阶段,都应考虑**不同类型设备间最大程度的复用代码**,以减少开发及后续维护的工作量。
# 布局基础
- **[栅格系统](design-grid.md)**
- **[自适应布局](design-adaptive-layout.md)**
- **[响应式布局](design-responsive-layout.md)**
\ No newline at end of file
# 布局能力简介 # 布局简介
开发多设备上同一页面时,建议开发者优先使用一套布局,尽可能的实现代码复用 布局可以分为自适应布局和响应式布局,二者的介绍如下表所示
一般情况下,可以通过页面的组件结构(组件个数、组件的父子/兄弟关系、组件类型)来判断是否可以使用一套布局: | 名称 | 简介 |
| -------- | -------- |
| 自适应布局 | 当外部容器大小发生变化时,元素可以**根据相对关系自动变化**以适应外部容器变化的布局能力。相对关系如占比、固定宽高比、显示优先级等。当前自适应布局能力有7种:[拉伸能力](adaptive-layout.md#拉伸能力)[均分能力](adaptive-layout.md#均分能力)[占比能力](adaptive-layout.md#占比能力)[缩放能力](adaptive-layout.md#缩放能力)[延伸能力](adaptive-layout.md#延伸能力)[隐藏能力](adaptive-layout.md#隐藏能力)[折行能力](adaptive-layout.md#折行能力)。自适应布局能力可以实现界面显示随外部容器大小连续变化。 |
| 响应式布局 | 当外部容器大小发生变化时,元素可以**根据断点、栅格或特定的特征(如屏幕方向、窗口宽高等)自动变化**以适应外部容器变化的布局能力。当前响应式布局能力有3种:[断点](responsive-layout.md#断点)[媒体查询](responsive-layout.md#媒体查询)[栅格布局](responsive-layout.md#栅格布局)。响应式布局可以实现界面随外部容器大小有级不连续变化,通常不同特征下的界面显示会有较大的差异。 |
- 对于页面组件结构相同的场景,在开发过程中可以灵活使用[自适应布局](adaptive-layout-intro.md)[栅格布局](grid-breakpoint.md)能力来达到预期效果 自适应布局和响应式布局常常需要借助容器类组件实现,或与容器类组件搭配使用
- 对于页面组件结构不同的场景,可以借助[媒体查询](media-query.md)能力动态加载多套布局。
- 自适应布局常常需要借助[Row组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-row.md)[Column组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-column.md)[Flex组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-flex.md)实现。
![image-20220922185907892](figures/image-20220922185907892.png)
- 响应式布局常常与[GridRow组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-gridrow.md)[Grid组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-grid.md)[List组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md)[Swiper组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-swiper.md)[Tabs组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-tabs.md)搭配使用。
![image-20220922190217247](figures/image-20220922190217247.png)
接下来将依次介绍自适应布局和响应式布局,同时结合实际,通过典型布局场景以及典型页面场景详细介绍两种布局能力的用法。
下面将详细介绍这些布局能力。
## 相关实例 ## 相关实例
针对一次开发,多端部署,有以下相关实例可供参考: 针对一次开发,多端部署,有以下相关实例可供参考:
...@@ -22,3 +34,4 @@ ...@@ -22,3 +34,4 @@
- [`AdaptiveCapabilities`:多设备自适应能力(eTS)(API9)](https://gitee.com/openharmony/applications_app_samples/tree/master/MultiDeviceAppDev/AdaptiveCapabilities) - [`AdaptiveCapabilities`:多设备自适应能力(eTS)(API9)](https://gitee.com/openharmony/applications_app_samples/tree/master/MultiDeviceAppDev/AdaptiveCapabilities)
- [`JsAdaptiveCapabilities`:多设备自适应能力(JS)(API8)](https://gitee.com/openharmony/applications_app_samples/tree/master/MultiDeviceAppDev/JsAdaptiveCapabilities) - [`JsAdaptiveCapabilities`:多设备自适应能力(JS)(API8)](https://gitee.com/openharmony/applications_app_samples/tree/master/MultiDeviceAppDev/JsAdaptiveCapabilities)
- [一次开发多端部署(eTS)(API8)](https://gitee.com/openharmony/codelabs/tree/master/ETSUI/MultiDeploymentEts) - [一次开发多端部署(eTS)(API8)](https://gitee.com/openharmony/codelabs/tree/master/ETSUI/MultiDeploymentEts)
# 布局能力
- **[布局简介](layout-intro.md)**
- **[自适应布局](adaptive-layout.md)**
- **[响应式布局](responsive-layout.md)**
- **[典型布局场景](typical-layout-scenario.md)**
- **[典型页面场景](typical-page-layout.md)**
\ No newline at end of file
# 人机交互
- **[交互基础](interaction-basics.md)**
- **[常见输入方式](common-input-modes.md)**
- **[交互事件归一](design-interaction-event-normalization.md)**
\ No newline at end of file
# 媒体查询
媒体查询是一种常用的功能,在移动设备上应用非常广泛。开发者经常需要根据设备的大致类型或特定的特征和设备参数(例如屏幕分辨率)来修改应用的样式。为此媒体查询提供了如下功能:
- 针对设备和应用的属性信息,可以设计出相匹配的布局样式。
- 当屏幕发生动态改变时(比如横竖屏切换、屏幕宽高比),页面布局同步更新。
当前支持对如下媒体特征做媒体查询。
| 类型 | 说明 |
| -------- | -------- |
| height | 应用页面显示区域的高度。 |
| min-height | 应用页面显示区域的最小高度。 |
| max-height | 应用页面显示区域的最大高度。 |
| width | 应用页面显示区域的宽度。 |
| min-width | 应用页面显示区域的最小宽度。 |
| max-width | 应用页面显示区域的最大宽度。 |
| resolution | 设备的分辨率,支持dpi,dppx和dpcm单位。 |
| min-resolution | 设备的最小分辨率。 |
| max-resolution | 设备的最大分辨率。 |
| orientation | 屏幕的方向,支持portrait(竖屏)和landscape(横屏)。 |
| device-type | 设备类型,支持tablet、tv、wearable等。 |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 声明式开发范式,请查看[媒体查询](../../ui/ui-ts-layout-mediaquery.md)了解详细用法。
>
> - 类Web开发范式,支持在js文件和css文件中使用媒体查询,请查看[js媒体查询](../../reference/apis/js-apis-mediaquery.md)和[css媒体查询](../../reference/arkui-js/js-components-common-mediaquery.md)了解详细用法。
>
> - 媒体查询能力最为强大,它可以改变页面组件结构,而自适应布局和栅格布局均无此能力。
>
> - 相对于其它”一多”能力,媒体查询可能增加较多代码量。在可以满足需求的前提下,建议优先使用其它”一多”能力。
## 示例:
如下图,媒体查询不仅可以改变页面中的元素属性(文字内容、文字颜色),还可以改变页面结构(是否显示图片)。
![zh-cn_image_0000001226091264](figures/zh-cn_image_0000001226091264.jpg)
```ts
import mediaquery from '@ohos.mediaquery'
@Entry
@Component
struct MediaQuerySample {
@State color: string = '#DB7093';
@State text: string = 'Portrait';
@State flag: boolean = false;
private listener: mediaquery.MediaQueryListener = mediaquery.matchMediaSync('(orientation: landscape)');
onOrientationChange = (mediaQueryResult) => {
if (mediaQueryResult.matches) {
this.color = '#FFD700';
this.text = 'Landscape';
this.flag = true;
} else {
this.color = '#DB7093';
this.text = 'Portrait';
this.flag = false;
}
}
private aboutToAppear(): void {
this.listener.on('change', this.onOrientationChange);
}
private aboutToDisappear(): void {
this.listener.off('change', this.onOrientationChange);
}
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
if (this.flag) { // 通过媒体查询,改变布局
Image($r("app.media.my_image"))
.width(100)
.height(100)
}
Text(this.text).fontSize(24).fontColor(this.color)
}
.width('100%').height('100%')
}
}
```
# 音乐专辑页
本小节将以音乐专辑页为例,介绍如何使用自适应布局能力和响应式布局能力适配不同尺寸窗口。本示例已经在[OpenHarmony应用示例](https://gitee.com/openharmony/applications_app_samples/tree/master/MultiDeviceAppDev/MusicAlbum)中开源,读者可以根据需要自行下载源码并运行及查看效果。
## 页面设计
音乐专辑页的页面设计如下。
| sm | md | lg |
| -------- | -------- | -------- |
| ![zh-cn_image_0000001381013985](figures/zh-cn_image_0000001381013985.png) | ![zh-cn_image_0000001381133197](figures/zh-cn_image_0000001381133197.png) | ![zh-cn_image_0000001329813432](figures/zh-cn_image_0000001329813432.png) |
同样观察音乐专辑的页面设计,不同断点下的页面设计有较多相似的地方。
据此,我们可以将页面分拆为多个组成部分。
1. 标题栏
2. 歌单封面
3. 歌单列表
4. 播放控制栏
| sm | md | lg |
| -------- | -------- | -------- |
| ![zh-cn_image_0000001380933349](figures/zh-cn_image_0000001380933349.jpg) | ![zh-cn_image_0000001330133330](figures/zh-cn_image_0000001330133330.jpg) | ![zh-cn_image_0000001381013989](figures/zh-cn_image_0000001381013989.jpg) |
## 标题栏
不同断点下,标题栏始终只显示“返回按钮”、“歌单”以及“更多按钮”,但“歌单”与“更多按钮”之间的间距不同。由于不同断点下标题栏的背景色也有较大差异,因此无法使用拉伸能力实现,此场景更适合使用栅格实现。我们可以将标题栏划分为“返回按钮及歌单”和“更多按钮”两部分,这两部分在不同断点下占据的列数如下图所示。另外,还可以借助OnBreakpointChange事件,调整不同断点下这两部分的背景色。
| | sm | md | lg |
| -------- | -------- | -------- | -------- |
| 效果图 | ![zh-cn_image_0000001329817776](figures/zh-cn_image_0000001329817776.png) | ![zh-cn_image_0000001381018337](figures/zh-cn_image_0000001381018337.png) | ![zh-cn_image_0000001381137517](figures/zh-cn_image_0000001381137517.jpg) |
| 栅格布局图 | ![zh-cn_image_0000001330137692](figures/zh-cn_image_0000001330137692.png) | ![zh-cn_image_0000001329977740](figures/zh-cn_image_0000001329977740.png) | ![zh-cn_image_0000001329658136](figures/zh-cn_image_0000001329658136.png) |
```
@Component
export struct PlayListHeader {
@State moreBackgroundColor: Resource = $r('app.color.play_list_cover_background_color');
build() {
GridRow() {
GridCol({span: {sm:6, md: 6, lg:4}}) {
Row() {
Image($r('app.media.ic_back')).height('24vp').width('24vp')
}
.width('100%')
.height('50vp')
.justifyContent(FlexAlign.Start)
.alignItems(VerticalAlign.Center)
.padding({left:$r('app.float.default_margin')})
.backgroundColor($r('app.color.play_list_cover_background_color'))
}
GridCol({span: {sm:6, md: 6, lg:8}}) {
Row() {
Image($r('app.media.ic_add')).height('24vp').width('24vp')
}
.width('100%')
.height('50vp')
.justifyContent(FlexAlign.End)
.alignItems(VerticalAlign.Center)
.padding({right:$r('app.float.default_margin')})
.backgroundColor(this.moreBackgroundColor)
}
}.onBreakpointChange((currentBreakpoint) => {
// 调整不同断点下返回按钮及歌单的背景色
if (currentBreakpoint === 'sm') {
this.moreBackgroundColor = $r('app.color.play_list_cover_background_color');
} else {
this.moreBackgroundColor = $r('app.color.play_list_songs_background_color');
}
}).height('100%').width('100%')
}
}
```
## 歌单封面
歌单封面由封面图片、歌单介绍及常用操作三部分组成,这三部分的布局在md和lg断点下完全相同,但在sm断点下有较大差异。此场景同样可以用栅格实现。
| | sm | md/lg |
| -------- | -------- | -------- |
| 效果图 | ![zh-cn_image_0000001329660244](figures/zh-cn_image_0000001329660244.jpg) | ![zh-cn_image_0000001381379829](figures/zh-cn_image_0000001381379829.png) |
| 栅格布局图 | ![zh-cn_image_0000001381220165](figures/zh-cn_image_0000001381220165.png) | ![zh-cn_image_0000001381220169](figures/zh-cn_image_0000001381220169.png) |
```
@Component
export default struct PlayListCover {
...
build() {
Column() {
// 借助栅格组件实现总体布局
GridRow() {
// 歌单图片
GridCol({ span: { sm: 4, md: 10 }, offset: { sm: 0, md: 1, lg: 1 } }) {
this.CoverImage()
}
// 歌单介绍
GridCol({ span: { sm: 8, md: 10 }, offset: { sm: 0, md: 2, lg: 2 } }) {
this.CoverIntroduction()
}
// 歌单操作
GridCol({ span: { sm: 12, md: 10 }, offset: { sm: 0, md: 2, lg: 2 } }) {
this.CoverOptions()
}.margin({
top: this.currentBreakpoint === 'sm' ? 15 : 0,
bottom: this.currentBreakpoint === 'sm' ? 15 : 0
})
}
.margin({ left: this.coverMargin, right: this.coverMargin })
}
.height(this.currentBreakpoint === 'sm' ? this.coverHeight : '100%')
.padding({ top: this.currentBreakpoint === 'sm' ? 50 : 70 })
}
}
```
## 歌单列表
不同断点下,歌单列表的样式基本一致,但sm和md断点下是歌单列表是单列显示,lg断点下是双列显示。可以通过[List组件](https://gitee.com/fanzhaonan/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md)的lanes属性实现这一效果。
```
@Component
export default struct PlayList {
...
build() {
Column() {
this.PlayAll()
Scroll() {
List() {
LazyForEach(new MyDataSource(songList), item => {
ListItem() {
this.SongItem(item.title, item.label, item.singer)
}
}, item => item.id)
}
.width('100%')
.height('100%')
// 配置不同断点下歌单列表的列数
.lanes(this.currentBreakpoint === 'lg' ? 2 : 1)
}
.backgroundColor('#fff')
.margin({ top: 50, bottom: this.currentBreakpoint === 'sm' ? this.coverHeight : 0 })
}
.padding({top: 50,bottom: 48})
}
}
```
## 播放控制栏
在不同断点下,播放控制栏显示的内容完全一致,唯一的区别是歌曲信息与播放控制按钮之间的间距有差异,这是典型的拉伸能力的使用场景。
```
@Component
export struct MusicBar {
build() {
Row() {
Image($r('app.media.pic_album')).height(32).width(32).margin({right: 12})
SongTitle()
// 通过Blank组件实现拉伸能力
Blank()
Image($r('app.media.icon_play')).height(26).width(26).margin({right: 16})
Image($r('app.media.ic_next')).height(24).width(24).margin({right: 16})
Image($r('app.media.ic_Music_list')).height(24).width(24)
}
.width('100%')
.height(48)
.backgroundColor('#D8D8D8')
.alignItems(VerticalAlign.Center)
.padding({left: 16, right: 16})
}
}
```
## 运行效果
将页面中的四部分组合在一起,即可显示完整的页面。
其中歌单封面和歌单列表这两部分的相对位置,在sm断点下是上下排布,在md和lg断点下是左右排布,也可以用栅格来实现目标效果。
| | sm | md | lg |
| -------- | -------- | -------- | -------- |
| 效果图 | ![zh-cn_image_0000001381026609](figures/zh-cn_image_0000001381026609.jpg) | ![zh-cn_image_0000001381145789](figures/zh-cn_image_0000001381145789.jpg) | ![zh-cn_image_0000001329666380](figures/zh-cn_image_0000001329666380.jpg) |
| 栅格布局图 | ![zh-cn_image_0000001330145976](figures/zh-cn_image_0000001330145976.png) | ![zh-cn_image_0000001381385985](figures/zh-cn_image_0000001381385985.png) | ![zh-cn_image_0000001381226321](figures/zh-cn_image_0000001381226321.png) |
```
@Component
export default struct MusicContent {
...
build() {
GridRow() {
// 歌单封面
GridCol({ span: { xs: 12, sm: 12, md: 6, lg: 4 } }) {
PlayListCover()
}
// 歌单列表
GridCol({ span: { xs: 12, sm: 12, md: 6, lg: 8 } }) {
PlayList()
}
}
.height('100%')
}
}
```
最后将页面各部分组合在一起即可。
```
@Entry
@Component
struct Index {
build() {
Column() {
// 标题栏
PlayListHeader()
// 歌单
MusicContent()
// 播放控制栏
MusicBar()
}.width('100%').height('100%')
}
}
```
音乐专辑页面的运行效果如下所示。
| sm | md | lg |
| -------- | -------- | -------- |
| ![MusicAlbum_sm_running](figures/MusicAlbum_sm_running.png) | ![MusicAlbum_md_running](figures/MusicAlbum_md_running.png) | ![MusicAlbum_lg_running](figures/MusicAlbum_lg_running.png) |
# 应用导航结构设计要求 # 应用导航结构设计要求
应用中的导航用于引导用户在应用的各个页面进行浏览。好的导航让用户知道身处何处,去往何方,以及来自哪里。 应用中的导航用于引导用户在应用的各个页面进行浏览。好的导航让用户知道身处何处,去往何方,以及来自哪里。
## 导航的原则 ## 导航的原则
导航需要遵循以下原则: 导航需要遵循以下原则:
- **一致**:导航操作的结果应该与用户的期望保持一致。相同或类似的场景使用用户熟悉的界面布局和控件,在多设备上确保一致的应用架构和导航行为,让用户无论在什么页面,都知道如何导航。例如二级界面使用左上角的返回按钮来返回界面的上一个层级。 - **一致:**导航操作的结果应该与用户的期望保持一致。相同或类似的场景使用用户熟悉的界面布局和控件,在多设备上确保一致的应用架构和导航行为,让用户无论在什么页面,都知道如何导航。例如二级界面使用左上角的返回按钮来返回界面的上一个层级。
- **清晰**:导航应该提供清晰的路径。用户使用的时候,逻辑关系简单且容易理解,能够知道当前处在界面的什么位置,操作后将会跳转到什么位置,不会迷失方向。例如使用底部页签,让用户在平级页面之间进行切换。 - **清晰:**导航应该提供清晰的路径。用户使用的时候,逻辑关系简单且容易理解,能够知道当前处在界面的什么位置,操作后将会跳转到什么位置,不会迷失方向。例如使用底部页签,让用户在平级页面之间进行切换。
导航要避免以下设计: 导航要避免以下设计:
- **层级过深**:导航层级建议在三层以内。对于太深的层次,会带来操作效率的问题。如果确实需要深层级设计,建议使用面包屑设计或增加一键回到首页的功能。 - **层级过深:**导航层级建议在三层以内。对于太深的层次,会带来操作效率的问题。如果确实需要深层级设计,建议使用面包屑设计或增加一键回到首页的功能。
- **导航复杂**:在侧边导航中,使用底部页签,会让操作变得复杂,建议仅使用侧边导航。 - **导航复杂:**在侧边导航中,使用底部页签,会让操作变得复杂,建议仅使用侧边导航。
## 导航的分类 ## 导航的分类
常用的应用导航有:平级导航、层级导航和混合导航。 常用的应用导航有:平级导航、层级导航和混合导航。
**平级导航** **平级导航**
平级导航结构中,页面均处在同一层级。 平级导航结构中,页面均处在同一层级。
使用场景:用于展示同等地位或同等层级的界面。 使用场景:用于展示同等地位或同等层级的界面。
![zh-cn_image_0000001224053150](figures/zh-cn_image_0000001224053150.jpg) ![zh-cn_image_0000001224053150](figures/zh-cn_image_0000001224053150.jpg)
例如:以Tab方式组成的页面。图中照片、相册、发现为一级界面,从视频相册进入二级内容界面。 例如:以Tab方式组成的页面。图中照片、相册、发现为一级界面,从视频相册进入二级内容界面。
![zh-cn_image_0000001226444718](figures/zh-cn_image_0000001226444718.png) ![一多-2-2](figures/一多-2-2.png)
多设备设计:可转化导航类控件到符合设备体验的位置上。默认设备上使用Tab导航,PAD和PC使用侧边Tab导航,智慧屏使用顶部Tab导航。 多设备设计:可转化导航类控件到符合设备体验的位置上。默认设备上使用Tab导航,PAD和PC使用侧边Tab导航,智慧屏使用顶部Tab导航。
![zh-cn_image_0000001270924709](figures/zh-cn_image_0000001270924709.png) ![一多-2-3](figures/一多-2-3.png)
**层级导航** **层级导航**
层级导航结构由父页面和子页面组成。父页面可以有一个或多个子页面。每个子页面都有一个父页面。 层级导航结构由父页面和子页面组成。父页面可以有一个或多个子页面。每个子页面都有一个父页面。
层级导航适用于多层级的复杂结构。层级结构深的内容,用户访问的路径变长,效率降低,可以通过适当的层级穿透设计(例如:控制中心中的蓝牙开关,解决了进“设置-蓝牙”界面设置操作路径过长的问题)解决此问题。 层级导航适用于多层级的复杂结构。层级结构深的内容,用户访问的路径变长,效率降低,可以通过适当的层级穿透设计(例如:控制中心中的蓝牙开关,解决了进“设置-蓝牙”界面设置操作路径过长的问题)解决此问题。
使用场景:页面存在上下级关系的应用。 使用场景:页面存在上下级关系的应用。
![zh-cn_image_0000001224173138](figures/zh-cn_image_0000001224173138.jpg) ![zh-cn_image_0000001224173138](figures/zh-cn_image_0000001224173138.jpg)
例如:通过从内容进入后经返回键返回之前的页面。 例如:通过从内容进入后经返回键返回之前的页面。
![zh-cn_image_0000001270804909](figures/zh-cn_image_0000001270804909.png) ![一多-2-5](figures/一多-2-5.png)
多设备设计:可以考虑将上下层级的界面在同一界面展示。默认设备和智慧屏上使用上下层级关系。平板和PC使用上分栏的方式展示内容。 多设备设计:可以考虑将上下层级的界面在同一界面展示。默认设备和智慧屏上使用上下层级关系。平板和PC使用上分栏的方式展示内容。
![zh-cn_image_0000001226124842](figures/zh-cn_image_0000001226124842.png) ![一多-2-6](figures/一多-2-6.png)
**混合导航** **混合导航**
在实际应用设计中,仅使用平级或层级导航可能无法应对更复杂的业务结构。此时需区分不同页面的导航关系,对同等地位或同等层级的页面使用平级导航结构,对具有复杂关系的页面使用层级导航结构。 在实际应用设计中,仅使用平级或层级导航可能无法应对更复杂的业务结构。此时需区分不同页面的导航关系,对同等地位或同等层级的页面使用平级导航结构,对具有复杂关系的页面使用层级导航结构。
使用场景:应用由几个同等级的模块组成,每个模块又有上下层级关系页面。 使用场景:应用由几个同等级的模块组成,每个模块又有上下层级关系页面。
![zh-cn_image_0000001268653317](figures/zh-cn_image_0000001268653317.jpg) ![zh-cn_image_0000001268653317](figures/zh-cn_image_0000001268653317.jpg)
多设备设计:可以根据平级导航、层级导航自身的设计规则综合运用,一般平级导航优先级比层级高。 多设备设计:可以根据平级导航、层级导航自身的设计规则综合运用,一般平级导航优先级比层级高。
![zh-cn_image_0000001263489242](figures/zh-cn_image_0000001263489242.png) ![混合导航](figures/混合导航.png)
# 应用页面结构设计 # 应用页面结构设计
## 通用页面结构 ## 通用页面结构
应用程序由多个页面组成。我们将常见的页面进行了梳理,总结了以下常用的页面结构。 应用程序由多个页面组成。我们将常见的页面进行了梳理,总结了以下常用的页面结构。
**启动页面** **启动页面**
针对内容型应用,应用首页内容的获取需要花费一定的时间,此时可以使用启动页缓解页面加载内容的等待感。启动页可以展示应用的品牌形象或者广告,避免让用户等待过长时间。没有网络加载内容的应用,不需要使用启动页。 针对内容型应用,应用首页内容的获取需要花费一定的时间,此时可以使用启动页缓解页面加载内容的等待感。启动页可以展示应用的品牌形象或者广告,避免让用户等待过长时间。没有网络加载内容的应用,不需要使用启动页。
![zh-cn_image_0000001317205637](figures/zh-cn_image_0000001317205637.png) ![一多-应用架构-启动页](figures/一多-应用架构-启动页.png)
用户总是希望第一时间看到应用内容,因此在页面加载完成后,需要及时呈现内容。 用户总是希望第一时间看到应用内容,因此在页面加载完成后,需要及时呈现内容。
从后台加载应用时,不应该显示启动页。当应用被切换到后台后,再从后台加载回来时,不应该再次显示启动页。应用需要保留应用的状态,以便从后台恢复,方便用户继续浏览。 从后台加载应用时,不应该显示启动页。当应用被切换到后台后,再从后台加载回来时,不应该再次显示启动页。应用需要保留应用的状态,以便从后台恢复,方便用户继续浏览。
**列表内容页面** **列表内容页面**
列表内容页面通常用于文字和数据的展示,利于提升使用效率。 列表内容页面通常用于文字和数据的展示,利于提升使用效率。
![zh-cn_image_0000001268605598](figures/zh-cn_image_0000001268605598.png) ![一多-应用架构-列表视觉图](figures/一多-应用架构-列表视觉图.png)
列表应该按照一定的逻辑排序,便于用户浏览和操作。例如:按字母顺序排序、按时间排序。 列表应该按照一定的逻辑排序,便于用户浏览和操作。例如:按字母顺序排序、按时间排序。
列表应该是同类项的集合,应该对外呈现一致的布局样式。常见的是单行列表、双行列表和三行列表。 列表应该是同类项的集合,应该对外呈现一致的布局样式。常见的是单行列表、双行列表和三行列表。
列表显示的内容要主次分明,用户一眼就能关注到重要的信息和操作。 列表显示的内容要主次分明,用户一眼就能关注到重要的信息和操作。
**网格内容页面** **网格内容页面**
网格内容页面通常用于图片和视频的展示,利于沉浸浏览内容。 网格内容页面通常用于图片和视频的展示,利于沉浸浏览内容。
![zh-cn_image_0000001268445650](figures/zh-cn_image_0000001268445650.png) ![一多-应用架构-网格视图](figures/一多-应用架构-网格视图.png)
网格视图显示同等重要的项目,具有统一的布局。 网格视图显示同等重要的项目,具有统一的布局。
网格视图以图像为主组织内容。例如图库中用网格视图展示图片。 网格视图以图像为主组织内容。例如图库中用网格视图展示图片。
网格视图可以辅以文字和操作。例如应用市场中使用网格展示应用程序图标、简单描述和下载按钮。 网格视图可以辅以文字和操作。例如应用市场中使用网格展示应用程序图标、简单描述和下载按钮。
网格视图应该考虑响应式布局。在横竖屏切换时,网格视图应该能够调整网格的数量以适应页面的宽度变化。 网格视图应该考虑响应式布局。在横竖屏切换时,网格视图应该能够调整网格的数量以适应页面的宽度变化。
**多选页面** **多选页面**
多选页面是对页面内的数据多项选择,然后进行批量处理。常见的是针对列表的多项选择或宫格的多项选择。 多选页面是对页面内的数据多项选择,然后进行批量处理。常见的是针对列表的多项选择或宫格的多项选择。
![zh-cn_image_0000001268125810](figures/zh-cn_image_0000001268125810.png) ![应用架构-常用页面结构-通用页面结构-多选页面低保真](figures/应用架构-常用页面结构-通用页面结构-多选页面低保真.png)
**详情页面** **详情页面**
详情页用于展示应用的详细描述和操作。 详情页用于展示应用的详细描述和操作。
![zh-cn_image_0000001317325613](figures/zh-cn_image_0000001317325613.png) ![应用架构-常用页面结构-通用页面结构-详情页面低保真](figures/应用架构-常用页面结构-通用页面结构-详情页面低保真.png)
**空页面** **空页面**
在页面内没有数据的时候,使用空页面。 在页面内没有数据的时候,使用空页面。
![zh-cn_image_0000001317485577](figures/zh-cn_image_0000001317485577.png) ![一多-应用架构-空页面](figures/一多-应用架构-空页面.png)
**设置页面** **设置页面**
设置页面通常是一个模块所有设置项的聚合。 设置页面通常是一个模块所有设置项的聚合。
![zh-cn_image_0000001268285682](figures/zh-cn_image_0000001268285682.png) ![一多-应用架构-设置](figures/一多-应用架构-设置.png)
**我的页面** **我的页面**
针对内容型应用,可以提供我的页面,用于承载用户的信息和资产内容。 针对内容型应用,可以提供我的页面,用于承载用户的信息和资产内容。
![zh-cn_image_0000001317085761](figures/zh-cn_image_0000001317085761.png) ![一多-应用架构-我的页面](figures/一多-应用架构-我的页面.png)
**关于页面** **关于页面**
关于页面用于呈现应用的基本情况,包括联系方式,法律条款等内容。 关于页面用于呈现应用的基本情况,包括联系方式,法律条款等内容。
![zh-cn_image_0000001317205645](figures/zh-cn_image_0000001317205645.png) ![一多-应用架构-关于](figures/一多-应用架构-关于.png)
## 垂类页面结构 ## 垂类页面结构
垂类是指垂直领域,为特定的人群提供特定的服务,属于应用的细分类别。例如:华为音乐、网易云音乐等属于音乐类,华为视频、优酷等属于视频类,快手、抖音等属于直播类。垂类页面结构是在特定领域长期使用的过程中,形成的广受用户接受和理解的页面结构。 垂类是指垂直领域,为特定的人群提供特定的服务,属于应用的细分类别。例如:华为音乐、网易云音乐等属于音乐类,华为视频、优酷等属于视频类,快手、抖音等属于直播类。垂类页面结构是在特定领域长期使用的过程中,形成的广泛被用户接受和理解的页面结构。
例如: 例如:
音乐类应用都有音乐歌单、音乐专辑、音乐播放界面。 音乐类应用都有音乐歌单,音乐专辑,音乐播放界面。
视频类应用都有视频详情和视频播放界面。 视频类应用都有视频详情和视频播放界面。
直播类应用,都有瀑布流推荐和直播界面。 直播类应用,都有瀑布流推荐和直播界面。
常见的垂类页面结构有: ...
- 音乐播放页面 常见的垂类页面结构有:
- 专辑详情页面 - 音乐播放页面
- 视频详情页面 - 专辑详情页面
- 视频播放页面 - 视频详情页面
**音乐播放界面** - 视频播放页面
音乐类应用中的播放器界面,该界面通常有音乐操控(播放,暂停,上一首,下一首)、歌词显示等功能。 **音乐播放界面**
![zh-cn_image_0000001268605602](figures/zh-cn_image_0000001268605602.png) 音乐类应用中的播放器界面,该界面通常有音乐操控(播放,暂停,上一首,下一首)、歌词显示等功能。
**专辑详情页** ![应用架构-常用页面结构-垂类页面结构-音乐播放低保真](figures/应用架构-常用页面结构-垂类页面结构-音乐播放低保真.png)
音乐类应用中的音乐专辑详情界面,该界面通常有专辑介绍、专辑包含的歌曲列表等功能。 **专辑详情页**
![zh-cn_image_0000001268445654](figures/zh-cn_image_0000001268445654.png) 音乐类应用中的音乐专辑详情界面,该界面通常有专辑介绍、专辑包含的歌曲列表等功能。
**视频详情页面** ![应用架构-常用页面结构-垂类页面结构-歌单详情低保真](figures/应用架构-常用页面结构-垂类页面结构-歌单详情低保真.png)
视频类应用的视频详情界面,该界面通常有视频播放器、视频剧集显示、视频简介等功能。 **视频详情页面**
![zh-cn_image_0000001268125814](figures/zh-cn_image_0000001268125814.png) 视频类应用的视频详情界面,该界面通常有视频播放器、视频剧集显示、视频简介等功能。
**视频播放界面** ![一多-应用架构-视频详情](figures/一多-应用架构-视频详情.png)
视频类应用的视频播放界面,该界面通常有视频画面预览、播放控制等功能。 **视频播放界面**
![zh-cn_image_0000001317325617](figures/zh-cn_image_0000001317325617.png) 视频类应用的视频播放界面,该界面通常有视频画面预览、播放控制等功能。
![一多-应用架构-视频播放](figures/一多-应用架构-视频播放.png)
## 特殊页面结构
部分应用界面在差异较大的设备间切换,无法使用自适应和响应式布局设计方法进行适配,从用户预期上也需要调整应用架构时,将需要做特殊适配。 ## 特殊页面结构
例如,同时具有底部Tab和子页签的页面,在大屏上应考虑将底部入口置于顶部工具栏或与子页签融合。 部分应用界面在差异较大的设备间切换,无法使用自适应和响应式布局设计方法进行适配,从用户预期上也需要调整应用架构时,将需要做特殊适配。
![zh-cn_image_0000001317485581](figures/zh-cn_image_0000001317485581.png) 例如,同时具有底部Tab和子页签的页面,在大屏上应考虑将底部入口置于顶部工具栏或与子页签融合。
![特殊页面结构](figures/特殊页面结构.png)
# 简介
本章介绍如何使用方舟开发框架“一多”能力,开发出在多设备上正常显示的页面。方舟开发框架推荐开发者使用声明式开发范式开发应用,故本章的内容和示例都主要基于声明式开发范式。本章主要包含如下内容:
- [布局能力](adaptive-layout.md)
布局决定了页面中的元素按照何种方式排布及显示,是页面设计及开发过程中首先需要考虑的问题。一般情况下,可以通过页面(或自定义组件)内的组件结构(组件个数、组件的父子/兄弟关系、组件类型、组件的相对位置)来判断使用何种布局能力。
- 对于随尺寸变化组件结构相同的场景,可以在开发过程中灵活使用[自适应布局能力](adaptive-layout.md)来达到目标效果。
- 对于随尺寸变化组件结构不同的场景,更适合使用[响应式布局能力](responsive-layout.md)来实现不同尺寸下的不同显示的效果。
- [交互归一](interaction-event-normalization.md)
- [多态组件](polymorphic-controls.md)
- [资源使用](resource-usage.md)
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 开发多设备上同一页面时,建议开发者多使用[自定义组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/ts-component-based-component.md),既可以增加代码的可读性和可维护性,同时也可以尽可能的实现代码复用。
>
> - 本章中涉及的示例代码均可以在[OpenHarmony应用示例](https://gitee.com/openharmony/applications_app_samples/tree/master/MultiDeviceAppDev)中获取,感兴趣的开发者可以自行下载、运行及查看效果。
# 页面开发的一多能力介绍
- **[简介](page-development-intro.md)**
- **[布局能力](layout.md)**
- **[交互归一](interaction-event-normalization.md)**
- **[多态组件](polymorphic-controls.md)**
- **[资源使用](resource-usage.md)**
\ No newline at end of file
# 多态组件
方舟开发框架不仅提供了多种基础组件,如文本显示、图片显示、按键交互等。并且针对不同类型设备进行了组件设计,提供了组件在不同平台上的样式适配能力,此种组件称为“多态组件”。开发者在使用多态组件时,无需考虑设备差异,只需关注功能实现即可。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> OpenHarmony上的多态组件能力正在逐步补齐中。
# 多态组件
方舟开发框架不仅提供了多种基础组件(如文本显示、图片显示、按键交互等),并且针对不同类型设备分别进行了适配。同一组件在不同的设备上会呈现出不同的形态(即视觉、交互、动效等可能有差异),称为“多态组件”。开发者在使用多态组件时,无需考虑设备差异,只需关注功能实现即可。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> OpenHarmony上的多态组件能力正在逐步补齐中。
# 资源使用 # 资源使用
在页面开发过程中,经常需要用到颜色、字体、间距、图片等资源,在不同的设备或配置中,这些资源的值可能不同。有两种方式处理: 在页面开发过程中,经常需要用到颜色、字体、间距、图片等资源,在不同的设备或配置中,这些资源的值可能不同。有两种方式处理:
- [自定义资源](#自定义资源):借助资源文件能力,开发者在应用中自定义资源,自行管理这些资源在不同的设备或配置中的表现。 - [应用资源](#应用资源):借助资源文件能力,开发者在应用中自定义资源,自行管理这些资源在不同的设备或配置中的表现。
- [系统资源](#系统资源):开发者直接使用系统预置的资源定义(即分层参数)。 - [系统资源](#系统资源):开发者直接使用系统预置的资源定义(即分层参数)。
## 自定义资源 ## 应用资源
### 资源文件介绍 ### 资源文件介绍
开发者可以在项目工程的resources目录中创建指定类型的资源文件,通过”key-value”的形式定义资源,同时可以借助资源限定词能力,定义同一资源在不同设备(默认设备、智慧屏等)或同一设备不同配置(横竖屏、深浅色等)下的表现。工程内的resources目录按照两级目录的形式来组织: 应用开发中使用的各类自定义资源文件,需要统一存放于应用的resources目录下,便于使用和维护。resources目录包括两大类目录,一类为base目录与限定词目录,另一类为rawfile目录,其基础目录结构如下所示。
- 一级目录为base目录、限定词目录以及rawfile目录
- base目录是默认存在的目录。当应用的resources资源目录中没有与设备状态匹配的限定词目录时,会自动引用该目录中的资源文件。 ```
- 限定词目录需要开发者自行创建,其可以由一个或多个表征应用场景或设备特征的限定词组合而成,包括移动国家码和移动网络码、语言、文字、国家或地区、横竖屏、设备类型、颜色模式和屏幕密度等维度,限定词之间通过下划线(_)或者中划线(-)连接。 resources
- 在引用rawfile中的资源时,不会根据系统的状态去匹配,rawfile目录中可以直接存放资源文件。 |---base // 默认存在的目录
| |---element
- 二级目录为资源目录 | | |---string.json
- 用于存放字符串、颜色、浮点数等基础元素,以及媒体等资源文件。 | |---media
- 当前支持的文件和资源类型如下: | | |---icon.png
| 文件名 | 资源类型 | |---en_GB-vertical-car-mdpi // 限定词目录示例,需要开发者自行创建
| -------- | -------- | | |---element
| color.json | 颜色资源。 | | | |---string.json
| float.json | 间距、圆角、字体等资源。 | | |---media
| string.json | 字符串资源。 | | | |---icon.png
| plural.json | 字符串资源。 | |---rawfile // rawfile目录
| media目录 | 图片资源 | ```
base目录默认存在,而限定词目录需要开发者自行创建,其名称可以由一个或多个表征应用场景或设备特征的限定词组合而成。应用使用某资源时,系统会根据当前设备状态优先从相匹配的限定词目录中寻找该资源。只有当resources目录中没有与设备状态匹配的限定词目录,或者在限定词目录中找不到该资源时,才会去base目录中查找。rawfile是原始文件目录,它不会根据设备状态去匹配不同的资源,故不在本文的讨论范文内。
### 资源文件使用
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
在工程中,通过 "$r('app.type.name')" 的形式引用应用资源。app代表是应用内resources目录中定义的资源;type 代表资源类型(或资源的存放位置),可以取 color、float、string、plural和media,name代表资源命名,由开发者定义资源时确定。 > - 请访问[声明式开发范式资源文件分类](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/ui-ts-basic-resource-file-categories.md),了解限定词目录的命名规则、创建流程、匹配规则等,本文不展开介绍。
>
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > - 没有设备状态匹配的限定词目录,或者在限定词目录中找不到目标资源时,会继续在base目录中查找。**强烈建议对于所有应用自定义资源都在base目录中定义默认值**,防止出现找不到资源值的异常场景。
> - 可以查看[声明式开发范式资源访问](../../ui/ts-resource-access.md),了解资源访问的更多细节。 >
> > - 类Web开发范式的资源文件路径及资源限定词的使用与声明式范式不同,详情请参考[类Web开发范式资源限定与访问](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/js-framework-resource-restriction.md)及[类Web开发范式文件组织](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/js-framework-file.md)。
> - 类Web开发范式的资源文件路径及资源限定词的使用与声明式范式不同,详情请参考[类Web开发范式资源限定与访问](../../ui/js-framework-resource-restriction.md)及[类Web开发范式文件组织](../../ui/js-framework-file.md)。
base目录与限定词目录下面可以创建资源组目录(包括element、media等),用于存放特定类型的资源文件。
### 示例 | 资源组目录 | 目录说明 | 资源文件 |
| -------- | -------- | -------- |
按照如下说明,配置工程resources目录中的json资源文件(如文件不存在,需手工创建)。另外,准备两张不同的图片,分别放置于resources/base/media/my_image.jpg及resources/tablet/media/my_image.jpg路径下。 | element | 表示元素资源,以下每一类数据都采用相应的JSON文件来表征。<br/>-&nbsp;boolean,布尔型<br/>-&nbsp;color,颜色<br/>-&nbsp;float,浮点型<br/>-&nbsp;intarray,整型数组<br/>-&nbsp;integer,整型<br/>-&nbsp;pattern,样式<br/>-&nbsp;plural,复数形式<br/>-&nbsp;strarray,字符串数组<br/>-&nbsp;string,字符串 | element目录中的文件名称建议与下面的文件名保持一致。每个文件中只能包含同一类型的数据。<br/>-&nbsp;boolean.json<br/>-&nbsp;color.json<br/>-&nbsp;float.json<br/>-&nbsp;intarray.json<br/>-&nbsp;integer.json<br/>-&nbsp;pattern.json<br/>-&nbsp;plural.json<br/>-&nbsp;strarray.json<br/>-&nbsp;string.json |
| media | 表示媒体资源,包括图片、音频、视频等非文本格式的文件。 | 文件名可自定义,例如:icon.png。 |
```ts 在element目录的各个资源文件中,以“name-value”的形式定义资源,如下所示。而在media目录中,直接以文件名作为name,故开发者将文件放入media目录即可,无需再额外定义name。
//resources/base/element/string.json
{
"string":[ ```
{ // color.json
"name":"my_string", {
"value":"default" "color": [
} {
] "name": "color_red",
} "value": "#ffff0000"
//resources/base/element/color.json },
{ {
"color":[ "name": "color_blue",
{ "value": "#ff0000ff"
"name":"my_color", }
"value":"#ff0000" ]
} }
] ```
}
//resources/base/element/float.json
{ ### 访问应用资源
"float":[
{ 在工程中,通过 "$r('app.type.name')" 的形式引用应用资源。app代表是应用内resources目录中定义的资源;type 代表资源类型(或资源的存放位置),可以取 color、float、string、plural和media,name代表资源命名,由开发者添加资源时确定。
"name":"my_float",
"value":"60vp" > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
} > 可以查看[声明式范式访问应用资源](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/ts-resource-access.md),了解资源访问的更多细节。
]
}
### 示例
//resources/tablet/element/string.json
{ 在应用的resources目录下,创建名为tablet的限定词子目录,并按照下表所示,在base目录和tablet限定词目录中添加相应的资源。
"string":[
{ | 资源名称 | 资源类型 | base目录中资源值 | 限定词目录(tablet)中资源值 |
"name":"my_string", | -------- | -------- | -------- | -------- |
"value":"tablet" | my_string | string | default | tablet |
} | my_color | color | \#ff0000 | \#0000ff |
] | my_float | float | 60vp | 80vp |
} | my_image | media | my_image.png(太阳图标) | my_image.png(月亮图标) |
//resources/tablet/element/color.json
{ 在代码中通过 "$r('app.type.name')" 的形式使用应用资源,并分别在默认设备和平板上查看代码的运行效果,可以发现同一资源在不同设备上的取值不同。
"color":[
{ ![zh-cn_image_0000001325731389](figures/zh-cn_image_0000001325731389.png)
"name":"my_color",
"value":"#0000ff"
} ```
] @Entry
} @Component
//resources/tablet/element/float.json struct Index {
{ build() {
"float":[ Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
{ Text($r("app.string.my_string"))
"name":"my_float", .fontSize($r("app.float.my_float"))
"value":"80vp" .fontColor($r("app.color.my_color"))
} Image($r("app.media.my_image"))
] .width(100)
} .height(100)
``` }
.width('100%')
![zh-cn_image_0000001267577314](figures/zh-cn_image_0000001267577314.png) .height('100%')
}
页面源码如下: }
```
```ts
@Entry ## 系统资源
@Component
struct Index { 除了自定义资源,开发者也可以使用系统中预定义的资源(即[分层参数](visual-basics.md),同一资源ID在设备类型、深浅色等不同配置下有不同的取值)。
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { 在开发过程中,分层参数的用法与资源限定词基本一致。开发者可以通过"$r('sys.type.resource_id')"的形式引用系统资源。sys代表是系统资源;type代表资源类型,值可以取color、float、string和media;resource_id代表资源id。
Text($r("app.string.my_string"))
.fontSize($r("app.float.my_float")) 可以查看本文[应用UX设计中关于资源的介绍](design-resources.md),获取OpenHarmony支持的系统资源ID及其在不同配置下的取值。
.fontColor($r("app.color.my_color"))
Image($r("app.media.my_image")) > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
.width(100) > - 仅声明式开发范式支持使用分层参数,类Web开发范式不支持。
.height(100) >
} > - 系统资源可以保证不同团队开发出的应用有较为一致的视觉风格。对于系统预置应用,强烈建议使用系统资源;对于三方应用,可以根据需要选择使用系统资源或自定义应用资源。
.width('100%') >
.height('100%') > - 可以查看[OpenHarmony/resources代码仓](https://gitee.com/openharmony/resources/tree/master/systemres/main/resources)了解系统预置资源的实现,这里的目录结构与工程中的resources目录类似,也是通过资源限定词匹配不同的设备或设备状态。
}
}
```
## 系统资源
除了自定义资源,开发者也可以使用系统中预定义的资源(即[分层参数](visual-style-basics.md),同一资源ID在设备类型、深浅色等不同配置下有不同的取值)。
在开发过程中,分层参数的用法与资源限定词基本一致。开发者可以通过"$r('sys.type.resource_id')"的形式引用系统资源。sys代表是系统资源;type代表资源类型,值可以取color、float、string和media;resource_id代表资源id。
可以访问本文"[资源](resource.md)",获取OHOS上支持的系统资源ID及其在不同配置下的取值。也可以访问[OpenHarmony/resources代码仓](https://gitee.com/openharmony/resources/tree/master/systemres/main/resources),了解OpenHarmony系统中预置的分层参数资源,可以发现这里目录结构与工程中的resources目录类似,也是通过资源限定词匹配不同的设备或设备状态。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 仅声明式开发范式支持使用分层参数,类Web开发范式不支持。
# 典型场景
当基本的自适应布局无法满足多终端上屏幕的体验要求时,我们可以针对不同终端的屏幕特点,借助栅格系统和媒体查询能力,实现更复杂的布局效果。
## 缩进布局
在上一小节“栅格系统”中,我们介绍了四种不同的设备宽度类型,在不同宽度类型的设备中,默认的Margin、Gutter及Column数量不同。借助栅格系统,我们可以很方便的在不同宽度的设备上实现不同的缩进效果。
### 示例
![zh-cn_image_0000001317091985](figures/zh-cn_image_0000001317091985.png)
```ts
@Entry
@Component
struct IndentationSample {
build() {
Row() {
GridContainer() {
Column() {
ForEach([0, 1, 2, 4], () => {
Column() {
ItemContent()
}.useSizeType({ xs: 2, sm: 4, md: 6, lg: 8 })
})
}
}
}
.alignItems(VerticalAlign.Center)
.height('100%')
.backgroundColor('#F1F3F5')
}
}
@Component
struct ItemContent {
build() {
Column() {
Row() {
Row() {}
.width(28).height(28).borderRadius(14).margin({ right: 15 })
.backgroundColor('#E4E6E8')
Row() {}
.width('30%').height(20).borderRadius(4)
.backgroundColor('#E4E6E8')
}.width('100%').height(28)
Row() {}
.width('100%').height(68).borderRadius(16).margin({ top: 12 })
.backgroundColor('#E4E6E8')
}
.height(128)
.borderRadius(24)
.backgroundColor('#FFFFFF')
.padding({ top: 12, bottom: 12, left: 18, right: 18 })
.margin({ bottom: 12 })
}
}
```
## 挪移布局
挪移布局是栅格和折行能力的结合。当屏幕宽度发生改变,达到预设的断点时,栅格中子元素占据的列数会随着开发者的配置发生改变。当一行中的列数超过栅格组件在该断点的指定值时,可以自动换行。借助挪移布局,我们可以很方便的实现内容尺寸及相对位置的调整。
### 示例
当屏幕宽度发生变化时,图片和文字由”上下布局”切换为”左右布局”。
![zh-cn_image_0000001317211889](figures/zh-cn_image_0000001317211889.png)
```ts
@Entry
@Component
struct DiversionSample {
build() {
Row() {
GridContainer() {
Flex({
direction: FlexDirection.Row,
alignItems: ItemAlign.Center,
justifyContent: FlexAlign.Center,
wrap: FlexWrap.Wrap
}) {
Row() {
Image($r('app.media.illustrator'))
}
.aspectRatio(1)
.useSizeType({ xs: 2, sm: 4, md: 4, lg: 6 })
Flex({
direction: FlexDirection.Column,
alignItems: ItemAlign.Center,
justifyContent: FlexAlign.Center
}) {
Text('用户体验改进计划')
.textAlign(TextAlign.Center)
.fontSize(20)
.fontWeight(FontWeight.Medium)
Text('用户体验改进计划通过系统、应用分析、故障诊断,提升华为的产品和服务质量')
.textAlign(TextAlign.Center)
.fontSize(14)
.fontWeight(FontWeight.Medium)
}
.height(100)
.useSizeType({ xs: 2, sm: 4, md: 4, lg: 6 })
}
}
}.height('100%')
.alignItems(VerticalAlign.Center)
.backgroundColor('#F1F3F5')
}
}
```
## 重复布局
充分利用屏幕尺寸优势,当屏幕变宽时,增加显示元素的数量。注意这种场景下,组件的数量发生了变化。可以使用媒体查询改变元素数量,同时借助栅格系统设置这些元素在不同宽度设备下的尺寸和位置。
### 示例
![zh-cn_image_0000001268611858](figures/zh-cn_image_0000001268611858.png)
```ts
import mediaquery from '@ohos.mediaquery'
@Entry
@Component
struct RepeatSample {
@State isWidescreen: boolean = false;
private listener: mediaquery.MediaQueryListener = mediaquery.matchMediaSync('(width > 1200)');
onWidthChange = (mediaQueryResult) => {
if (mediaQueryResult.matches) {
this.isWidescreen = true;
} else {
this.isWidescreen = false;
}
}
private aboutToAppear(): void {
this.listener.on('change', this.onWidthChange);
}
private aboutToDisappear(): void {
this.listener.off('change', this.onWidthChange);
}
build() {
Row() {
GridContainer() {
ForEach([0, 1, 2, 3], () => {
Row() {
Column() { RepeatItemContent() }
.useSizeType({
xs: { span: 2, offset: 0 }, sm: { span: 4, offset: 0 },
md: { span: 4, offset: 0 }, lg: { span: 6, offset: 0 }
})
if (this.isWidescreen) {
Column() { RepeatItemContent() }
.useSizeType({
md: { span: 4, offset: 4 }, lg: { span: 6, offset: 6 }
})
}
}
})
}
}
.height('100%')
.backgroundColor('#F1F3F5')
}
}
@Component
struct RepeatItemContent {
build() {
Flex() {
Row() {}.width(43).height(43).borderRadius(12).backgroundColor('#E4E6E8')
Flex({ alignItems: ItemAlign.Start, direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceAround }) {
Row() {}.height(10).width('100%').backgroundColor('#E4E6E8')
Row() {}.height(10).backgroundColor('#E4E6E8').width('50%')
}.flexGrow(1).margin({ left: 13 })
}
.padding({ top: 13, bottom: 13, left: 13, right: 37 })
.height(69)
.backgroundColor('#FFFFFF')
.margin({ bottom: 12 })
.borderRadius(24)
}
}
```
# 响应式布局
自适应布局可以保证窗口尺寸在一定范围内变化时,页面的显示是正常的。但是将窗口尺寸变化较大时(如窗口宽度从400vp变化为1000vp),仅仅依靠自适应布局可能出现图片异常放大或页面内容稀疏、留白过多等问题,此时就需要借助响应式布局能力调整页面结构。
响应式布局是指页面内的元素可以根据特定的特征(如窗口宽度、屏幕方向等)自动变化以适应外部容器变化的布局能力。响应式布局中最常使用的特征是窗口宽度,可以将窗口宽度划分为不同的范围(下文中称为断点)。当窗口宽度从一个断点变化到另一个断点时,改变页面布局(如将页面内容从单列排布调整为双列排布甚至三列排布等)以获得更好的显示效果。
当前OpenHarmony提供了如下三种响应式布局能力,后文中我们将依次展开介绍。
| 响应式布局能力 | 简介 |
| -------- | -------- |
| [断点](#断点) | 将窗口宽度划分为不同的范围(即断点),监听窗口尺寸变化,当断点改变时同步调整页面布局。 |
| [媒体查询](#媒体查询) | 媒体查询支持监听窗口宽度、横竖屏、深浅色、设备类型等多种媒体特征,当媒体特征发生改变时同步调整页面布局。 |
| [栅格布局](#栅格布局) | 栅格组件将其所在的区域划分为有规律的多列,通过调整不同断点下的栅格组件的参数以及其子组件占据的列数等,实现不同的布局效果。 |
## 断点
断点以应用窗口宽度为切入点,将应用窗口在宽度维度上分成了几个不同的区间即不同的断点,在不同的区间下,开发者可根据需要实现不同的页面布局效果。具体的断点如下所示。
| 断点名称 | 取值范围(vp) |
| -------- | -------- |
| xs | [0,&nbsp;320) |
| sm | [320,&nbsp;520) |
| md | [520,&nbsp;840) |
| lg | [840,&nbsp;+∞) |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 以设备屏幕宽度作为参照物,也可以实现类似的效果。考虑到应用可能以非全屏窗口的形式显示,以应用窗口宽度为参照物更为通用。
>
> - 开发者可以根据实际使用场景决定适配哪些断点。如xs断点对应的一般是智能穿戴类设备,如果确定某页面不会在智能穿戴设备上显示,则可以不适配xs断点。
OpenHarmony提供了多种方法,判断应用当前处于何种断点,进而可以调整应用的布局。常见的监听断点变化的方法如下所示:
- 获取窗口对象并监听窗口尺寸变化
- 通过媒体查询监听应用窗口尺寸变化
- 借助栅格组件能力监听不同断点的变化
本小节中,先介绍如何通过窗口对象监听断点变化,后续的媒体查询及栅格章节中,将进一步展开介绍另外两种方法。
通过窗口对象监听断点变化的核心是获取窗口对象及注册窗口尺寸变化的回调函数。
1. 在Ability的[onWindowStageCreate](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ability/stage-ability.md)生命周期回调中,获取并记录[窗口](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-window.md)对象。
```
// MainAbility.ts
import window from '@ohos.window'
export default class MainAbility extends Ability {
...
onWindowStageCreate(windowStage) {
window.getTopWindow(this.context).then((windowObj) => {
AppStorage.SetOrCreate('windowObj', windowObj)
})
}
...
}
```
2. 在页面中,通过窗口对象获取启动时的应用窗口宽度,同时注册回调函数监听窗口尺寸变化。
```
@Entry
@Component
struct Index {
@State private currentBreakpoint: string = 'sm'
private updateBreakpoint(windowWidth) {
if (windowWidth < 320) {
this.currentBreakpoint = 'xs'
return
}
if (windowWidth < 520) {
this.currentBreakpoint = 'sm'
return
}
if (windowWidth < 840) {
this.currentBreakpoint = 'md'
return
}
this.currentBreakpoint = 'lg'
}
aboutToAppear() {
let windowObj: window.Window = AppStorage.Get('windowObj')
// 获取应用启动时的窗口尺寸
windowObj.getProperties().then((windowProperties) => {
this.updateBreakpoint(px2vp(windowProperties.windowRect.width))
})
// 注册回调函数,监听窗口尺寸变化
windowObj.on('windowSizeChange', (data) => {
this.updateBreakpoint(px2vp(data.width))
});
}
aboutToDisappear() {
let windowObj: window.Window = AppStorage.Get('windowObj')
windowObj.off('windowSizeChange')
}
build() {
Flex({justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center}) {
Text(this.currentBreakpoint).fontSize(50).fontWeight(FontWeight.Medium)
}
.width('100%')
.height('100%')
}
}
```
3. 运行及验证效果。
| | | |
| -------- | -------- | -------- |
| ![zh-cn_image_0000001336485520](figures/zh-cn_image_0000001336485520.jpg) | ![zh-cn_image_0000001386645965](figures/zh-cn_image_0000001386645965.jpg) | ![zh-cn_image_0000001386325621](figures/zh-cn_image_0000001386325621.jpg) |
## 媒体查询
在实际应用开发过程中,开发者常常需要针对不同类型设备或同一类型设备的不同状态来修改应用的样式。媒体查询提供了丰富的媒体特征监听能力,可以监听应用显示区域变化、横竖屏、深浅色、设备类型等等,因此在应用开发过程中使用的非常广泛。
本小节仅介绍**媒体查询跟断点的结合**,即如何借助媒体查询能力,监听断点的变化,读者可以自行查阅官网中关于[媒体查询](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/ui-ts-layout-mediaquery.md)的相关介绍了解更详细的用法。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 类Web开发范式,支持在js文件和css文件中使用媒体查询,请查看[js媒体查询](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-mediaquery.md)和[css媒体查询](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-common-mediaquery.md)了解详细用法。
**示例:**
通过媒体查询,监听应用窗口宽度变化,获取当前应用所处的断点值。
| | | |
| -------- | -------- | -------- |
| ![zh-cn_image_0000001336165712](figures/zh-cn_image_0000001336165712.jpg) | ![zh-cn_image_0000001386485617](figures/zh-cn_image_0000001386485617.jpg) | ![zh-cn_image_0000001386805569](figures/zh-cn_image_0000001386805569.jpg) |
```
// common/breakpointsystem.ets
// 对通过媒体查询监听断点的功能做简单的封装,方便后续使用
import mediaquery from '@ohos.mediaquery';
export class BreakpointType<T> {
sm: T
md: T
lg: T
constructor(sm: T, md: T, lg: T) {
this.sm = sm
this.md = md
this.lg = lg
}
GetValue(currentBreakpoint: string) {
if (currentBreakpoint === 'sm') {
return this.sm
}
if (currentBreakpoint === 'md') {
return this.md
}
if (currentBreakpoint === 'lg') {
return this.lg
}
return undefined
}
}
export class BreakpointSystem {
private currentBreakpoint: string = 'md'
private smListener: mediaquery.MediaQueryListener
private mdListener: mediaquery.MediaQueryListener
private lgListener: mediaquery.MediaQueryListener
private updateCurrentBreakpoint(breakpoint: string) {
if (this.currentBreakpoint !== breakpoint) {
this.currentBreakpoint = breakpoint
AppStorage.Set<string>('currentBreakpoint', this.currentBreakpoint)
}
}
private isBreakpointSM = (mediaQueryResult) => {
if (mediaQueryResult.matches) {
this.updateCurrentBreakpoint('sm')
}
}
private isBreakpointMD = (mediaQueryResult) => {
if (mediaQueryResult.matches) {
this.updateCurrentBreakpoint('md')
}
}
private isBreakpointLG = (mediaQueryResult) => {
if (mediaQueryResult.matches) {
this.updateCurrentBreakpoint('lg')
}
}
public register() {
this.smListener = mediaquery.matchMediaSync("(320vp<width<520vp)")
this.smListener.on("change", this.isBreakpointSM)
this.mdListener = mediaquery.matchMediaSync("(520vp<width<840vp)")
this.mdListener.on("change", this.isBreakpointMD)
this.lgListener = mediaquery.matchMediaSync("(840vp<width)")
this.lgListener.on("change", this.isBreakpointLG)
}
public unregister() {
this.smListener.off("change", this.isBreakpointSM)
this.mdListener.off("change", this.isBreakpointMD)
this.lgListener.off("change", this.isBreakpointLG)
}
}
// MediaQuerySample.ets
import { BreakpointSystem, BreakpointType } from '../common/breakpointsystem'
@Entry
@Component
struct MediaQuerySample {
@StorageLink('currentBreakpoint') private currentBreakpoint: string = "md";
@State private icon: Resource = $r('app.media.md')
private breakpointSystem: BreakpointSystem = new BreakpointSystem()
aboutToAppear() {
this.breakpointSystem.register()
}
aboutToDisappear() {
this.breakpointSystem.unregister()
}
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Image(new BreakpointType($r('app.media.sm'), $r('app.media.md'), $r('app.media.lg')).GetValue(this.currentBreakpoint))
.height(100)
.width(100)
.objectFit(ImageFit.Contain)
Text(this.currentBreakpoint)
.fontSize(24)
.margin(10)
}
.width('100%')
.height('100%')
}
}
```
## 栅格布局
## <sub>栅格</sub>
栅格是多设备场景下通用的辅助定位工具,通过将空间分割为有规律的栅格。栅格可以显著降低适配不同屏幕尺寸的设计及开发成本,使得整体设计和开发流程更有秩序和节奏感,同时也保证多设备上应用显示的协调性和一致性,提升用户体验。
![zh-cn_image_0000001224173302](figures/zh-cn_image_0000001224173302.png)
栅格的样式由Margin、Gutter、Columns三个属性决定。
- Margin是相对应用窗口、父容器的左右边缘的距离,决定了内容可展示的整体宽度。
- Gutter是相邻的两个Column之间的距离,决定内容间的紧密程度。
- Columns是栅格中的列数,其数值决定了内容的布局复杂度。
单个Column的宽度是系统结合Margin、Gutter和Columns自动计算的,不需要也不允许开发者手动配置。
### 栅格布局
栅格布局就是栅格结合了断点,实现栅格布局能力的组件叫栅格组件。在实际使用场景中,可以根据需要配置不同断点下栅格组件中元素占据的列数,同时也可以调整Margin、Gutter、Columns的取值,从而实现不同的布局效果。
| sm断点 | md断点 |
| -------- | -------- |
| ![zh-cn_image_0000001336486244](figures/zh-cn_image_0000001336486244.jpg) | ![zh-cn_image_0000001386646685](figures/zh-cn_image_0000001386646685.jpg) |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - ArkUI在API 9对栅格组件做了重构,推出了新的栅格组件[GridRow](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-gridrow.md)和[GridCol](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-gridcol.md),同时原有的[GridContainer组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-gridcontainer.md)及[栅格设置](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-grid.md)已经废弃。
>
> - 本文中提到的栅格组件,如无特别说明,都是指GridRow和GridCol组件。
### 栅格组件的断点
栅格组件提供了丰富的断点定制能力。
**(一)开发者可以修改断点的取值范围,支持启用最多6个断点。**
- 基于本文断点小节介绍的推荐值,栅格组件默认提供xs、sm、md、lg四个断点。
- 栅格组件支持开发者修改断点的取值范围,除了默认的四个断点,还支持开发者启用xl和xxl两个额外的断点。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 断点并非越多越好,通常每个断点都需要开发者“精心适配”以达到最佳显示效果。
**示例1:**
修改默认的断点范围,同时启用xl和xxl断点。
图片右下角显示了当前设备屏幕的尺寸(即应用窗口尺寸),可以看到随着窗口尺寸发生变化,栅格的断点也相应发生了改变。(为了便于理解,下图中将设备的DPI设置为160,此时1vp=1px)
![window3](figures/window3.gif)
```
@Entry
@Component
struct GridRowSample1 {
@State private currentBreakpoint: string = 'unknown'
build() {
// 修改断点的取值范围同时启用更多断点,注意,修改的断点值后面必须加上vp单位。
GridRow(breakpoints: {value: ['600vp', '700vp', '800vp', '900vp', '1000vp'],
reference: BreakpointsReference.WindowSize}}) {
GridCol({span:{xs: 12, sm: 12, md: 12, lg:12, xl: 12, xxl:12}}) {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text(this.currentBreakpoint).fontSize(50).fontWeight(FontWeight.Medium)
}
}
}.onBreakpointChange((currentBreakpoint: string) => {
this.currentBreakpoint = currentBreakpoint
})
}
}
```
**(二)栅格断点默认以窗口宽度为参照物,同时还允许开发者配置为以栅格组件本身的宽度为参照物。**
栅格既可以用于页面整体布局的场景,也可以用于页面局部布局的场景。考虑到在实际场景中,存在应用窗口尺寸不变但是局部区域尺寸发生了变化的情况,栅格组件支持以自身宽度为参照物响应断点变化具有更大的灵活性。
**示例2:**
以栅格组件宽度为参考物响应断点变化。满足窗口尺寸不变,而部分内容区需要做响应式变化的场景。
为了便于理解,下图中自定义预览器的设备屏幕宽度设置为650vp。示例代码中将侧边栏的变化范围控制在[100vp, 600vp],那么右侧的栅格组件宽度相对应在[550vp, 50vp]之间变化。根据代码中对栅格断点的配置,栅格组件宽度发生变化时,其断点相应的发生改变。
![component](figures/component.gif)
```
@Entry
@Component
struct GridRowSample2 {
@State private currentBreakpoint: string = 'unknown';
build() {
// 用户可以通过拖拽侧边栏组件中的分隔线,调整侧边栏和内容区的宽度。
SideBarContainer(SideBarContainerType.Embed)
{
// 侧边栏,尺寸变化范围 [100vp, 600vp]
Column(){}.width('100%').backgroundColor('#19000000')
// 内容区,尺寸变化范围 [窗口宽度550vp, 窗口宽度50vp]
GridRow({breakpoints: {value: ['100vp', '200vp', '300vp', '400vp', '500vp'],
reference: BreakpointsReference.ComponentSize}}) {
GridCol({span:{xs: 12, sm: 12, md: 12, lg:12, xl: 12, xxl:12}}) {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text(this.currentBreakpoint).fontSize(50).fontWeight(FontWeight.Medium)
}
}
}.onBreakpointChange((currentBreakpoint: string) => {
this.currentBreakpoint = currentBreakpoint;
}).width('100%')
}
// 侧边栏拖拽到最小宽度时,不自动隐藏
.autoHide(false)
.sideBarWidth(100)
// 侧边栏的最小宽度
.minSideBarWidth(100)
// 侧边栏的最大宽度
.maxSideBarWidth(600)
}
}
```
**(三)栅格组件的断点发生变化时,会通过onBreakPointChange事件通知开发者。**
在之前的两个例子中,已经演示了onBreakpointChange事件的用法,此处不再赘述。
### 栅格组件的columns、gutter和margin
栅格组件columns默认为12列,gutter默认为0,同时支持开发者根据实际需要定义不同断点下的columns数量以及gutter长度。特别的,在栅格组件实际使用过程中,常常会发生多个元素占据的列数相加超过总列数而折行的场景。栅格组件还允许开发者分别定义水平方向的gutter(相邻两列之间的间距)和垂直方向的gutter(折行时相邻两行之间的间距)。
考虑到[组件通用属性](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-size.md)中已经有margin和padding,栅格组件不再单独提供额外的margin属性,直接使用通用属性即可。借助margin或者padding属性,均可以控制栅格组件与父容器左右边缘的距离,但是二者也存在一些差异:
- margin区域在栅格组件的边界外,padding区域在栅格组件的边界内。
- 栅格组件的backgroundColor会影响padding区域,但不会影响margin区域。
总的来讲,margin在组件外而padding在组件内,开发者可以根据实际需要进行选择及实现目标效果。
**示例3:**
不同断点下,定义不同的columns和gutter。
| sm | md | lg |
| -------- | -------- | -------- |
| ![zh-cn_image_0000001386807405](figures/zh-cn_image_0000001386807405.jpg) | ![zh-cn_image_0000001336167540](figures/zh-cn_image_0000001336167540.jpg) | ![zh-cn_image_0000001386487457](figures/zh-cn_image_0000001386487457.jpg) |
```
@Entry
@Component
struct GridRowSample3 {
private bgColors: ResourceColor[] = [
$r('sys.color.ohos_id_color_palette_aux1'),
$r('sys.color.ohos_id_color_palette_aux2'),
$r('sys.color.ohos_id_color_palette_aux3'),
$r('sys.color.ohos_id_color_palette_aux4'),
$r('sys.color.ohos_id_color_palette_aux5'),
$r('sys.color.ohos_id_color_palette_aux6')
]
build() {
// 配置不同断点下columns和gutter的取值
GridRow({columns: {sm: 4, md: 8, lg: 12},
gutter: {x: {sm: 8, md: 16, lg: 24}, y: {sm: 8, md: 16, lg: 24}}}) {
ForEach(this.bgColors, (bgColor)=>{
GridCol({span: {sm: 2, md: 2, lg: 2}}) {
Row().backgroundColor(bgColor).height(30)
}
})
}
}
}
```
**示例4:**
通过通用属性margin或者padding,均可以控制栅格组件与其父容器左右两侧的距离,但padding区域计算在栅格组件内而margin区域计算在栅格组件外。此外,借助onBreakpointChange事件,还可以改变不同断点下margin或padding值。
![zh-cn_image_0000001336327452](figures/zh-cn_image_0000001336327452.png)
```
@Entry
@Component
struct GridRowSample4 {
@State private gridMargin: number = 0
build() {
Column() {
Row().width('100%').height(30)
// 使用padding控制栅格左右间距
GridRow() {
GridCol({span:{xs: 12, sm: 12, md: 12, lg:12}}) {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text("padding").fontSize(24).fontWeight(FontWeight.Medium)
}.backgroundColor('#19000000')
}
}
.height(50)
.borderWidth(2)
.borderColor('#F1CCB8')
.padding({left: this.gridMargin, right: this.gridMargin})
// 借助断点变化事件配置不同断点下栅格组件的左右间距值
.onBreakpointChange((currentBreakpoint: string) => {
if (currentBreakpoint === 'lg' || currentBreakpoint === 'md') {
this.gridMargin = 24
} else {
this.gridMargin = 12
}
})
Row().width('100%').height(30)
// 使用margin控制栅格左右间距
GridRow() {
GridCol({span:{xs: 12, sm: 12, md: 12, lg:12}}) {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text("margin").fontSize(24).fontWeight(FontWeight.Medium)
}.backgroundColor('#19000000')
}
}
.height(50)
.borderWidth(2)
.borderColor('#F1CCB8')
.margin({left: this.gridMargin, right: this.gridMargin})
}
}
}
```
### 栅格组件的span、offset和order
栅格组件(GridRow)的直接孩子节点只可以是栅格子组件(GridCol),GridCol组件支持配置span、offset和order三个参数。这三个参数的取值按照"xs -&gt; sm -&gt; md -&gt; lg -&gt; xl -&gt; xxl"的向后方向具有继承性(不支持向前方向的继承性),例如将sm断点下span的值配置为3,不配置md断点下span的值,则md断点下span的取值也是3。
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
| -------- | -------- | -------- | -------- | -------- |
| span | {xs?:&nbsp;number,&nbsp;sm?:&nbsp;number,&nbsp;md?:&nbsp;number,&nbsp;lg?:&nbsp;number,&nbsp;xl?:&nbsp;number,&nbsp;xxl?:number} | 是 | - | 在栅格中占据的列数。span为0,意味着该元素既不参与布局计算,也不会被渲染。 |
| offset | {xs?:&nbsp;number,&nbsp;sm?:&nbsp;number,&nbsp;md?:&nbsp;number,&nbsp;lg?:&nbsp;number,&nbsp;xl?:&nbsp;number,&nbsp;xxl?:number} | 否 | 0 | 相对于前一个栅格子组件偏移的列数。 |
| order | {xs?:&nbsp;number,&nbsp;sm?:&nbsp;number,&nbsp;md?:&nbsp;number,&nbsp;lg?:&nbsp;number,&nbsp;xl?:&nbsp;number,&nbsp;xxl?:number} | 否 | 0 | 元素的序号,根据栅格子组件的序号,从小到大对栅格子组件做排序。 |
**示例5:**
通过span参数配置GridCol在不同断点下占据不同的列数。特别的,将md断点下和6的span配置为0,这样在md断点下3和6不会渲染和显示。
| sm | md | lg |
| -------- | -------- | -------- |
| ![zh-cn_image_0000001336487884](figures/zh-cn_image_0000001336487884.jpg) | ![zh-cn_image_0000001386648317](figures/zh-cn_image_0000001386648317.jpg) | ![zh-cn_image_0000001386327997](figures/zh-cn_image_0000001386327997.jpg) |
```
@Entry
@Component
struct GridRowSample5 {
private elements: Object[] = [
{'index': 1, 'color': $r('sys.color.ohos_id_color_palette_aux1')},
{'index': 2, 'color': $r('sys.color.ohos_id_color_palette_aux2')},
{'index': 3, 'color': $r('sys.color.ohos_id_color_palette_aux3')},
{'index': 4, 'color': $r('sys.color.ohos_id_color_palette_aux4')},
{'index': 5, 'color': $r('sys.color.ohos_id_color_palette_aux5')},
{'index': 6, 'color': $r('sys.color.ohos_id_color_palette_aux6')},
]
build() {
GridRow() {
ForEach(this.elements, (item)=>{
GridCol({span: {sm: 6, md: (item.index % 3 === 0) ? 0 : 4, lg: 3}}) {
Row() {
Text('' + item.index).fontSize(24)
}
.justifyContent(FlexAlign.Center)
.backgroundColor(item.color).height(30)
}
})
}
}
}
```
**示例6:**
通过offset参数,配置GridCol相对其前一个兄弟间隔的列数。
| sm | md | lg |
| -------- | -------- | -------- |
| ![zh-cn_image_0000001386807873](figures/zh-cn_image_0000001386807873.jpg) | ![zh-cn_image_0000001336168020](figures/zh-cn_image_0000001336168020.jpg) | ![zh-cn_image_0000001386487913](figures/zh-cn_image_0000001386487913.jpg) |
```
@Entry
@Component
struct GridRowSample6 {
private elements: Object[] = [
{'index': 1, 'color': $r('sys.color.ohos_id_color_palette_aux1')},
{'index': 2, 'color': $r('sys.color.ohos_id_color_palette_aux2')},
{'index': 3, 'color': $r('sys.color.ohos_id_color_palette_aux3')},
{'index': 4, 'color': $r('sys.color.ohos_id_color_palette_aux4')},
{'index': 5, 'color': $r('sys.color.ohos_id_color_palette_aux5')},
{'index': 6, 'color': $r('sys.color.ohos_id_color_palette_aux6')},
]
build() {
GridRow() {
ForEach(this.elements, (item)=>{
GridCol({span: {sm: 6, md: 4, lg: 3}, offset: {sm: 0, md: 2, lg: 1} }) {
Row() {
Text('' + item.index).fontSize(24)
}
.justifyContent(FlexAlign.Center)
.backgroundColor(item.color).height(30)
}
})
}
}
}
```
**示例7:**
通过order属性,控制GridCol的顺序。在sm和md断点下,按照至6的顺序排列显示;在lg断点下,按照6至1的顺序排列显示。
| sm | md | lg |
| -------- | -------- | -------- |
| ![zh-cn_image_0000001336327916](figures/zh-cn_image_0000001336327916.jpg) | ![zh-cn_image_0000001336008356](figures/zh-cn_image_0000001336008356.jpg) | ![zh-cn_image_0000001336487888](figures/zh-cn_image_0000001336487888.jpg) |
```
@Entry
@Component
struct GridRowSample7 {
private elements: Object[] = [
{'index': 1, 'color': $r('sys.color.ohos_id_color_palette_aux1')},
{'index': 2, 'color': $r('sys.color.ohos_id_color_palette_aux2')},
{'index': 3, 'color': $r('sys.color.ohos_id_color_palette_aux3')},
{'index': 4, 'color': $r('sys.color.ohos_id_color_palette_aux4')},
{'index': 5, 'color': $r('sys.color.ohos_id_color_palette_aux5')},
{'index': 6, 'color': $r('sys.color.ohos_id_color_palette_aux6')},
]
build() {
GridRow() {
ForEach(this.elements, (item)=>{
GridCol({span: {sm: 6, md: 4, lg: 3}, order: {lg: (6-item.index)}}) {
Row() {
Text('' + item.index).fontSize(24)
}
.justifyContent(FlexAlign.Center)
.backgroundColor(item.color).height(30)
}
})
}
}
}
```
**示例8:**
仅配置sm和lg断点下span、offset和order参数的值,则md断点下这三个参数的取值与sm断点相同(按照“sm-&gt;md-&gt;lg”的向后方向继承)。
| sm | md | lg |
| -------- | -------- | -------- |
| ![zh-cn_image_0000001386648321](figures/zh-cn_image_0000001386648321.jpg) | ![zh-cn_image_0000001386328001](figures/zh-cn_image_0000001386328001.jpg) | ![zh-cn_image_0000001386807877](figures/zh-cn_image_0000001386807877.jpg) |
```
@Entry
@Component
struct GridRowSample8 {
private elements: Object[] = [
{'index': 1, 'color': $r('sys.color.ohos_id_color_palette_aux1')},
{'index': 2, 'color': $r('sys.color.ohos_id_color_palette_aux2')},
{'index': 3, 'color': $r('sys.color.ohos_id_color_palette_aux3')},
{'index': 4, 'color': $r('sys.color.ohos_id_color_palette_aux4')},
{'index': 5, 'color': $r('sys.color.ohos_id_color_palette_aux5')},
{'index': 6, 'color': $r('sys.color.ohos_id_color_palette_aux6')},
]
build() {
GridRow() {
ForEach(this.elements, (item)=>{
// 不配置md断点下三个参数的值,则其取值与sm断点相同
GridCol({span: {sm:4, lg: 3}, offset: {sm: 2, lg: 1},
order: {sm: (6-item.index), lg: item.index}}) {
Row() {
Text('' + item.index).fontSize(24)
}
.justifyContent(FlexAlign.Center)
.backgroundColor(item.color).height(30)
}
})
}
}
}
```
### 栅格组件的嵌套使用
栅格组件可以嵌套使用以满足复杂场景的需要。
**示例9:**
| sm | md | lg |
| -------- | -------- | -------- |
| ![zh-cn_image_0000001336338670](figures/zh-cn_image_0000001336338670.jpg) | ![zh-cn_image_0000001336019094](figures/zh-cn_image_0000001336019094.jpg) | ![zh-cn_image_0000001336498646](figures/zh-cn_image_0000001336498646.jpg) |
```
@Entry
@Component
struct GridRowSample9 {
private elements: Object[] = [
{'index': 1, 'color': $r('sys.color.ohos_id_color_palette_aux1')},
{'index': 2, 'color': $r('sys.color.ohos_id_color_palette_aux2')},
{'index': 3, 'color': $r('sys.color.ohos_id_color_palette_aux3')},
{'index': 4, 'color': $r('sys.color.ohos_id_color_palette_aux4')},
{'index': 5, 'color': $r('sys.color.ohos_id_color_palette_aux5')},
{'index': 6, 'color': $r('sys.color.ohos_id_color_palette_aux6')},
]
build() {
GridRow() {
GridCol({span: {sm: 12, md: 10, lg: 8}, offset: {sm: 0, md: 1, lg: 2}}) {
GridRow() {
ForEach(this.elements, (item)=>{
GridCol({span: {sm: 6, md: 4, lg: 3}}) {
Row() {
Text('' + item.index).fontSize(24)
}
.justifyContent(FlexAlign.Center)
.backgroundColor(item.color).height(30)
}
})
}
.backgroundColor('#19000000')
.height('100%')
}
}
}
}
```
### 总结
如前所述,栅格组件提供了丰富的自定义能力,功能异常灵活和强大。只需要明确栅格在不同断点下的Columns、Margin、Gutter及span等参数,即可确定最终布局,无需关心具体的设备类型及设备状态(如横竖屏)等。栅格可以节约设计团队与开发团队的沟通成本,提升整体开发效率。
## 相关实例
针对栅格断点系统开发,有以下相关实例可供参考:
- [`Weather`:一多天气(eTS)(API9)](https://gitee.com/openharmony/applications_app_samples/tree/master/MultiDeviceAppDev/Weather)
# 概览
[短信](https://gitee.com/openharmony/applications_mms/tree/master)是OpenHarmony中预置的系统应用,主要包含信息查看、发送短信、接收短信、短信送达报告、删除短信等功能。在不同类型设备上,短信应用的功能完全相同,故短信应用适合使用[部署模型A](introduction.md#部署模型)(即:不同类型的设备上安装运行相同的HAP包或HAP包组合)。
本案例中,在会话详情页面利用[方舟开发框架](introduction.md#方舟开发框架)提供的“一多”能力,用一套代码同时适配默认设备和平板。
## 工程结构
短信应用的工程结构如下图所示,当前该应用的功能较少,所以直接使用了DevEco Studio创建出的默认工程结构。具体采用何种形式的工程结构,并不影响应用的开发。但是使用推荐的工程结构,目录结构更清晰,拓展性也更好。
短信应用UI相关的逻辑集中在views和pages两个目录,分别存放公共组件及页面。当前短信应用主要包含如下页面:
- 信息列表页面:首页,展示信息列表。
- 通知信息列表页面:将通知类信息集中在一起展示,与信息列表页面类似。
- 会话详情页面:展示与某联系人的所有信息往来。
- 报告详情页面:信息发送报告的详情页面。
- 设置页面:消息设置页面,如是否展示送达报告等。
```
/Mms/
├── doc # 资料
├── entry
│ └── src
│ └── main
│ ├── resources # 资源配置文件存放目录
│ ├── config.json # 全局配置文件
│ └── ets # ets代码目录
│ ├── ServiceAbility # 后台常驻服务
│ └── default # 业务代码目录
│ ├── data # 自定义数据类型
│ ├── model # 对接数据库
│ ├── pages # 所有页面
│ │ ├── conversation # 会话详情页面
│ │ ├── conversationlist # 信息列表页面
│ │ ├── index # 初始页面
│ │ ├── info_msg # 通知信息列表页面
│ │ ├── query_report # 报告详情页面
│ │ └── settings # 设置页面
│ ├── service # 业务逻辑
│ ├── utils # 工具类
│ ├── views # 自定义组件
│ └── app.ets # 应用生命周期
├── signs # 签名
└── LICENSE
```
短信应用在开发阶段,采用了一层工程结构。由于功能较为简单,所以并没有规划共用的feature和common目录,仅采用了一层product目录。
- 业务形态层(product)
该目录采用IDE工程默认创建的entry目录,开发者可根据需要在创建Module时自行更改该目录名。不同产品形态,编译出相同的短信HAP包。
# 组合成型
现在会话详情页面的顶部标题栏、信息列表及底部输入栏都已经准备完毕,将这三部分组合起来即可得到完整的页面。
- 通过[Flex组件](../../reference/arkui-ts/ts-container-flex.md)将三个部分组合起来,注意justifyContent: FlexAlign.SpaceBetween配置项是将Flex组件中的元素按照主轴方向均匀分配,其中第一个元素与顶部对齐,最后一个元素与底部对齐。
- 通过[List组件](../../reference/arkui-ts/ts-container-list.md)[ForEach语法](../../ui/ts-rending-control-syntax-foreach.md),显示整个消息列表。
| 默认设备 | 平板 |
| -------- | -------- |
| ![zh-cn_image_0000001225812214](figures/zh-cn_image_0000001225812214.png) | ![zh-cn_image_0000001269812713](figures/zh-cn_image_0000001269812713.png) |
```ts
@Entry
@Component
struct Conversation {
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start,
justifyContent: FlexAlign.SpaceBetween }) {
Column() {
TopArea() // 顶部标题栏
List() { // 消息列表
ForEach(globalMessageList, (item, index) => {
ListItem() {
MessageItem({
isReceived: item.isReceived,
content: item.content,
time: item.time
})
})
}
.listDirection(Axis.Vertical)
.edgeEffect(EdgeEffect.Spring)
}
ButtomArea() // 底部输入栏
}
.backgroundColor("#F1F3F5")
.width('100%')
.height('100%')
}
}
```
# 底部输入栏
有了顶部工具栏的开发经验,可以发现底部输入栏的结构更为简单,它同样以Flex组件作为父容器,同时包含文本输入框(请访问[文本输入组件](../../reference/arkui-ts/ts-basic-components-textarea.md)查看详细介绍)和消息发送图标两个子节点。
![zh-cn_image_0000001285597989](figures/zh-cn_image_0000001285597989.jpg)
为了便于查看效果,我们同样给底部输入栏设置了淡蓝色的背景色。注意这里有一个特殊的地方,我们给TextArea设置了flexGrow(1)属性。flexGrow属性仅在父组件是Flex组件时生效,表示Flex容器的剩余空间分配给此属性所在的组件的比例,flexGrow(1)表示父容器的剩余空间全部分配给此组件,详见[Flex布局](../../reference/arkui-ts/ts-universal-attributes-flex-layout.md)
| 默认设备 | 平板 |
| -------- | -------- |
| ![zh-cn_image_0000001292656257](figures/zh-cn_image_0000001292656257.png) | ![zh-cn_image_0000001246337342](figures/zh-cn_image_0000001246337342.png) |
```
@Component
struct ButtomArea {
build() {
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
TextArea({ placeholder:'短信' })
.placeholderColor("#99000000")
.caretColor("#007DFF")
.backgroundColor("#F1F3F5")
.borderRadius(20)
.height(40)
.flexGrow(1) // 将父容器的剩余空间全部分配给此组件
Image($r("app.media.send"))
.height(36)
.width(36)
.opacity(0.4)
.margin({ left:12 })
}
.height(72)
.width('100%')
.padding({ left:24, right:24, bottom:8, top:8 })
.backgroundColor('#87CEFA') // 底部输入栏背景色,仅用于开发测试
}
}
```
# 信息列表
观察信息列表区域,可以发现它是由一个个消息气泡组成的,另外消息气泡在默认设备和平板上的布局有差异。本小节将围绕如下两个主题介绍如何实现消息列表。
- 如何实现自定义消息气泡组件。
- 如何在默认设备和平板上自适应布局。
| 默认设备 | 平板 |
| -------- | -------- |
| ![zh-cn_image_0000001224250574](figures/zh-cn_image_0000001224250574.jpg) | ![zh-cn_image_0000001225809618](figures/zh-cn_image_0000001225809618.png) |
## 消息气泡
先做一个最简单的消息气泡,通过borderRadius属性可以设置边框的圆角半径(详见[边框设置](../../reference/arkui-ts/ts-universal-attributes-border.md))。
| 默认设备 | 平板 |
| -------- | -------- |
| ![zh-cn_image_0000001313844881](figures/zh-cn_image_0000001313844881.png) | ![zh-cn_image_0000001313724825](figures/zh-cn_image_0000001313724825.png) |
```
@Component
struct MessageBubble {
private content: string = "OpenHarmony";
build() {
Column() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) {
Text(this.content)
.fontSize(16)
.lineHeight(21)
.padding({ left: 12, right: 12, top: 8, bottom: 8 })
.backgroundColor("#C0EBDF")
.borderRadius(24)
.fontColor("#182431")
}.width('100%')
}
.margin({left: 24, right: 24 })
.backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试
}
}
```
注意这个简单的消息气泡,左上角(或右上角)的样式,与实际期望不符。我们先修改发送消息右上角的样式,接收消息左上角的实现与之类似。
[Stack组件](../../reference/arkui-ts/ts-container-stack.md)是一个堆叠容器,其子组件按照轴方向依次堆叠,后一个子组件覆盖前一个子组件。通过其alignContent接口,可以设置子组件在容器内的对齐方式,如alignContent: Alignment.TopStart代表子组件从左上角对齐。
| 默认设备 | 平板 |
| -------- | -------- |
| ![zh-cn_image_0000001313604829](figures/zh-cn_image_0000001313604829.png) | ![zh-cn_image_0000001313523845](figures/zh-cn_image_0000001313523845.png) |
```
@Component
struct MessageBubble {
private content: string = "OpenHarmony";
private time: string = "今天 上午 10:35";
build() {
Column() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) {
Stack({ alignContent: Alignment.TopEnd }) { // 在左上角堆叠一个小色块
Column()
.backgroundColor("#C0EBDF")
.borderRadius(4)
.width(24)
.height(24)
Text(this.content)
.fontSize(16)
.lineHeight(21)
.padding({ left: 12, right: 12, top: 8, bottom: 8 })
.backgroundColor("#C0EBDF")
.borderRadius(24)
.fontColor("#182431")
}
}.width('100%')
}
.margin({left: 24, right: 24 })
.backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试
}
}
```
接下来我们在消息气泡下方加上时间显示,如下图所示,一个消息气泡自定义组件就基本完成了。
| 默认设备 | 平板 |
| -------- | -------- |
| ![zh-cn_image_0000001266163748](figures/zh-cn_image_0000001266163748.png) | ![zh-cn_image_0000001265685020](figures/zh-cn_image_0000001265685020.png) |
```
@Component
struct MessageBubble {
private content: string = "OpenHarmony";
private time: string = "上午 10:35";
build() {
Column() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) {
Stack({ alignContent: Alignment.TopEnd }) {
Column()
.backgroundColor("#C0EBDF")
.borderRadius(4)
.width(24)
.height(24)
Text(this.content)
.fontSize(16)
.lineHeight(21)
.padding({ left: 12, right: 12, top: 8, bottom: 8 })
.backgroundColor("#C0EBDF")
.borderRadius(24)
.fontColor("#182431")
}
}.width('100%')
// 在消息气泡底部增加时间显示
Flex({ alignItems: ItemAlign.Center, direction: FlexDirection.Row,
justifyContent: FlexAlign.End}) {
Text(this.time)
.textAlign(TextAlign.Start)
.fontSize(10)
.lineHeight(13)
.fontColor("#99182431")
}.width('100%').margin({ left: 12, right: 0 })
}
.margin({left: 24, right: 24 })
.backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试
}
}
```
发送出的消息和接收到的消息的消息气泡结构基本一致,可以通过增加一个标志位,让两种消息共用MessageBubble这个自定义组件,代码如下所示。将这个标志位设置true,可以查看接收消息的效果。
| 默认设备 | 平板 |
| -------- | -------- |
| ![zh-cn_image_0000001265844904](figures/zh-cn_image_0000001265844904.png) | ![zh-cn_image_0000001266004832](figures/zh-cn_image_0000001266004832.png) |
```
@Component
struct MessageBubble {
private isReceived:boolean=false; // 通过标志位,判断是发送or接收场景,进而使用不同的样式
private content:string="OpenHarmony";
private time:string="今天 10:00";
build() {
Column() {
Flex({ justifyContent:this.isReceived? FlexAlign.Start: FlexAlign.End,
alignItems: ItemAlign.Center }) {
Stack({ alignContent:this.isReceived? Alignment.TopStart: Alignment.TopEnd }) {
Column()
.backgroundColor(this.isReceived?"#FFFFFF":"#C0EBDF")
.borderRadius(4)
.width(24)
.height(24)
Text(this.content)
.fontSize(16)
.lineHeight(21)
.padding({ left:12, right:12, top:8, bottom:8 })
.backgroundColor(this.isReceived?"#FFFFFF":"#C0EBDF")
.borderRadius(24)
.fontColor("#182431")
}
}.width('100%')
Flex({ alignItems: ItemAlign.Center, direction: FlexDirection.Row,
justifyContent:this.isReceived? FlexAlign.Start: FlexAlign.End }) {
Text(this.time)
.textAlign(TextAlign.Start)
.fontSize(10)
.lineHeight(13)
.fontColor("#99182431")
}.width('100%')
.margin({ left:this.isReceived?12:0, right:this.isReceived?0:12 })
}
.margin({left:24, right:24 })
.backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试
}
}
```
## 栅格布局
回顾方舟开发框架一多能力,消息气泡在默认设备和平板上布局不同,可以借助栅格布局来解决。为了方便测试,我们预定义一个全局数组。
```
const globalMessageList:any[] = [
{
'time':'上午 10:20',
'content':'项目介绍',
'isReceived':false
},
{
'time':'上午 10:28',
'content':'OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及运营的开源项目,目标是面向全场景、全连接、全智能时代,基于开源的方式,搭建一个智能终端设备操作系统的框架和平台,促进万物互联产业的繁荣发展。',
'isReceived':false
},{
'time':'上午 10:32',
'content':'技术架构',
'isReceived':true
},
{
'time':'上午 10:35',
'content':'OpenHarmony整体遵从分层设计,从下向上依次为:内核层、系统服务层、框架层和应用层。系统功能按照“系统 > 子系统 > 组件”逐级展开,在多设备部署场景下,支持根据实际需求裁剪某些非必要的组件。',
'isReceived':true
}
];
```
结合[栅格组件](../../reference/arkui-ts/ts-container-gridcontainer.md)的定义,考虑我们当前的实际场景,GridContainer的各参数设置如下。
- columns:取默认值(auto),即根据设备尺寸自动设置栅格中的列数。
- sizeType:取默认值(SizeType.Auto),即根据设备类型自动选择。
- gutter:栅格布局列间距,当前场景未使用该参数,设置为0即可。
- margin: 栅格布局两侧间距,在开发消息气泡组件时,已经设置了左右间距,故该属性也配置为0。
栅格中仅包含我们自定义的消息气泡组件,该组件在各类型设备上的参数配置如下,可以通过[useSizeType属性](../../reference/arkui-ts/ts-universal-attributes-grid.md)设置消息气泡在不同场景下的尺寸和偏移值。
| SizeType类型 | 设备宽度(vp) | 设备总列数 | 消息气泡占用的列数 | 接收场景偏移的列数 | 发送场景偏移的列数 |
| -------- | -------- | -------- | -------- | -------- | -------- |
| XS | [0,&nbsp;320) | 2 | 2 | 0 | 0 |
| SM | [320,&nbsp;600) | 4 | 4 | 0 | 0 |
| MD | [600,&nbsp;840) | 8 | 6 | 0 | 2 |
| LG | [840,&nbsp;+∞) | 12 | 8 | 0 | 4 |
| 默认设备 | 平板 |
| -------- | -------- |
| ![zh-cn_image_0000001313844889](figures/zh-cn_image_0000001313844889.png) | ![zh-cn_image_0000001313724829](figures/zh-cn_image_0000001313724829.png) |
```
@Component
struct MessageItem {
private isReceived:boolean;
private content:string;
private time:string;
build() {
GridContainer({gutter:0, margin:0 }) {
Flex({ justifyContent: FlexAlign.End, alignItems: ItemAlign.End }) {
MessageBubble({
isReceived:this.isReceived,
content:this.content,
time:this.time
})
}
.useSizeType({
xs: { span:2, offset:0 },
sm: { span:4, offset:0 },
md: { span:6, offset:this.isReceived?0:2 },
lg: { span:8, offset:this.isReceived?0:4 }
})
}.width('100%')
}
}
@Entry
@Component
struct Conversation {
build() {
Column() { // 验证效果
MessageItem({
isReceived: globalMessageList[1].isReceived,
content: globalMessageList[1].content,
time: globalMessageList[1].time
})
MessageItem({
isReceived: globalMessageList[3].isReceived,
content: globalMessageList[3].content,
time: globalMessageList[3].time
})
}.backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试
}
}
```
# 页面结构
| 默认设备 | 平板 |
| -------- | -------- |
| ![zh-cn_image_0000001270045849](figures/zh-cn_image_0000001270045849.png) | ![zh-cn_image_0000001225486054](figures/zh-cn_image_0000001225486054.png) |
会话详情页面在默认设备和平板上的样式如上图所示,会话详情页面可以划分为三个部分:
| 页面组成 | 介绍 |
| -------- | -------- |
| 顶部标题栏 | ![zh-cn_image_0000001224250350](figures/zh-cn_image_0000001224250350.jpg) |
| 信息列表 | ![zh-cn_image_0000001268490361](figures/zh-cn_image_0000001268490361.jpg) |
| 底部输入栏 | ![zh-cn_image_0000001268250529](figures/zh-cn_image_0000001268250529.jpg) |
接下来我们详细介绍各部分的实现。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 为了方便理解,我们对会话详情页面做了一定的精简,本小节仅介绍会话详情页面最基础的实现。
# 顶部标题栏
| 默认设备 | 平板 |
| -------- | -------- |
| ![zh-cn_image_0000001268450593](figures/zh-cn_image_0000001268450593.jpg) | ![zh-cn_image_0000001225486202](figures/zh-cn_image_0000001225486202.png) |
顶部标题栏是一个简单的行布局,包含返回图标、联系人头像、联系人姓名和号码、拨号图标、设置图标共5个元素。其中,联系人姓名和号码以列布局的形式放在一起。
在默认设备和平板上,顶部标题栏的组件结构是相同的,仅联系人姓名和号码与拨号图标的间距不同。回顾方舟开发框架一多能力介绍,这个场景可以借助Blank组件使用拉伸能力。
我们先实现联系人姓名和号码,用Flex组件作为父容器,其包含两个Text子组件,分别用于存放联系人姓名和号码。Flex组件的属性设置如下:
- direction: FlexDirection.Column:子组件在Flex容器上以列的方式排布,即主轴是垂直方向。
- justifyContent: FlexAlign.Center:子组件在Flex容器主轴(垂直方向)上居中对齐。
- alignItems: ItemAlign.Start:子组件在Flex容器交叉轴(水平方向)上首部对齐。
可以查看[Flex组件](../../reference/arkui-ts/ts-container-flex.md)[Text组件](../../reference/arkui-ts/ts-basic-components-text.md)了解这两个组件各个属性的含义及详细用法。
| 默认设备 | 平板 |
| -------- | -------- |
| ![zh-cn_image_0000001246816566](figures/zh-cn_image_0000001246816566.png) | ![zh-cn_image_0000001292777537](figures/zh-cn_image_0000001292777537.png) |
```
@Component
struct TopArea {
build() {
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Start}) {
Text('张三').fontSize(16).fontColor("#182431")
Text('+123 4567 8901').fontSize(14).fontColor("#66182431")
}
}
}
```
接下来我们通过width属性和height属性设置四个图标的宽高(详见[尺寸设置](../../reference/arkui-ts/ts-universal-attributes-size.md)),并将它们与联系人姓名和电话以及Blank组件一起放到Flex父容器中。为了便于查看效果,对顶部标题栏设置了淡蓝色的背景色。
| 默认设备 | 平板 |
| -------- | -------- |
| ![zh-cn_image_0000001292777233](figures/zh-cn_image_0000001292777233.png) | ![zh-cn_image_0000001246497370](figures/zh-cn_image_0000001246497370.png) |
```
@Component
struct TopArea {
build() {
Flex({ alignItems: ItemAlign.Center }) {
Image($r('app.media.back'))
.width(24)
.height(24)
Image($r('app.media.contact'))
.width(40)
.height(40)
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Start}) {
Text('张三').fontSize(16).fontColor("#182431")
Text('+123 4567 8901').fontSize(14).fontColor("#66182431")
}
Blank() // 拉伸能力
Image($r("app.media.call"))
.width(24)
.height(24)
Image($r('app.media.dots'))
.width(24)
.height(24)
}
.width('100%')
.height(56)
.backgroundColor('#87CEFA') // 顶部标题栏背景色,仅用于开发测试
}
}
```
当前标题栏中子组件的布局同预期还有些差异,接下来通过margin属性,设置各个元素的左右间距(详见[尺寸设置](../../reference/arkui-ts/ts-universal-attributes-size.md))。如下图所示,最终顶部工具栏在默认设备和平板上都可以达到预期显示效果。
| 默认设备 | 平板 |
| -------- | -------- |
| ![zh-cn_image_0000001293015965](figures/zh-cn_image_0000001293015965.png) | ![zh-cn_image_0000001246656958](figures/zh-cn_image_0000001246656958.png) |
```
@Component
struct TopArea {
build() {
Flex({ alignItems: ItemAlign.Center }) {
Image($r('app.media.back'))
.width(24)
.height(24)
.margin({ left:24 }) // 设置间距
Image($r('app.media.contact'))
.width(40)
.height(40)
.margin({ left:16, right:16 }) // 设置间距
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Start}) {
Text('张三').fontSize(16).fontColor("#182431")
Text('+123 4567 8901').fontSize(14).fontColor("#66182431")
}
Blank()
Image($r("app.media.call"))
.width(24)
.height(24)
Image($r('app.media.dots'))
.width(24)
.height(24)
.margin({ left:16, right:24 }) // 设置间距
}
.width('100%')
.height(56)
.backgroundColor('#87CEFA') // 顶部标题栏背景色,仅用于开发测试
}
}
```
# 总结
短信应用在默认设备和平板上的功能完全相同,因此选择了部署模型A。借助方舟开发框架一多能力,短信应用实现了在默认设备和平板上共用同一份代码,同时自然也共用安装包。
在实际开发过程中,会话详情页面需要从底层做数据交互,同时还要支持信息选择、信息删除、信息发送状态、输入框与输入法联动等等功能,会比本小节中介绍的基础版本复杂很多。读者如果对这部分感兴趣,可以访问[短信应用开源代码仓](https://gitee.com/openharmony/applications_mms/tree/master),了解会话详情页面的详细实现。
# 从一个例子开始
本章通过一个天气应用,介绍一多应用的整体开发过程,包括UX设计、工程管理及调试、页面开发等。
## UX设计
本示例中的天气应用包含主页、管理城市和添加城市三个页面,其中主页中又包含菜单和更新间隔两个弹窗,基本业务逻辑如下所示。
![image-20220820153523548](figures/image-20220820153523548.png)
“一多”建议从最初的设计阶段开始就拉通多设备综合考虑。考虑实际智能终端设备种类繁多,设计师无法针对每种具体设备各自出一份UX设计图。“一多”建议从设备屏幕宽度的维度,将设备划分为四大类。设计师只需要针对这四大类设备做设计,而无需关心具体的设备形态。
| 设备类型 | 屏幕宽度(vp) |
| -------- | -------- |
| 超小设备 | [0,&nbsp;320) |
| 小设备 | [320,&nbsp;520) |
| 中设备 | [520,&nbsp;840) |
| 大设备 | [840,&nbsp;+∞) |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - vp是virtual pixel(虚拟像素)的缩写,是OpenHarmony中常用的长度单位,详见本文[视觉基础](visual-basics.md)小节中的介绍。
>
> - 此处基于设备屏幕宽度划分不同设备是为了读者方便理解。通常智能设备上的应用都是以全屏的形式运行,但随着移动技术的发展,当前部分智能设备支持应用以自由窗口模式运行(即用户可以通过拖拽等操作自由调整应用运行窗口的尺寸),故以应用窗口尺寸为基准进行划分更为合适,本文后续的响应式布局章节中将详细介绍相关内容。
>
> - OpenHarmony当前仅有默认设备和平板两种设备形态,IDE在创建OpenHarmony工程时也仅可以选择默认设备和平板。随着OpenHarmony的演进,其支持的设备形态会不断丰富,本文也会定期刷新相关介绍。
默认设备和平板对应于小设备、中设备及大设备,本示例以这三类设备场景为例,介绍不同设备上的UX设计。天气主页在不同设备上的设计图如下所示。
| | 小设备 | 中设备 | 大设备 |
| -------- | -------- | -------- | -------- |
| 主页 | ![zh-cn_image_0000001334020938](figures/zh-cn_image_0000001334020938.png) | ![zh-cn_image_0000001385380457](figures/zh-cn_image_0000001385380457.jpg) | ![zh-cn_image_0000001348546856](figures/zh-cn_image_0000001348546856.jpg) |
另外,大设备中天气主页还允许用户开启或者隐藏侧边栏。
| 开启侧边栏 | 隐藏侧边栏 |
| -------- | -------- |
| ![zh-cn_image_0000001334340566](figures/zh-cn_image_0000001334340566.jpg) | ![zh-cn_image_0000001385100509](figures/zh-cn_image_0000001385100509.jpg) |
从天气应用在各设备上的UX设计图中,可以观察到如下UX的一些“规律”:
- 在不同的屏幕宽度下,应用的整体风格基本保持一致。
- 在相近的屏幕宽度范围内,应用的布局基本不变;在不同的屏幕宽度范围内,应用的布局有较大差异。
- 应用在小屏幕下显示的元素,是大屏幕中显示元素的子集。
- 考虑到屏幕尺寸及显示效果,大屏幕中可以显示的元素数量一定不少于小屏幕。
- 为充分利用屏幕尺寸优势,大屏幕可以有其独有的元素或设计(如本示例中的侧边栏)。
如此,既在各设备上体现了UX的一致性,也在各设备上体现了UX的差异性,从而既可以保障各设备上应用界面的体验,也可以最大程度复用界面代码。
在本文[应用UX设计章节](ux-design.md)中,将详细介绍应用的UX设计规则。
## 工程管理及调试
在本文[IDE使用章节](ide-using.md)中,将详细介绍一多的工程创建及管理等,本小节仅介绍最基础的工程创建及多设备预览调试。
### 工程创建
一多应用的工程创建过程,与传统应用并无较大差异。只需在工程创建过程中,注意在“Device Type”选项中勾选所有该应用期望运行的目标设备类型,保证后续该应用可以在所有目标设备上正确安装即可。
![project](figures/project.png)
### 预览调试
在代码开发过程中,可以开启预览器,并打开“Multi-profile preview”开关,实时观察应用在不同设备下的表现。
![zh-cn_image_0000001384621049](figures/zh-cn_image_0000001384621049.jpg)
特别的,还可以点击“+ New Profile”按钮,新增自定义预览器。
![previewer](figures/previewer.jpg)
## 页面开发
天气应用中涉及较多的页面和弹窗,本小节以天气主页为例,简单介绍不同设备下的页面实现思路。天气应用已经在[OpenHarmony应用示例](https://gitee.com/openharmony/applications_app_samples/tree/master/MultiDeviceAppDev/Weather)中开源,感兴趣的读者可以自行下载及了解详细代码实现。
观察天气主页在不同设备上的UX设计图,可以进行如下设计:
- 将天气主页划分为9个基础区域,如:
![home_full](figures/home_full.png)
- 基础区域9仅在大设备上显示,基础区域1-8虽然在各设备上始终展示但其尺寸及区域内的布局基本保持不变,可以结合[自适应布局](adaptive-layout.md)能力以[自定义组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/ts-component-based-component.md)的形式分别实现这9个基础区域。
| | 小设备 | 中设备 | 大设备 |
| -------- | -------- | -------- | -------- |
| 主页 | ![Home_sm](figures/Home_sm.png) | ![Home_md_mark](figures/Home_md_mark.png) | ![Home_lg_mark](figures/Home_lg_mark.png) |
- 基础区域1-8之间的布局在不同设备上有较大差异,可以使用响应式布局中的[栅格布局](responsive-layout.md#栅格布局)能力实现组件间的布局效果。
- 展开和隐藏侧边栏的功能可以通过[侧边栏组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-sidebarcontainer.md)来实现。侧边栏是大设备上独有的,借助响应式布局中的[媒体查询](responsive-layout.md#媒体查询)能力,控制仅在大设备上展示侧边栏即可。
### 主页基础区域
天气主页中的9个基础区域介绍及实现方案如下表所示。
| 编号 | 简介 | 实现方案 |
| -------- | -------- | -------- |
| 1 | 标题栏 | 自适应布局拉伸能力 |
| 2 | 天气概览 | Row和Column组件,并指定其子组件按照主轴起始方向对齐或居中对齐。 |
| 3 | 每小时天气 | 自适应布局延伸能力 |
| 4 | 每日天气 | 自适应布局延伸能力 |
| 5 | 空气质量 | Canvas画布组件绘制空气质量图,并使用Row组件和Column组件控制内部元素的布局。 |
| 6 | 生活指数 | 自适应布局均分能力 |
| 7 | 日出日落 | Canvas画布组件绘制日出日落图 |
| 8 | 应用信息 | Row和Column组件,并指定其子组件居中对齐。 |
| 9 | 侧边导航栏 | 综合运用自适应布局中的拉伸能力、占比能力和延伸能力 |
天气主页涉及的内容较多,因篇幅限制,本小节仅介绍区域3(每小时天气)的实现,读者可以自行查看开源代码,了解其它基础区域的实现。
延伸能力是指容器组件内的子组件,按照其在列表中的先后顺序,随容器组件尺寸变化显示或隐藏。随着可用显示区域的增加,用户可以看到的“每小时天气”信息也不断增加,故“每小时天气”可以通过延伸能力实现,其核心代码如下所示。
```
@Component
export default struct HoursWeather {
...
build() {
// 通过列表组件实现延伸能力
List() {
LazyForEach(this.hoursDataResource, (hoursItem) => {
ListItem() {
// 具体每个小时的天气情况
Column() { ... }
}
}, item => `${item.key}`)
}
.height(Style.CARD_HEIGHT)
.borderRadius(Style.NORMAL_RADIUS)
.backgroundColor(Style.CARD_BACKGROUND_COLOR)
// 将列表方向设置为水平方向
.listDirection(Axis.Horizontal)
}
}
```
### 城市天气详情
天气主页右侧的城市天气详情由区域1-8组成,区域1(标题栏)始终固定在页面顶部,区域2-8在不同设备下的布局不同且可以随页面上下滚动。本小节介绍如何实现城市天气详情中区域2~8的布局效果。
设备屏幕可能无法一次性显示区域2-8的所有内容,故需要在外层增加滚动组件(即Scroll组件)以支持上下滚动。不同设备下区域2-8的相对位置一共有三套不同的布局,可以借助响应式布局中的[栅格布局](responsive-layout.md#栅格布局)实现这一效果。本示例中将栅格在不同场景下分别划分为4列、8列和12列,区域2-8在不同场景下的布局如下表所示。
| 小设备 | 中设备&nbsp;&nbsp;大设备(侧边栏显示状态) | 大设备(侧边栏隐藏状态) |
| -------- | -------- | -------- |
| ![zh-cn_image_0000001395631821](figures/zh-cn_image_0000001395631821.png) | ![zh-cn_image_0000001345312038](figures/zh-cn_image_0000001345312038.png) | ![zh-cn_image_0000001349454550](figures/zh-cn_image_0000001349454550.png) |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 为提升用户体验,大设备侧边栏隐藏状态下,每日天气与空气质量的相对顺序发生了改变。可以调整通过GridCol栅格子组件的order属性,实现目标效果。
```
@Component
export default struct HomeContent {
...
build() {
// 支持滚动
Scroll() {
GridRow({
columns: { sm: 4, md: 8, lg: this.showSideBar ? 8 : 12 },
gutter: { x: Style.GRID_GUTTER, y: Style.GRID_GUTTER },
breakpoints: { reference: BreakpointsReference.WindowSize } }) {
// 天气概览
GridCol({ span: { sm: 4, md: 8, lg: this.showSideBar ? 8 : 12 }, order: 1 }) {
IndexHeader({ headerDate: this.cityListData.header, index: this.index })
.opacity(this.headerOpacity)
}
// 每小时天气
GridCol({ span: { sm: 4, md: 8, lg: 8 }, order: 2 }) {
HoursWeather({ hoursData: this.cityListData.hoursData })
}
// 每日天气
GridCol({ span: 4, order: {sm: 3, md: 3, lg: this.showSideBar ? 3 : 4} }) {
MultidayWeather({ weekData: this.cityListData.weekData })
}
// 空气质量
GridCol({ span: 4, order: {sm: 4, md: 4, lg: this.showSideBar ? 4 : 3} }) {
AirQuality({ airData: this.cityListData.airData, airIndexData: this.cityListData.airIndex })
}
// 生活指数
GridCol({ span: 4, order: 5 }) {
LifeIndex({ lifeData: this.cityListData.suitDate })
}
// 日出日落
GridCol({ span: 4, order: 6 }) {
SunCanvas()
}
// 应用信息
GridCol({ span: { sm: 4, md: 8, lg: this.showSideBar ? 8 : 12 }, order: 7 }) {
IndexEnd()
}
}
}
.width('100%')
}
}
```
### 主页整体实现
综合考虑各设备下的效果,天气主页的根节点使用侧边栏组件:
- 小设备和中设备既不展示侧边栏,也不提供控制侧边栏显示和隐藏的按钮。
- 大设备默认展示侧边栏,同时提供控制侧边栏显示和隐藏的按钮。
另外主页右侧的城市天气详情,支持左右滑动切换城市,可以使用Swiper组件实现目标效果。
- 小设备和中设备开启Swiper组件的导航点,引导用户通过左右滑动切换不同城市。
- 大设备中用户通过点击侧边栏中的城市列表即可高效的切换不同城市,此时需要关闭Swiper组件的导航点。
```
@Entry
@Component
struct Home {
...
build() {
SideBarContainer(SideBarContainerType.Embed) {
// 左侧侧边栏
SideContent({ showSideBar: $showSideBar })
// 右侧内容区
Flex({direction: FlexDirection.Column}) {
// 基础区域1标题栏
IndexTitleBar({ curBp: this.curBp, showSideBar: $showSideBar })
.height(56)
// 天气详情,通过Swiper组件实现左右滑动切换城市的效果
Swiper() {
ForEach(this.cityListWeatherData, (item, index) => {
HomeContent({ showSideBar: this.showSideBar, cityListData: item, index: index })
}, item => item.city)
}
// 大设备关闭导航点
.indicator(this.curBp !== 'lg')
.width('100%')
}
}
.height('100%')
.sideBarWidth('33.3%')
// 通过状态变量,控制不同设备下侧边栏的显隐状态
.showSideBar(this.showSideBar)
}
}
```
最终,天气首页的运行效果如下图所示。
| 小设备 | 中设备 | 大设备(隐藏侧边栏) | 大设备(显示侧边栏) |
| -------- | -------- | -------- | -------- |
| ![zh-cn_image_0000001344993822](figures/zh-cn_image_0000001344993822.jpg) | ![zh-cn_image_0000001345473362](figures/zh-cn_image_0000001345473362.jpg) | ![zh-cn_image_0000001400662385](figures/zh-cn_image_0000001400662385.png) | ![zh-cn_image_0000001395713305](figures/zh-cn_image_0000001395713305.jpg) |
## 功能开发
应用开发不仅包含应用页面开发,还包括应用后端功能开发以及服务器端开发等。服务器端开发不在本文的讨论范围内,本小节仅介绍多设备上应用功能开发的注意事项。
如前文所示,本示例的目标运行设备是小设备、中设备和大设备,对应实际的设备类型为默认设备和平板等。这些设备运行的都是标准系统,其系统能力一致,所以无需做特别考虑。但是在超小设备(对应的实际设备类型为智能穿戴设备等)上,考虑CPU、内存、硬盘等硬件限制,往往会对系统进行裁剪。如果在应用后端功能开发时调用当前系统没有的能力,就可能会引发异常。
通常有两种方式解决上述问题:
- 在应用安装包中描述其需要的系统能力,保证本应用仅被分发和安装到可以满足其诉求的系统中。
- 在使用特定系统能力前,通过canIUse接口判断系统能力是否存在,进而执行不同的逻辑。
在本文的[功能开发的一多能力介绍](development-intro.md)章节中,将详细展开介绍。
# 典型布局场景
虽然不同应用的页面千变万化,但对其进行拆分和分析,页面中的很多布局场景是相似的。本小节将介绍如何借助自适应布局、响应式布局以及常见的容器类组件,实现应用中的典型布局场景。
| 布局场景 | 实现方案 |
| -------- | -------- |
| [页签栏](#页签栏) | Tab组件&nbsp;+&nbsp;响应式布局 |
| [运营横幅(Banner)](#运营横幅banner) | Swiper组件&nbsp;+&nbsp;响应式布局 |
| [网格](#网格) | Grid组件&nbsp;/&nbsp;List组件&nbsp;+&nbsp;响应式布局 |
| [侧边栏](#侧边栏) | SiderBar组件&nbsp;+&nbsp;响应式布局 |
| [大图浏览](#大图浏览) | Image组件 |
| [操作入口](#操作入口) | Scroll组件+Row组件横向均分 |
| [顶部](#顶部) | 栅格组件 |
| [缩进布局](#缩进布局) | 栅格组件 |
| [挪移布局](#挪移布局) | 栅格组件 |
| [重复布局](#重复布局) | 栅格组件 |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 在本文[媒体查询](responsive-layout.md#媒体查询)小节中已经介绍了如何通过媒体查询监听断点变化,后续的示例中不再重复介绍此部分代码。
## 页签栏
**布局效果**
| sm | md | lg |
| -------- | -------- | -------- |
| 页签在底部<br/>页签的图标和文字垂直布局<br/>页签宽度均分<br/>页签高度固定72vp | 页签在底部<br/>页签的图标和文字水平布局<br/>页签宽度均分<br/>页签高度固定56vp | 页签在左边<br/>页签的图标和文字垂直布局<br/>页签宽度固定96vp<br/>页签高度总占比‘60%’后均分 |
| ![页签布局手机](figures/页签布局手机.png) | ![页签布局折叠屏](figures/页签布局折叠屏.png) | ![页签布局matePadPro](figures/页签布局matePadPro.png) |
**实现方案**
不同断点下,页签在页面中的位置及尺寸都有差异,可以结合响应式布局能力,设置不同断点下[Tab组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-tabs.md)的barPosition、vertical、barWidth和barHeight属性实现目标效果。
另外,页签栏中的文字和图片的相对位置不同,同样可以通过设置不同断点下[tabBar](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-tabcontent.md#%E5%B1%9E%E6%80%A7)对应的CustomBuilder中的布局方向,实现目标效果。
**参考代码**
```
import { BreakpointSystem, BreakPointType } from 'common/BreakpointSystem'
type TabBar = {
name: string
icon: Resource
selectIcon: Resource
}
@Entry
@Component
struct Home {
@State currentIndex: number = 0
@State tabs: Array<TabBar> = [{
name: '首页',
icon: $r('app.media.ic_music_home'),
selectIcon: $r('app.media.ic_music_home_selected')
}, {
name: '排行榜',
icon: $r('app.media.ic_music_ranking'),
selectIcon: $r('app.media.ic_music_ranking_selected')
}, {
name: '我的',
icon: $r('app.media.ic_music_me_nor'),
selectIcon: $r('app.media.ic_music_me_selected')
}]
@Builder TabBarBuilder(index: number, tabBar: TabBar) {
Flex({
direction: new BreakPointType({
sm: FlexDirection.Column,
md: FlexDirection.Row,
lg: FlexDirection.Column
}).getValue(this.currentBreakpoint),
justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Center
}) {
Image(this.currentIndex === index ? tabBar.selectIcon : tabBar.icon)
.size({ width: 36, height: 36 })
Text(tabBar.name)
.fontColor(this.currentIndex === index ? '#FF1948' : '#999')
.margin(new BreakPointType({
sm: { top: 4 },
md: { left: 8 },
lg: { top: 4 } }).getValue(this.currentBreakpoint))
.fontSize(16)
}
.width('100%')
.height('100%')
}
@StorageLink('currentBreakpoint') currentBreakpoint: string = 'md'
private breakpointSystem: BreakpointSystem = new BreakpointSystem()
aboutToAppear() {
this.breakpointSystem.register()
}
aboutToDisappear() {
this.breakpointSystem.unregister()
}
build() {
Tabs({
barPosition: new BreakPointType({
sm: BarPosition.End,
md: BarPosition.End,
lg: BarPosition.Start
}).getValue(this.currentBreakpoint)
}) {
ForEach(this.tabs, (item, index) => {
TabContent() {
Stack() {
Text(item.name).fontSize(30)
}.width('100%').height('100%')
}.tabBar(this.TabBarBuilder(index, item))
})
}
.vertical(new BreakPointType({ sm: false, md: false, lg: true }).getValue(this.currentBreakpoint))
.barWidth(new BreakPointType({ sm: '100%', md: '100%', lg: '96vp' }).getValue(this.currentBreakpoint))
.barHeight(new BreakPointType({ sm: '72vp', md: '56vp', lg: '60%' }).getValue(this.currentBreakpoint))
.animationDuration(0)
.onChange((index: number) => {
this.currentIndex = index
})
}
}
```
## 运营横幅(Banner)
**布局效果**
| sm | md | lg |
| -------- | -------- | -------- |
| 展示一个内容项 | 展示两个内容项 | 展示三个内容项 |
| ![banner1](figures/banner1.PNG) | ![banner2](figures/banner2.PNG) | ![banner3](figures/banner3.PNG) |
**实现方案**
运营横幅通常使用[Swiper组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-swiper.md)实现。不同断点下,运营横幅中展示的图片数量不同。只需要结合响应式布局,配置不同断点下Swiper组件的displayCount属性,即可实现目标效果。
**参考代码**
```
import { BreakpointSystem, BreakPointType } from 'common/BreakpointSystem'
@Entry
@Component
export default struct Banner {
private data: Array<Resource> = [
$r('app.media.banner1'),
$r('app.media.banner2'),
$r('app.media.banner3'),
$r('app.media.banner4'),
$r('app.media.banner5'),
$r('app.media.banner6'),
]
private breakpointSystem: BreakpointSystem = new BreakpointSystem()
@StorageProp('currentBreakpoint') currentBreakpoint: string = 'md'
aboutToAppear() {
this.breakpointSystem.register()
}
aboutToDisappear() {
this.breakpointSystem.unregister()
}
build() {
Swiper() {
ForEach(this.data, (item) => {
Image(item)
.size({ width: '100%', height: 200 })
.borderRadius(12)
.padding(8)
})
}
.indicator(new BreakPointType({ sm: true, md: false, lg: false }).getValue(this.currentBreakpoint))
.displayCount(new BreakPointType({ sm: 1, md: 2, lg: 3 }).getValue(this.currentBreakpoint))
}
}
```
## 网格
**布局效果**
| sm | md | lg |
| -------- | -------- | -------- |
| 展示两列 | 展示四列 | 展示六列 |
| ![多列列表手机](figures/多列列表手机.png) | ![多列列表折叠屏](figures/多列列表折叠屏.png) | ![多列列表matePadPro](figures/多列列表matePadPro.png) |
**实现方案**
不同断点下,页面中图片的排布不同,此场景可以通过响应式布局能力结合[Grid组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-grid.md)实现,通过调整不同断点下的Grid组件的columnsTemplate属性即可实现目标效果。
另外,由于本例中各列的宽度相同,也可以通过响应式布局能力结合[List组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md)实现,通过调整不同断点下的List组件的lanes属性也可实现目标效果。
**参考代码**
通过Grid组件实现
```
import { BreakpointSystem, BreakPointType } from 'common/breakpointsystem'
type GridItemInfo = {
name: string
image: Resource
}
@Entry
@Component
struct MultiLaneList {
private data: GridItemInfo[] = [
{ name: '歌单集合1', image: $r('app.media.1') },
{ name: '歌单集合2', image: $r('app.media.2') },
{ name: '歌单集合3', image: $r('app.media.3') },
{ name: '歌单集合4', image: $r('app.media.4') },
{ name: '歌单集合5', image: $r('app.media.5') },
{ name: '歌单集合6', image: $r('app.media.6') },
{ name: '歌单集合7', image: $r('app.media.7') },
{ name: '歌单集合8', image: $r('app.media.8') },
{ name: '歌单集合9', image: $r('app.media.9') },
{ name: '歌单集合10', image: $r('app.media.10') },
{ name: '歌单集合11', image: $r('app.media.11') },
{ name: '歌单集合12', image: $r('app.media.12') }
]
private breakpointSystem: BreakpointSystem = new BreakpointSystem()
@StorageProp('currentBreakpoint') currentBreakpoint: string = 'md'
aboutToAppear() {
this.breakpointSystem.register()
}
aboutToDisappear() {
this.breakpointSystem.unregister()
}
build() {
Grid() {
ForEach(this.data, (item: GridItemInfo) => {
GridItem() {
Column() {
Image(item.image)
.aspectRatio(1.8)
Text(item.name)
.margin({ top: 8 })
.fontSize(20)
}.padding(4)
}
})
}
.columnsTemplate(new BreakPointType({
sm: '1fr 1fr',
md: '1fr 1fr 1fr 1fr',
lg: '1fr 1fr 1fr 1fr 1fr 1fr'
}).GetValue(this.currentBreakpoint))
}
}
```
通过List组件实现
```
import { BreakpointSystem, BreakPointType } from 'common/BreakpointSystem'
type ListItemInfo = {
name: string
image: Resource
}
@Entry
@Component
struct MultiLaneList {
private data: ListItemInfo[] = [
{ name: '歌单集合1', image: $r('app.media.1') },
{ name: '歌单集合2', image: $r('app.media.2') },
{ name: '歌单集合3', image: $r('app.media.3') },
{ name: '歌单集合4', image: $r('app.media.4') },
{ name: '歌单集合5', image: $r('app.media.5') },
{ name: '歌单集合6', image: $r('app.media.6') },
{ name: '歌单集合7', image: $r('app.media.7') },
{ name: '歌单集合8', image: $r('app.media.8') },
{ name: '歌单集合9', image: $r('app.media.9') },
{ name: '歌单集合10', image: $r('app.media.10') },
{ name: '歌单集合11', image: $r('app.media.11') },
{ name: '歌单集合12', image: $r('app.media.12') }
]
private breakpointSystem: BreakpointSystem = new BreakpointSystem()
@StorageProp('currentBreakpoint') currentBreakpoint: string = 'md'
aboutToAppear() {
this.breakpointSystem.register()
}
aboutToDisappear() {
this.breakpointSystem.unregister()
}
build() {
List() {
ForEach(this.data, (item: ListItemInfo) => {
ListItem() {
Column() {
Image(item.image)
Text(item.name)
.margin({ top: 8 })
.fontSize(20)
}.padding(4)
}
})
}
.lanes(new BreakPointType({ sm: 2, md: 4, lg: 6 }).getValue(this.currentBreakpoint))
.width('100%')
}
}
```
## 侧边栏
**布局效果**
| sm | md | lg |
| -------- | -------- | -------- |
| 默认隐藏侧边栏,同时提供侧边栏控制按钮,用户可以通过按钮控制侧边栏显示或隐藏。 | 始终显示侧边栏,不提供控制按钮,用户无法隐藏侧边栏。 | 始终显示侧边栏,不提供控制按钮,用户无法隐藏侧边栏。 |
| ![sm](figures/sm.png) | ![md](figures/md.png) | ![lg](figures/lg.png) |
**实现方案**
侧边栏通常通过[SideBarContainer组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-sidebarcontainer.md)实现,结合响应式布局能力,在不同断点下为SiderBarConContainer组件的sideBarWidth、showControlButton等属性配置不同的值,即可实现目标效果。
**参考代码**
```
@Entry
@Component
struct SideBarSample {
@StorageLink('currentBreakpoint') private currentBreakpoint: string = "md";
private breakpointSystem: BreakpointSystem = new BreakpointSystem()
@State showSideBar: boolean = false
@State selectIndex: number = 0;
aboutToAppear() {
this.breakpointSystem.register()
if (this.currentBreakpoint === 'sm') {
this.showSideBar = false
} else {
this.showSideBar = true
}
}
aboutToDisappear() {
this.breakpointSystem.unregister()
}
@Builder itemBuilder(index: number) {
Text(images[index].label)
.width('100%')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.borderRadius(5)
.margin(20)
.backgroundColor('#ffffff')
.textAlign(TextAlign.Center)
.width(180)
.height(36)
.onClick(() => {
this.selectIndex = index
if (this.currentBreakpoint === 'sm') {
this.showSideBar = false
}
})
}
build() {
SideBarContainer(this.currentBreakpoint === 'sm' ? SideBarContainerType.Overlay : SideBarContainerType.Embed) {
Column() {
this.itemBuilder(0)
this.itemBuilder(1)
}.backgroundColor('#F1F3F5')
.justifyContent(FlexAlign.Center)
Column() {
Image(images[this.selectIndex].imageSrc)
.objectFit(ImageFit.Contain)
.height(300)
.width(300)
}
.justifyContent(FlexAlign.Center)
.width('100%')
.height('100%')
}
.height('100%')
.sideBarWidth(this.currentBreakpoint === 'sm' ? '100%' : '33.33%')
.minSideBarWidth(this.currentBreakpoint === 'sm' ? '100%' : '33.33%')
.maxSideBarWidth(this.currentBreakpoint === 'sm' ? '100%' : '33.33%')
.showControlButton(this.currentBreakpoint === 'sm')
.autoHide(false)
.showSideBar(this.showSideBar)
.onChange((isBarShow: boolean) => {
this.showSideBar = isBarShow
})
}
}
```
## 大图浏览
**布局效果**
| sm | md | lg |
| -------- | -------- | -------- |
| 图片长宽比不变,最长边充满全屏 | 图片长宽比不变,最长边充满全屏 | 图片长宽比不变,最长边充满全屏 |
| ![大图浏览手机](figures/大图浏览手机.png) | ![大图浏览折叠屏](figures/大图浏览折叠屏.png) | ![大图浏览matePadPRo](figures/大图浏览matePadPRo.png) |
**实现方案**
图片通常使用[Image组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-image.md)展示,Image组件的objectFit属性默认为ImageFit.Cover,即保持宽高比进行缩小或者放大以使得图片两边都大于或等于显示边界。在大图浏览场景下,因屏幕与图片的宽高比可能有差异,常常会发生图片被截断的问题。此时只需将Image组件的objectFit属性设置为ImageFit.Contain,即保持宽高比进行缩小或者放大并使得图片完全显示在显示边界内,即可解决该问题。
**参考代码**
```
@Entry
@Component
struct BigImage {
build() {
Row() {
Image($r("app.media.image"))
.objectFit(ImageFit.Contain)
}
}
}
```
## 操作入口
**布局效果**
| sm | md | lg |
| -------- | -------- | -------- |
| 列表项尺寸固定,超出内容可滚动查看 | 列表项尺寸固定,剩余空间均分 | 列表项尺寸固定,剩余空间均分 |
| ![操作入口手机](figures/操作入口手机.png) | ![操作入口折叠屏](figures/操作入口折叠屏.png) | ![操作入口matePadPro](figures/操作入口matePadPro.png) |
**实现方案**
Scroll(内容超出宽度时可滚动) + Row(横向均分:justifyContent(FlexAlign.SpaceAround)、 最小宽度约束:constraintSize({ minWidth: '100%' })
**参考代码**
```
type OperationItem = {
name: string
icon: Resource
}
@Entry
@Component
export default struct OperationEntries {
@State listData: Array<OperationItem> = [
{ name: '私人FM', icon: $r('app.media.self_fm') },
{ name: '歌手', icon: $r('app.media.singer') },
{ name: '歌单', icon: $r('app.media.song_list') },
{ name: '排行榜', icon: $r('app.media.rank') },
{ name: '热门', icon: $r('app.media.hot') },
{ name: '运动音乐', icon: $r('app.media.sport') },
{ name: '音乐FM', icon: $r('app.media.audio_fm') },
{ name: '福利', icon: $r('app.media.bonus') }]
build() {
Scroll() {
Row() {
ForEach(this.listData, item => {
Column() {
Image(item.icon)
.width(48)
.aspectRatio(1)
Text(item.name)
.margin({ top: 8 })
.fontSize(16)
}
.justifyContent(FlexAlign.Center)
.height(104)
.padding({ left: 12, right: 12 })
})
}
.constraintSize({ minWidth: '100%' }).justifyContent(FlexAlign.SpaceAround)
}
.width('100%')
.scrollable(ScrollDirection.Horizontal)
}
}
```
## 顶部
**布局效果**
| sm | md | lg |
| -------- | -------- | -------- |
| 标题和搜索框两行显示 | 标题和搜索框一行显示 | 标题和搜索框一行显示 |
| ![顶部布局手机](figures/顶部布局手机.png) | ![顶部布局折叠屏](figures/顶部布局折叠屏.png) | ![顶部布局matePadPro](figures/顶部布局matePadPro.png) |
**实现方案**
最外层使用栅格行组件GridRow布局
文本标题使用栅格列组件GridCol
搜索框使用栅格列组件GridCol
**参考代码**
```
@Entry
@Component
export default struct Header {
@State needWrap: boolean = true
build() {
GridRow() {
GridCol({ span: { sm: 12, md: 6, lg: 7 } }) {
Row() {
Text('推荐').fontSize(24)
Blank()
Image($r('app.media.ic_public_more'))
.width(32)
.height(32)
.objectFit(ImageFit.Contain)
.visibility(this.needWrap ? Visibility.Visible : Visibility.None)
}
.width('100%').height(40)
.alignItems(VerticalAlign.Center)
}
GridCol({ span: { sm: 12, md: 6, lg: 5 } }) {
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
Search({ placeholder: '猜您喜欢: 万水千山' })
.placeholderFont({ size: 16 })
.margin({ top: 4, bottom: 4 })
Image($r('app.media.audio_fm'))
.width(32)
.height(32)
.objectFit(ImageFit.Contain)
.flexShrink(0)
.margin({ left: 12 })
Image($r('app.media.ic_public_more'))
.width(32)
.height(32)
.objectFit(ImageFit.Contain)
.flexShrink(0)
.margin({ left: 12 })
.visibility(this.needWrap ? Visibility.None : Visibility.Visible)
}
}
}.onBreakpointChange((breakpoint: string) => {
if (breakpoint === 'sm') {
this.needWrap = true
} else {
this.needWrap = false
}
})
.padding({ left: 12, right: 12 })
}
}
```
## 缩进布局
**布局效果**
| sm | md | lg |
| -------- | -------- | -------- |
| 栅格总列数为4,内容占满所有列 | 栅格总列数为8,内容占中间6列。 | 栅格总列数为12,内容占中间8列。 |
| ![indent_sm](figures/indent_sm.jpg) | ![indent_md](figures/indent_md.jpg) | ![indent_lg](figures/indent_lg.jpg) |
**实现方案**
借助[栅格组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-gridrow.md),控制待显示内容在不同的断点下占据不同的列数,即可实现不同设备上的缩进效果。另外还可以调整不同断点下栅格组件与两侧的间距,获得更好的显示效果。
**参考代码**
```
@Entry
@Component
struct IndentationSample {
@State private gridMargin: number = 24
build() {
Row() {
GridRow({columns: {sm: 4, md: 8, lg: 12}, gutter: 24}) {
GridCol({span: {sm: 4, md: 6, lg: 8}, offset: {md: 1, lg: 2}}) {
Column() {
ForEach([0, 1, 2, 4], () => {
Column() {
ItemContent()
}
})
}.width('100%')
}
}
.margin({left: this.gridMargin, right: this.gridMargin})
.onBreakpointChange((breakpoint: string) => {
if (breakpoint === 'lg') {
this.gridMargin = 48
} else if (breakpoint === 'md') {
this.gridMargin = 32
} else {
this.gridMargin = 24
}
})
}
.height('100%')
.alignItems((VerticalAlign.Center))
.backgroundColor('#F1F3f5')
}
}
@Component
struct ItemContent {
build() {
Column() {
Row() {
Row() {
}
.width(28)
.height(28)
.borderRadius(14)
.margin({ right: 15 })
.backgroundColor('#E4E6E8')
Row() {
}
.width('30%').height(20).borderRadius(4)
.backgroundColor('#E4E6E8')
}.width('100%').height(28)
Row() {
}
.width('100%')
.height(68)
.borderRadius(16)
.margin({ top: 12 })
.backgroundColor('#E4E6E8')
}
.height(128)
.borderRadius(24)
.backgroundColor('#FFFFFF')
.padding({ top: 12, bottom: 12, left: 18, right: 18 })
.margin({ bottom: 12 })
}
}
```
## 挪移布局
**布局效果**
| sm | md | lg |
| -------- | -------- | -------- |
| 图片和文字上下布局 | 图片和文字左右布局 | 图片和文字左右布局 |
| ![diversion_sm](figures/diversion_sm.jpg) | ![diversion_md](figures/diversion_md.jpg) | ![diversion_lg](figures/diversion_lg.jpg) |
**实现方案**
不同断点下,栅格子元素占据的列数会随着开发者的配置发生改变。当一行中的列数超过栅格组件在该断点的总列数时,可以自动换行,即实现”上下布局”与”左右布局”之间切换的效果。
**参考代码**
```
@Entry
@Component
struct DiversionSample {
@State private currentBreakpoint: string = 'md'
@State private imageHeight: number = 0
build() {
Row() {
GridRow() {
GridCol({span: {sm: 12, md: 6, lg: 6}}) {
Image($r('app.media.illustrator'))
.aspectRatio(1)
.onAreaChange((oldValue: Area, newValue: Area) => {
this.imageHeight = Number(newValue.height)
})
.margin({left: 12, right: 12})
}
GridCol({span: {sm: 12, md: 6, lg: 6}}) {
Column(){
Text($r('app.string.user_improvement'))
.textAlign(TextAlign.Center)
.fontSize(20)
.fontWeight(FontWeight.Medium)
Text($r('app.string.user_improvement_tips'))
.textAlign(TextAlign.Center)
.fontSize(14)
.fontWeight(FontWeight.Medium)
}
.margin({left: 12, right: 12})
.justifyContent(FlexAlign.Center)
.height(this.currentBreakpoint === 'sm' ? 100 : this.imageHeight)
}
}.onBreakpointChange((breakpoint: string) => {
this.currentBreakpoint = breakpoint;
})
}
.height('100%')
.alignItems((VerticalAlign.Center))
.backgroundColor('#F1F3F5')
}
}
```
## 重复布局
**布局效果**
| sm | md | lg |
| -------- | -------- | -------- |
| 单列显示,共8个元素<br>可以通过上下滑动查看不同的元素 | 双列显示,共8个元素 | 双列显示,共8个元素 |
| ![repeat_sm](figures/repeat_sm.jpg) | ![repeat_md](figures/repeat_md.jpg) | ![repeat_lg](figures/repeat_lg.jpg) |
**实现方案**
不同断点下,配置栅格子组件占据不同的列数,即可实现“小屏单列显示、大屏双列显示”的效果。另外,还可以通过栅格组件的onBreakpointChange事件,调整页面中显示的元素数量。
**参考代码**
```
@Entry
@Component
struct RepeatSample {
@State private currentBreakpoint: string = 'md'
@State private listItems: number[] = [1, 2, 3, 4, 5, 6, 7, 8]
@State private gridMargin: number = 24
build() {
Row() {
// 当目标区域不足以显示所有元素时,可以通过上下滑动查看不同的元素
Scroll() {
GridRow({gutter: 24}) {
ForEach(this.listItems, () => {
// 通过配置元素在不同断点下占的列数,实现不同的布局效果
GridCol({span: {sm: 12, md: 6, lg: 6}}) {
Column() {
RepeatItemContent()
}
}
})
}
.margin({left: this.gridMargin, right: this.gridMargin})
.onBreakpointChange((breakpoint: string) => {
this.currentBreakpoint = breakpoint;
if (breakpoint === 'lg') {
this.gridMargin = 48
} else if (breakpoint === 'md') {
this.gridMargin = 32
} else {
this.gridMargin = 24
}
})
}.height(348)
}
.height('100%')
.backgroundColor('#F1F3F5')
}
}
@Component
struct RepeatItemContent {
build() {
Flex() {
Row() {
}
.width(43)
.height(43)
.borderRadius(12)
.backgroundColor('#E4E6E8')
.flexGrow(0)
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start, justifyContent: FlexAlign.SpaceAround }) {
Row() {
}
.height(10)
.width('80%')
.backgroundColor('#E4E6E8')
Row() {
}
.height(10)
.width('50%')
.backgroundColor('#E4E6E8')
}
.flexGrow(1)
.margin({ left: 13 })
}
.padding({ top: 13, bottom: 13, left: 13, right: 37 })
.height(69)
.backgroundColor('#FFFFFF')
.borderRadius(24)
}
}
```
# 典型页面场景
- **[应用市场首页](appgallery-home-page.md)**
- **[音乐专辑页](music-album-page.md)**
\ No newline at end of file
# 应用UX设计
- **[设计原则和要点](design-principles.md)**
- **[应用架构设计](architecture-design.md)**
- **[界面布局](interface-layout-design.md)**
- **[人机交互](man-machine-interaction.md)**
- **[视觉风格](visual-style.md)**
- **[多态控件](design-polymorphic-controls.md)**
- **[设计自检表](design-checklist.md)**
- **[设计交付](design-delivery.md)**
- **[资源](design-resources.md)**
\ No newline at end of file
# 视觉基础 # 视觉基础
**虚拟像素单位:vp** **虚拟像素单位:vp**
虚拟像素(virtual pixel)是一台设备针对应用而言所具有的虚拟尺寸(区别于屏幕硬件本身的像素单位)。它提供了一种灵活的方式来适应不同屏幕密度的显示效果。 虚拟像素(virtual pixel)是一台设备针对应用而言所具有的虚拟尺寸(区别于屏幕硬件本身的像素单位)。它提供了一种灵活的方式来适应不同屏幕密度的显示效果。
![zh-cn_image_0000001224333864](figures/zh-cn_image_0000001224333864.png) ![zh-cn_image_0000001224333864](figures/zh-cn_image_0000001224333864.png)
相同的vp,在不同像素密度的屏幕上,对应不同px,一般称px/vp为像素密度比。像素密度比为当前设备屏幕的dpi/160。 相同的vp,在不同像素密度的屏幕上,对应不同px,一般称px/vp为像素密度比。像素密度比为当前设备屏幕的dpi/160。
在dpi为160的OpenHarmony设备上,像素密度比为1,则1vp等于1px。 在dpi为160的OpenHarmony设备上,像素密度比为1,则1vp等于1px。
以vp为尺寸标注单位,可使相同元素在不同密度的设备上具有一致的视觉体量,使用px则容易导致体量不一致的问题。 以vp为尺寸标注单位,可使相同元素在不同密度的设备上具有一致的视觉体量,使用px则容易导致体量不一致的问题。
**8vp网格系统** **8vp网格系统**
基于 8vp 为网格的基本单位可以对界面上元素的大小、位置、对齐方式进行更好的规划,构建更有层次感、秩序感,以及多设备上一致的布局效果。一些更小的控件(例如图标)大小也可以对齐 4vp 的网格大小。 基于 8vp 为网格的基本单位可以对界面上元素的大小、位置、对齐方式进行更好的规划,构建更有层次感、秩序感,以及多设备上一致的布局效果。一些更小的控件(例如图标)大小也可以对齐 4vp 的网格大小。
![zh-cn_image_0000001291670681](figures/zh-cn_image_0000001291670681.png) ![8vp](figures/8vp.png)
**字体像素单位:fp** **字体像素单位:fp**
字体像素(font pixel) 大小默认情况下与 vp 相同,即默认情况下 1 fp = 1vp。如果用户在设置中选择了更大的字体,字体的实际显示大小就会在 vp 的基础上乘以 scale 系数,即 1 fp = 1 vp \* scale。 字体像素(font pixel) 大小默认情况下与 vp 相同,即默认情况下 1 fp = 1vp。如果用户在设置中选择了更大的字体,字体的实际显示大小就会在 vp 的基础上乘以 scale 系数,即 1 fp = 1 vp \* scale。
**视觉属性:分层参数** **视觉属性:分层参数**
分层参数是根据使用场景定义的视觉属性ID,通过在不同色彩主题、多种设备上配置不同的数值,实现多设备适配的效果。OpenHarmony的分层参数包含色彩、字体、圆角、间距、阴影、模糊、缩放,并提供了默认实现。设备、应用、服务均可在此基础上管理并自定义不同场景的视觉属性。 分层参数是根据使用场景定义的视觉属性ID,通过在不同色彩主题、多种设备上配置不同的数值,实现多设备适配的效果。OpenHarmony的分层参数包含色彩、字体、圆角、间距、阴影、模糊、缩放,并提供了默认实现。设备、应用、服务均可在此基础上管理并自定义不同场景的视觉属性。
![zh-cn_image_0000001251153442](figures/zh-cn_image_0000001251153442.png) ![画板 copy](figures/画板copy.png)
例如,对于不同场景的主色调定义了对应的ID与默认实现 例如,对于不同场景的主色调定义了对应的ID与默认实现
| | | | | | 场景 | 色值 | ID |
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- |
| 主色调 | 高亮色 | \#007DFF | ohos_id_color_emphasize | | 高亮色 | \#007DFF | ohos_id_color_emphasize |
| 高亮色反色 | \#006CDE | ohos_id_color_emphasize_contrary | | 高亮色反色 | #006CDE |ohos_id_color_emphasize_contrary|
| 警告色 | \#FA2A2D | ohos_id_color_warning | | 警告色 | \#FA2A2D |ohos_id_color_warning|
| 警示色 | \#FF7500 | ohos_id_color_alert | | 警示色 | \#FF7500 |ohos_id_color_alert|
| 通讯色 | \#E84826 | ohos_id_color_handup | | 通讯色 | \#E84826 |ohos_id_color_handup|
| 通讯色 | \#00CB87 | ohos_id_color_connected | | 通讯色 | \#00CB87 |ohos_id_color_connected|
关于OpenHarmony默认提供的所有分层参数,详见:[资源](resource.md) 关于OpenHarmony默认提供的所有分层参数,详见:[资源](design-resources.md)
# 色彩 # 色彩
色彩能够赋予应用界面足够的生动性,并给用户提供不同设备上、不同应用间视觉感官上的连续性。同时,合理地运用色彩可以传达关键的状态信息,给予用户即时的状态反馈以及数据可视化呈现。 色彩能够赋予应用界面足够的生动性,并给用户提供不同设备上、不同应用间视觉感官上的连续性。同时,合理地运用色彩可以传达关键的状态信息,给予用户即时的状态反馈以及数据可视化呈现。
OpenHarmony采用蓝色作为系统的默认主色调。根据人因研究,对蓝色的接受度无论是在男性还是女性群体中,比例都是最高的。而在世界地域维度,蓝色也是最受欢迎的颜色。更重要的是,对于大多数色觉障碍人士,蓝色依然可以被辨识。 OpenHarmony采用蓝色作为系统的默认主色调。根据人因研究,对蓝色的接受度无论是在男性还是女性群体中,比例都是最高的。在世界地域维度,蓝色也是最受欢迎的颜色。更重要的是,对于大多数色觉障碍人士,蓝色依然可以被辨识。
**色值及使用场景** ## 色值及使用场景
在色彩设计上,既保持统一的色彩语言,又根据多端不同的使用场景做了调整,带来定制化用户体验。
在色彩设计上,既保持统一的色彩语言,又根据多端不同的使用场景做了调整,带来定制化用户体验。
例如,高亮色ohos_id_color_activated,在不同设备和色彩模式上会有不同具体的值:
例如,高亮色ohos_id_color_activated,在不同设备和色彩模式上会有不同具体的值: | | |
| -------- | -------- |
| ![zh-cn_image_0000001400554657](figures/zh-cn_image_0000001400554657.png)<br/>用于默认设备浅色风格。 | ![zh-cn_image_0000001400874297](figures/zh-cn_image_0000001400874297.png)<br/>用于默认设备深色风格。 |
| | | | | | ![zh-cn_image_0000001350234552](figures/zh-cn_image_0000001350234552.png)<br/>用于智慧屏深色风格。 | ![zh-cn_image_0000001400674189](figures/zh-cn_image_0000001400674189.png)<br/>用于智能穿戴深色风格。 |
| -------- | -------- | -------- | -------- |
| ![zh-cn_image_0000001268654109](figures/zh-cn_image_0000001268654109.png)<br/>用于默认设备浅色风格。 | ![zh-cn_image_0000001223973992](figures/zh-cn_image_0000001223973992.png)<br/>用于默认设备深色风格。 | ![zh-cn_image_0000001223973996](figures/zh-cn_image_0000001223973996.png)<br/>用于智慧屏深色风格。 | ![zh-cn_image_0000001224333892](figures/zh-cn_image_0000001224333892.png)<br/>用于智能穿戴深色风格。 | OpenHarmony后续将支持深色模式、浅色模式,及不同主题切换能力。
关于OpenHarmony默认提供的色彩相关分层参数,详见:[资源](design-resources.md)
OpenHarmony后续将支持深色模式、浅色模式,及不同主题切换能力。
关于OpenHarmony默认提供的色彩相关分层参数,详见:[资源](resource.md)
# 字体 # 字体
字体直接影响界面的展示效果和用户的阅读效率。优秀的字形设计、统一的多语言字形风格、正确的字体排版,能有效地提升应用使用体验,并传递品牌连续性。 字体直接影响界面的展示效果和用户的阅读效率。优秀的字形设计、统一的多语言字形风格、正确的字体排版,能有效地提升应用使用体验,并传递品牌连续性。
多设备字号层级 ## 多设备字号层级
选择合适的字号有助于定义内容的信息层级以及增强内容的可读性。通过研究全场景设备的显示环境、用户使用时环境的差异,OpenHarmony结合分层参数为不同设备形态提供了一套构建信息层级的字号系统。
选择合适的字号有助于定义内容的信息层级,以及达到内容的可读性。通过研究全场景设备的显示环境、用户使用时环境的差异,OpenHarmony结合分层参数为不同设备形态提供了一套构建信息层级的字号系统。
![字体 copy 2](figures/字体copy2.png)
![zh-cn_image_0000001292686089](figures/zh-cn_image_0000001292686089.png) 关于OpenHarmony默认提供的字体相关分层参数,详见:[资源](design-resources.md)
关于OpenHarmony默认提供的字体相关分层参数,详见:[资源](resource.md)
# 图标 # 图标
图标是操作系统与用户界面关键的视觉元素之一。图标应当具备直接识别关键信息或语义的特质,帮助用户轻松辨别图标所代表的含义。为了保证用户在不同的设备中视觉体验的一致性,在图标的设计上应当保持应用图标的元素一致,再根据不同的设备匹配对应的图标背板以适应于各种场景。除此之外,图标在颜色的使用上应当遵循符合人因的色彩规则,满足用户阅读的舒适度以及整体界面的和谐程度。对于面状图标与线状图标的使用也应当遵循系统的设计规则,两种样式使用同一种图形结构,降低用户阅读时再次识别的成本。 图标是操作系统与用户界面关键的视觉元素之一。图标应当具备直接识别关键信息或语义的特质,帮助用户轻松辨别图标所代表的含义。为了保证用户在不同的设备中视觉体验的一致性,在图标的设计上应当保持应用图标的元素一致,再根据不同的设备匹配对应的图标背板以适应于各种场景。除此之外,图标在颜色的使用上应当遵循符合人因的色彩规则,满足用户阅读的舒适度以及整体界面的和谐程度。对于面状图标与线状图标的使用应当遵循系统的设计规则,两种样式使用同一种图形结构,降低用户阅读时再次识别的成本。
![zh-cn_image_0000001268334113](figures/zh-cn_image_0000001268334113.jpg) ![zh-cn_image_0000001268334113](figures/zh-cn_image_0000001268334113.jpg)
关于OpenHarmony默认提供的图标库,详见[线上图标库](https://developer.harmonyos.com/cn/design/harmonyos-icon/) 关于OpenHarmony默认提供的图标库,详见[线上图标库](https://developer.harmonyos.com/cn/design/harmonyos-icon/)
# 视觉风格
- **[视觉基础](visual-basics.md)**
- **[色彩](visual-style-color.md)**
- **[字体](visual-style-font.md)**
- **[图标](visual-style-icon.md)**
\ No newline at end of file
...@@ -4,3 +4,4 @@ ...@@ -4,3 +4,4 @@
- [Drawing开发指导](drawing-guidelines.md) - [Drawing开发指导](drawing-guidelines.md)
- [Rawfile开发指导](rawfile-guidelines.md) - [Rawfile开发指导](rawfile-guidelines.md)
- [Window开发指导](native-window-guidelines.md) - [Window开发指导](native-window-guidelines.md)
- [使用MindSpore Lite引擎进行模型推理](mindspore-lite-guidelines.md)
# 使用MindSpore Lite引擎进行模型推理
## 场景介绍
MindSpore Lite是一款AI引擎,它提供了面向不同硬件设备AI模型推理的功能,目前已经在图像分类、目标识别、人脸识别、文字识别等应用中广泛使用。
本文介绍使用MindSpore Lite推理引擎进行模型推理的通用开发流程。
## 基本概念
在进行开发前,请先了解以下概念。
**张量**:它与数组和矩阵非常相似,是MindSpore Lite网络运算中的基本数据结构。
**Float16推理模式**: Float16又称半精度,它使用16比特表示一个数。Float16推理模式表示推理的时候用半精度进行推理。
## 接口说明
这里给出MindSpore Lite推理的通用开发流程中涉及的一些接口,具体请见下列表格。
### Context 相关接口
| 接口名称 | 描述 |
| ------------------ | ----------------- |
|OH_AI_ContextHandle OH_AI_ContextCreate()|创建一个上下文的对象。|
|void OH_AI_ContextSetThreadNum(OH_AI_ContextHandle context, int32_t thread_num)|设置运行时的线程数量。|
| void OH_AI_ContextSetThreadAffinityMode(OH_AI_ContextHandle context, int mode)|设置运行时线程绑定CPU核心的策略。一般情况下CPU会按照频率分为大小核,即频率较高的为大核,频率较低的为小核。|
|OH_AI_DeviceInfoHandle OH_AI_DeviceInfoCreate(OH_AI_DeviceType device_type)|创建一个运行时设备信息对象。|
|void OH_AI_ContextDestroy(OH_AI_ContextHandle *context)|释放上下文对象。|
|void OH_AI_DeviceInfoSetEnableFP16(OH_AI_DeviceInfoHandle device_info, bool is_fp16)|设置是否开启Float16推理模式,仅CPU/GPU设备可用。|
|void OH_AI_ContextAddDeviceInfo(OH_AI_ContextHandle context, OH_AI_DeviceInfoHandle device_info)|添加运行时设备信息。|
### Model 相关接口
| 接口名称 | 描述 |
| ------------------ | ----------------- |
|OH_AI_ModelHandle OH_AI_ModelCreate()|创建一个模型对象。|
|OH_AI_Status OH_AI_ModelBuildFromFile(OH_AI_ModelHandle model, const char *model_path,OH_AI_ModelType odel_type, const OH_AI_ContextHandle model_context)|通过模型文件加载并编译MindSpore模型。|
|void OH_AI_ModelDestroy(OH_AI_ModelHandle *model)|释放一个模型对象。|
### Tensor 相关接口
| 接口名称 | 描述 |
| ------------------ | ----------------- |
|OH_AI_TensorHandleArray OH_AI_ModelGetInputs(const OH_AI_ModelHandle model)|获取模型的输入张量数组结构体。|
|int64_t OH_AI_TensorGetElementNum(const OH_AI_TensorHandle tensor)|获取张量元素数量。|
|const char *OH_AI_TensorGetName(const OH_AI_TensorHandle tensor)|获取张量的名称。|
|OH_AI_DataType OH_AI_TensorGetDataType(const OH_AI_TensorHandle tensor)|获取张量数据类型。|
|void *OH_AI_TensorGetMutableData(const OH_AI_TensorHandle tensor)|获取可变的张量数据指针。|
## 开发步骤
使用MindSpore Lite进行模型推理的开发流程如下图所示。
**图 1** 使用MindSpore Lite进行模型推理的开发流程
![how-to-use-mindspore-lite](figures/01.png)
主要开发步骤包括模型的准备、读取、编译、推理和释放,具体开发过程及细节请见下文的开发步骤及示例。
1. 模型准备。
需要的模型可以直接下载,也可以通过模型转换工具获得。
- 下载模型的格式若为`.ms`,则可以直接使用。本文以mobilenetv2.ms为例。
- 如果是第三方框架的模型,比如 TensorFlow、TensorFlow Lite、Caffe、ONNX等,需要使用[模型转换工具](https://www.mindspore.cn/lite/docs/zh-CN/r1.5/use/benchmark_tool.html)转换为`.ms`格式的模型文件。
2. 创建上下文,设置线程数、设备类型等参数。
```c
// 创建并配置上下文,设置运行时的线程数量为2,绑核策略为大核优先
OH_AI_ContextHandle context = OH_AI_ContextCreate();
if (context == NULL) {
printf("OH_AI_ContextCreate failed.\n");
return OH_AI_STATUS_LITE_ERROR;
}
const int thread_num = 2;
OH_AI_ContextSetThreadNum(context, thread_num);
OH_AI_ContextSetThreadAffinityMode(context, 1);
//设置运行设备为CPU,不使用Float16推理
OH_AI_DeviceInfoHandle cpu_device_info = OH_AI_DeviceInfoCreate(OH_AI_DEVICETYPE_CPU);
if (cpu_device_info == NULL) {
printf("OH_AI_DeviceInfoCreate failed.\n");
OH_AI_ContextDestroy(&context);
return OH_AI_STATUS_LITE_ERROR;
}
OH_AI_DeviceInfoSetEnableFP16(cpu_device_info, false);
OH_AI_ContextAddDeviceInfo(context, cpu_device_info);
```
3. 创建、加载与编译模型。
调用OH_AI_ModelBuildFromFile加载并编译模型。
本例中传入OH_AI_ModelBuildFromFile的argv[1]参数是从控制台中输入的模型文件路径。
```c
// 创建模型
OH_AI_ModelHandle model = OH_AI_ModelCreate();
if (model == NULL) {
printf("OH_AI_ModelCreate failed.\n");
OH_AI_ContextDestroy(&context);
return OH_AI_STATUS_LITE_ERROR;
}
// 加载与编译模型,模型的类型为OH_AI_ModelTypeMindIR
int ret = OH_AI_ModelBuildFromFile(model, argv[1], OH_AI_ModelTypeMindIR, context);
if (ret != OH_AI_STATUS_SUCCESS) {
printf("OH_AI_ModelBuildFromFile failed, ret: %d.\n", ret);
OH_AI_ModelDestroy(&model);
return ret;
}
```
4. 输入数据。
模型执行之前需要向输入的张量中填充数据。本例使用随机的数据对模型进行填充。
```c
// 获得输入张量
OH_AI_TensorHandleArray inputs = OH_AI_ModelGetInputs(model);
if (inputs.handle_list == NULL) {
printf("OH_AI_ModelGetInputs failed, ret: %d.\n", ret);
OH_AI_ModelDestroy(&model);
return ret;
}
// 使用随机数据填充张量
ret = GenerateInputDataWithRandom(inputs);
if (ret != OH_AI_STATUS_SUCCESS) {
printf("GenerateInputDataWithRandom failed, ret: %d.\n", ret);
OH_AI_ModelDestroy(&model);
return ret;
}
```
5. 执行推理。
使用OH_AI_ModelPredict接口进行模型推理。
```c
// 执行模型推理
OH_AI_TensorHandleArray outputs;
ret = OH_AI_ModelPredict(model, inputs, &outputs, NULL, NULL);
if (ret != OH_AI_STATUS_SUCCESS) {
printf("OH_AI_ModelPredict failed, ret: %d.\n", ret);
OH_AI_ModelDestroy(&model);
return ret;
}
```
6. 获取输出。
模型推理结束之后,可以通过输出张量得到推理结果。
```c
// 获取模型的输出张量,并打印
for (size_t i = 0; i < outputs.handle_num; ++i) {
OH_AI_TensorHandle tensor = outputs.handle_list[i];
int64_t element_num = OH_AI_TensorGetElementNum(tensor);
printf("Tensor name: %s, tensor size is %zu ,elements num: %lld.\n", OH_AI_TensorGetName(tensor),
OH_AI_TensorGetDataSize(tensor), element_num);
const float *data = (const float *)OH_AI_TensorGetData(tensor);
printf("output data is:\n");
const int max_print_num = 50;
for (int j = 0; j < element_num && j <= max_print_num; ++j) {
printf("%f ", data[j]);
}
printf("\n");
}
```
7. 释放模型。
不再使用MindSpore Lite推理框架时,需要释放已经创建的模型。
```c
// 释放模型
OH_AI_ModelDestroy(&model);
```
## 调测验证
1. 编写CMakeLists.txt。
```cmake
cmake_minimum_required(VERSION 3.14)
project(Demo)
add_executable(demo main.c)
target_link_libraries(
demo
mindspore-lite.huawei
pthread
dl
)
```
- 使用ohos-sdk交叉编译,需要对CMake设置native工具链路径,即:`-DCMAKE_TOOLCHAIN_FILE="/xxx/ohos-sdk/linux/native/build/cmake/ohos.toolchain.camke"`
- 工具链默认编译64位的程序,如果要编译32位,需要添加:`-DOHOS_ARCH="armeabi-v7a"`
2. 运行。
- 使用hdc_std连接rk3568开发板,并将demo和mobilenetv2.ms推送到设备中的相同目录。
- 使用hdc_std shell进入开发板,并进入demo所在的目录执行如下命令,即可得到结果。
```shell
./demo mobilenetv2.ms
```
得到如下输出:
```shell
# ./QuickStart ./mobilenetv2.ms
Tensor name: Softmax-65, tensor size is 4004 ,elements num: 1001.
output data is:
0.000018 0.000012 0.000026 0.000194 0.000156 0.001501 0.000240 0.000825 0.000016 0.000006 0.000007 0.000004 0.000004 0.000004 0.000015 0.000099 0.000011 0.000013 0.000005 0.000023 0.000004 0.000008 0.000003 0.000003 0.000008 0.000014 0.000012 0.000006 0.000019 0.000006 0.000018 0.000024 0.000010 0.000002 0.000028 0.000372 0.000010 0.000017 0.000008 0.000004 0.000007 0.000010 0.000007 0.000012 0.000005 0.000015 0.000007 0.000040 0.000004 0.000085 0.000023
```
...@@ -480,7 +480,7 @@ extensionAbility示例 : ...@@ -480,7 +480,7 @@ extensionAbility示例 :
"name": "ohos.extability.form", "name": "ohos.extability.form",
"resource": "$profile:form_config", "resource": "$profile:form_config",
} }
], ]
} }
] ]
} }
......
...@@ -105,6 +105,7 @@ ...@@ -105,6 +105,7 @@
- [@ohos.animation.windowAnimationManager (窗口动画管理)](js-apis-windowAnimationManager.md) - [@ohos.animation.windowAnimationManager (窗口动画管理)](js-apis-windowAnimationManager.md)
- [@ohos.display (屏幕属性)](js-apis-display.md) - [@ohos.display (屏幕属性)](js-apis-display.md)
- [@ohos.effectKit (图像效果)](js-apis-effectKit.md) - [@ohos.effectKit (图像效果)](js-apis-effectKit.md)
- [@ohos.graphics.colorSpaceManager(色彩管理)](js-apis-colorSpaceManager.md)
- [@ohos.screen (屏幕)](js-apis-screen.md) - [@ohos.screen (屏幕)](js-apis-screen.md)
- [@ohos.screenshot (屏幕截图)](js-apis-screenshot.md) - [@ohos.screenshot (屏幕截图)](js-apis-screenshot.md)
- [@ohos.window (窗口)](js-apis-window.md) - [@ohos.window (窗口)](js-apis-window.md)
......
...@@ -402,6 +402,8 @@ catch(err){ ...@@ -402,6 +402,8 @@ catch(err){
表示权限状态变化操作类型的枚举。 表示权限状态变化操作类型的枚举。
**系统接口:** 此接口为系统接口。
**系统能力:** SystemCapability.Security.AccessToken **系统能力:** SystemCapability.Security.AccessToken
| 名称 | 默认值 | 描述 | | 名称 | 默认值 | 描述 |
...@@ -411,6 +413,8 @@ catch(err){ ...@@ -411,6 +413,8 @@ catch(err){
### PermissionStateChangeInfo<sup>9+</sup> ### PermissionStateChangeInfo<sup>9+</sup>
**系统接口:** 此接口为系统接口。
**系统能力:** SystemCapability.Security.AccessToken **系统能力:** SystemCapability.Security.AccessToken
| 名称 | 类型 | 可读 | 可写 | 说明 | | 名称 | 类型 | 可读 | 可写 | 说明 |
......
...@@ -55,8 +55,6 @@ class MainAbility extends AccessibilityExtensionAbility { ...@@ -55,8 +55,6 @@ class MainAbility extends AccessibilityExtensionAbility {
**系统能力**:以下各项对应的系统能力均为 SystemCapability.Barrierfree.Accessibility.Core **系统能力**:以下各项对应的系统能力均为 SystemCapability.Barrierfree.Accessibility.Core
### 参数
| 名称 | 参数类型 | 可读 | 可写 | 说明 | | 名称 | 参数类型 | 可读 | 可写 | 说明 |
| ------ | ------ | ---- | ---- | --------- | | ------ | ------ | ---- | ---- | --------- |
| left | number | 是 | 否 | 矩形区域的左边界。 | | left | number | 是 | 否 | 矩形区域的左边界。 |
...@@ -75,35 +73,9 @@ class MainAbility extends AccessibilityExtensionAbility { ...@@ -75,35 +73,9 @@ class MainAbility extends AccessibilityExtensionAbility {
| application | 表示应用窗口类型。 | | application | 表示应用窗口类型。 |
| system | 表示系统窗口类型。 | | system | 表示系统窗口类型。 |
## AccessibilityExtensionContext.setEventTypeFilter
setEventTypeFilter(type: Array<accessibility.EventType>): Promise\<boolean>;
设置关注的事件类型。
**系统能力:** SystemCapability.BarrierFree.Accessibility.Core
**参数:**
| 参数名 | 参数类型 | 必填 | 说明 |
| ---- | ---------------------------------------- | ---- | -------- |
| type | Array&lt;[EventType](js-apis-accessibility.md#EventType)&gt; | 是 | 关注的事件类型。 |
**返回值:**
| 类型 | 说明 |
| ---------------------- | --------------------- |
| Promise&lt;boolean&gt; | Promise对象。返回当前设置是否成功。 |
**示例:**
```ts
this.context.setEventTypeFilter(['click', 'longClick']);
```
## AccessibilityExtensionContext.setTargetBundleName ## AccessibilityExtensionContext.setTargetBundleName
setTargetBundleName(targetNames: Array\<string>): Promise\<boolean>; setTargetBundleName(targetNames: Array\<string>): Promise\<void>;
设置关注的事件类型。 设置关注的事件类型。
...@@ -213,7 +185,7 @@ this.context.getWindows().then(windows => { ...@@ -213,7 +185,7 @@ this.context.getWindows().then(windows => {
## AccessibilityExtensionContext.injectGesture ## AccessibilityExtensionContext.injectGesture
injectGesture(gesturePath: GesturePath, listener: Callback\<boolean>): Promise\<boolean injectGesture(gesturePath: GesturePath, listener: Callback\<boolean>): Promise\<void>
注入手势。 注入手势。
...@@ -244,3 +216,170 @@ this.context.gestureInject(gesturePath, (result) => { ...@@ -244,3 +216,170 @@ this.context.gestureInject(gesturePath, (result) => {
console.info('gestureInject result: ' + result); console.info('gestureInject result: ' + result);
}) })
``` ```
## AccessibilityElement.attributeNames
attributeNames\<T extends keyof ElementAttributeValues>(): Promise\<Array<T>>;
获取节点元素的所有属性名称。
**系统能力:** SystemCapability.BarrierFree.Accessibility.Core
**返回值:**
| 类型 | 说明 |
| ---------------------------------------- | ------------------------ |
| Promise&lt;Array&lt;T&gt;&gt; | Promise对象。返回获取元素所有属性名称的调用结果。 |
**示例:**
```ts
let accessibilityElement;
try {
accessibilityElement.attributeNames().then((values) => {
console.log("get attribute names success");
}).catch((err) => {
console.log("get attribute names err: " + JSON.stringify(err));
});
} catch (e) {
console.log("An unexpected error occurred. Error:" + e);
}
```
## AccessibilityElement.attributeValue
attributeValue\<T extends keyof ElementAttributeValues>(attributeName: T): Promise\<ElementAttributeValues[T]>;
根据属性名称获取属性值。
**系统能力:** SystemCapability.BarrierFree.Accessibility.Core
**参数:**
| 参数名 | 参数类型 | 必填 | 说明 |
| ----------- | ---------------------------------------- | ---- | -------------- |
| attributeName | T | 是 | 表示属性的名称。 |
**返回值:**
| 类型 | 说明 |
| ---------------------------------------- | ------------------------ |
| Promise&lt;Array&lt;ElementAttributeValues[T]&gt;&gt; | Promise对象。返回根据属性名称获取属性值的调用结果。 |
**示例:**
```ts
let accessibilityElement;
try {
let attributeName = 'name';
accessibilityElement.attributeValue(attributeName).then((value) => {
console.log("get attribute value by name success");
}).catch((err) => {
console.log("get attribute value by name err: " + JSON.stringify(err));
});
} catch (e) {
console.log("An unexpected error occurred. Error:" + e);
}
```
## AccessibilityElement.actionNames
actionNames(): Promise\<Array<string>>;
获取节点元素支持的所有操作名称。
**系统能力:** SystemCapability.BarrierFree.Accessibility.Core
**返回值:**
| 类型 | 说明 |
| ---------------------------------------- | ------------------------ |
| Promise&lt;Array&lt;string&gt;&gt; | Promise对象。返回获取节点元素支持的所有操作名称的调用结果。 |
**示例:**
```ts
let accessibilityElement;
try {
accessibilityElement.actionNames().then((values) => {
console.log("get action names success");
}).catch((err) => {
console.log("get action names err: " + JSON.stringify(err));
});
} catch (e) {
console.log("An unexpected error occurred. Error:" + e);
}
```
## AccessibilityElement.performAction
performAction(actionName: string, parameters?: object): Promise\<boolean>;
根据操作名称执行某个操作。
**系统能力:** SystemCapability.BarrierFree.Accessibility.Core
**参数:**
| 参数名 | 参数类型 | 必填 | 说明 |
| ----------- | ---------------------------------------- | ---- | -------------- |
| actionName | string | 是 | 表示属性的名称。 |
| parameters | object | 否 | 表示执行操作时所需要的参数。 |
**返回值:**
| 类型 | 说明 |
| ---------------------------------------- | ------------------------ |
| Promise&lt;Array&lt;boolean&gt;&gt; | Promise对象。返回获取元素所有属性名的调用结果。 |
**示例:**
```ts
let accessibilityElement;
try {
accessibilityElement.performAction('action').then((result) => {
console.info('perform action result: ' + result);
}).catch((err) => {
console.log("perform action err: " + JSON.stringify(err));
});
} catch (e) {
console.log("An unexpected error occurred. Error:" + e);
}
```
## AccessibilityElement.findElement
findElement(type: 'content', condition: string): Promise\<Array<AccessibilityElement>>;
查询节点元素的指定内容。
**系统能力:** SystemCapability.BarrierFree.Accessibility.Core
**参数:**
| 参数名 | 参数类型 | 必填 | 说明 |
| ----------- | ---------------------------------------- | ---- | -------------- |
| type | string | 是 | 固定为'content',表示查找的类型为节点元素内容。 |
| condition | string | 是 | 表示查找的条件。 |
**返回值:**
| 类型 | 说明 |
| ---------------------------------------- | ------------------------ |
| Promise&lt;Array&lt;T&gt;&gt; | Promise对象。返回获取元素所有属性名的调用结果。 |
**示例:**
```ts
let accessibilityElement;
try {
let condition = 'keyword';
accessibilityElement.findElement('content', condition).then((values) => {
console.log("find element success");
}).catch((err) => {
console.log("find element err: " + JSON.stringify(err));
});
} catch (e) {
console.log("An unexpected error occurred. Error:" + e);
}
```
# 色彩管理
本模块提供管理抽象化色域对象的一些基础能力,包括色域对象的创建与色域基础属性的获取等。
> **说明:**
>
> 本模块首批接口从API version 9开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。
## 导入模块
```js
import colorSpaceManager from '@ohos.graphics.colorSpaceManager';
```
## ColorSpace
色域类型枚举。
**系统能力:** SystemCapability.Graphic.Graphic2D.ColorManager.Core
| 名称 | 值 | 说明 |
| --------------------------- | ------ | ----------------------- |
| UNKNOWN | 0 | 未知的色域类型。|
| ADOBE_RGB_1998 | 1 | RGB色域为Adobe RGB(1998)类型。 |
| DCI_P3 | 2 | RGB色域为DCI-P3类型。|
| DISPLAY_P3 | 3 | RGB色域为Display P3类型。 |
| SRGB | 4 | RGB色域为SRGB类型。<br>系统默认色域类型。 |
| CUSTOM | 5 | 用户自定义色域类型。|
## ColorSpacePrimaries
色域标准三原色(红、绿、蓝)和白色,使用(x, y)表示其在色彩空间中的位置。
**系统能力:** SystemCapability.Graphic.Graphic2D.ColorManager.Core
| 名称 | 参数类型 | 可读 | 可写 | 说明 |
| ---------------------------- | -------- | ---- | ---- | ----------------------------------------------------- |
| redX | number | 是 | 是 | 标准红色在色彩空间的x坐标值。 |
| redY | number | 是 | 是 | 标准红色在色彩空间的y坐标值。 |
| greenX | number | 是 | 是 | 标准绿色在色彩空间的x坐标值。 |
| greenY | number | 是 | 是 | 标准绿色在色彩空间的y坐标值。 |
| blueX | number | 是 | 是 | 标准蓝色在色彩空间的x坐标值。 |
| blueY | number | 是 | 是 | 标准蓝色在色彩空间的y坐标值。 |
| whitePointX | number | 是 | 是 | 标准白色在色彩空间的x坐标值。 |
| whitePointY | number | 是 | 是 | 标准白色在色彩空间的y坐标值。 |
## colorSpaceManager.create
create(colorSpaceName: ColorSpace): ColorSpaceManager
创建标准色域对象。
**系统能力:** SystemCapability.Graphic.Graphic2D.ColorManager.Core
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| --------------- | ------------------------ | ---- | -----------------------------|
| colorSpaceName | [ColorSpace](#colorspace)| 是 | 标准色域类型枚举值。<br>UNKNOWN与CUSTOM不可用于直接创建色域对象。 |
**返回值:**
| 类型 | 说明 |
| ------------------ | ------------------------ |
| [ColorSpaceManager](#colorspacemanager) | 返回当前创建的色域对象实例。 |
**示例:**
```js
let colorSpace = null;
try {
colorSpace = colorSpaceManager.create(colorSpaceManager.ColorSpace.SRGB);
} catch (err) {
console.log(`Failed to create SRGB colorSpace. Cause: ` + JSON.stringify(err));
}
```
## colorSpaceManager.create
create(primaries: ColorSpacePrimaries, gamma: number): ColorSpaceManager
创建用户自定义色域对象。
**系统能力:** SystemCapability.Graphic.Graphic2D.ColorManager.Core
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| --------------- | ------------------------------------------ | ---- | -----------------------------|
| primaries | [ColorSpacePrimaries](#colorspaceprimaries)| 是 | 色域标准三原色。 |
| gamma | number | 是 | 色域gamma值。 |
**返回值:**
| 类型 | 说明 |
| ------------------ | ------------------------ |
| [ColorSpaceManager](#colorspacemanager) | 返回当前创建的色域对象实例。<br>色域类型定义为[ColorSpace](#colorspace)枚举值`CUSTOM`。 |
**示例:**
```js
let colorSpace = null;
try {
let primaries = {
redX: 0.1,
redY: 0.1,
greenX: 0.2,
greenY: 0.2,
blueX: 0.3,
blueY: 0.3,
whitePointX: 0.4,
whitePointY: 0.4
};
let gamma = 2.2;
colorSpace = colorSpaceManager.create(primaries, gamma);
} catch (err) {
console.log(`Failed to create colorSpace with customized primaries and gamma. Cause: ` + JSON.stringify(err));
}
```
## ColorSpaceManager
当前色域对象实例。
下列API示例中都需先使用[create()](#colorspacemanagercreate)获取到ColorSpaceManager实例(i.e. `colorSpace`),再通过此实例调用对应方法。
### getColorSpaceName
getColorSpaceName(): ColorSpace
获取色域类型。
**系统能力:** SystemCapability.Graphic.Graphic2D.ColorManager.Core
**返回值:**
| 类型 | 说明 |
| ------------------ | ------------------------ |
| [ColorSpace](#colorspace) | 返回色域类型枚举值。 |
**示例:**
```js
try {
let csType = colorSpace.getColorSpaceName();
} catch (err) {
console.log(`Fail to get colorSpace's name. Cause: ` + JSON.stringify(err));
}
```
### getWhitePoint
getWhitePoint(): Array\<number\>
获取色域白点值。
**系统能力:** SystemCapability.Graphic.Graphic2D.ColorManager.Core
**返回值:**
| 类型 | 说明 |
| ------------------ | ------------------------ |
| Array\<number\> | 返回色域白点值[x, y]。 |
**示例:**
```js
try {
let wp = colorSpace.getWhitePoint();
} catch (err) {
console.log(`Failed to get white point. Cause: ` + JSON.stringify(err));
}
```
### getGamma
getGamma(): number
获取色域gamma值。
**系统能力:** SystemCapability.Graphic.Graphic2D.ColorManager.Core
**返回值:**
| 类型 | 说明 |
| ------------------ | ------------------------ |
| number | 返回色域gamma值。 |
**示例:**
```js
try {
let gamma = colorSpace.getGamma();
} catch (err) {
console.log(`Failed to get gamma. Cause: ` + JSON.stringify(err));
}
```
...@@ -18,7 +18,7 @@ import distributedObject from '@ohos.data.distributedDataObject'; ...@@ -18,7 +18,7 @@ import distributedObject from '@ohos.data.distributedDataObject';
createDistributedObject(source: object): DistributedObject createDistributedObject(source: object): DistributedObject
创建一个分布式对象。 创建一个分布式数据对象。
**系统能力:** SystemCapability.DistributedDataManager.DataObject.DistributedObject。 **系统能力:** SystemCapability.DistributedDataManager.DataObject.DistributedObject。
...@@ -26,13 +26,13 @@ createDistributedObject(source: object): DistributedObject ...@@ -26,13 +26,13 @@ createDistributedObject(source: object): DistributedObject
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| source | object | 是 | 设置distributedObject的属性。 | | source | object | 是 | 设置分布式数据对象的属性。 |
**返回值:** **返回值:**
| 类型 | 说明 | | 类型 | 说明 |
| -------- | -------- | | -------- | -------- |
| [DistributedObject](#distributedobject) | 创建完成的分布式对象。 | | [DistributedObject](#distributedobject) | 创建完成的分布式数据对象。 |
**示例:** **示例:**
...@@ -88,7 +88,7 @@ revokeSave接口回调信息。 ...@@ -88,7 +88,7 @@ revokeSave接口回调信息。
## DistributedObject ## DistributedObject
表示一个分布式对象。 表示一个分布式数据对象。
### setSessionId ### setSessionId
...@@ -104,7 +104,7 @@ setSessionId(sessionId?: string): boolean ...@@ -104,7 +104,7 @@ setSessionId(sessionId?: string): boolean
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| sessionId | string | 否 | 分布式对象在可信组网中的标识ID。如果要退出分布式组网,设置为""或不设置均可。 | | sessionId | string | 否 | 分布式数据对象在可信组网中的标识ID。如果要退出分布式组网,设置为""或不设置均可。 |
**返回值:** **返回值:**
...@@ -127,7 +127,7 @@ g_object.setSessionId(""); ...@@ -127,7 +127,7 @@ g_object.setSessionId("");
on(type: 'change', callback: Callback<{ sessionId: string, fields: Array&lt;string&gt; }>): void on(type: 'change', callback: Callback<{ sessionId: string, fields: Array&lt;string&gt; }>): void
监听分布式对象的变更。 监听分布式数据对象的变更。
**系统能力:** SystemCapability.DistributedDataManager.DataObject.DistributedObject。 **系统能力:** SystemCapability.DistributedDataManager.DataObject.DistributedObject。
...@@ -185,7 +185,7 @@ g_object.off("change"); ...@@ -185,7 +185,7 @@ g_object.off("change");
on(type: 'status', callback: Callback<{ sessionId: string, networkId: string, status: 'online' | 'offline' }>): void on(type: 'status', callback: Callback<{ sessionId: string, networkId: string, status: 'online' | 'offline' }>): void
监听分布式对象的上下线。 监听分布式数据对象的上下线。
**系统能力:** SystemCapability.DistributedDataManager.DataObject.DistributedObject。 **系统能力:** SystemCapability.DistributedDataManager.DataObject.DistributedObject。
......
...@@ -358,7 +358,7 @@ httpRequest.once('headersReceive', (header) => { ...@@ -358,7 +358,7 @@ httpRequest.once('headersReceive', (header) => {
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| -------------- | --------------------------------------------- | ---- | ------------------------------------------------------------ | | -------------- | --------------------------------------------- | ---- | ------------------------------------------------------------ |
| method | [RequestMethod](#requestmethod) | 否 | 请求方式。 | | method | [RequestMethod](#requestmethod) | 否 | 请求方式。 |
| extraData | string \| Object \| ArrayBuffer<sup>8+</sup> | 否 | 发送请求的额外数据。<br />- 当HTTP请求为POST、PUT等方法时,此字段为HTTP请求的content。<br />- 当HTTP请求为GET、OPTIONS、DELETE、TRACE、CONNECT等方法时,此字段为HTTP请求的参数补充,参数内容会拼接到URL中进行发送。<sup>8+</sup><br />- 开发者传入string对象,开发者需要自行编码,将编码后的string传入。<sup>8+</sup> | | extraData | string \| Object \| ArrayBuffer<sup>6+</sup> | 否 | 发送请求的额外数据。<br />- 当HTTP请求为POST、PUT等方法时,此字段为HTTP请求的content。<br />- 当HTTP请求为GET、OPTIONS、DELETE、TRACE、CONNECT等方法时,此字段为HTTP请求的参数补充,参数内容会拼接到URL中进行发送。<sup>6+</sup><br />- 开发者传入string对象,开发者需要自行编码,将编码后的string传入。<sup>6+</sup> |
| header | Object | 否 | HTTP请求头字段。默认{'Content-Type': 'application/json'}。 | | header | Object | 否 | HTTP请求头字段。默认{'Content-Type': 'application/json'}。 |
| readTimeout | number | 否 | 读取超时时间。单位为毫秒(ms),默认为60000ms。 | | readTimeout | number | 否 | 读取超时时间。单位为毫秒(ms),默认为60000ms。 |
| connectTimeout | number | 否 | 连接超时时间。单位为毫秒(ms),默认为60000ms。 | | connectTimeout | number | 否 | 连接超时时间。单位为毫秒(ms),默认为60000ms。 |
...@@ -432,7 +432,7 @@ request方法回调函数的返回值类型。 ...@@ -432,7 +432,7 @@ request方法回调函数的返回值类型。
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| -------------------- | -------------------------------------------- | ---- | ------------------------------------------------------------ | | -------------------- | -------------------------------------------- | ---- | ------------------------------------------------------------ |
| result | string \| Object \| ArrayBuffer<sup>8+</sup> | 是 | HTTP请求根据响应头中Content-type类型返回对应的响应格式内容:<br />- application/json:返回JSON格式的字符串,如需HTTP响应具体内容,需开发者自行解析<br />- application/octet-stream:ArrayBuffer<br />- 其他:string | | result | string \| Object \| ArrayBuffer<sup>6+</sup> | 是 | HTTP请求根据响应头中Content-type类型返回对应的响应格式内容:<br />- application/json:返回JSON格式的字符串,如需HTTP响应具体内容,需开发者自行解析<br />- application/octet-stream:ArrayBuffer<br />- 其他:string |
| responseCode | [ResponseCode](#responsecode) \| number | 是 | 回调函数执行成功时,此字段为[ResponseCode](#responsecode)。若执行失败,错误码将会从AsyncCallback中的err字段返回。错误码参考[Response错误码](#response常用错误码)。 | | responseCode | [ResponseCode](#responsecode) \| number | 是 | 回调函数执行成功时,此字段为[ResponseCode](#responsecode)。若执行失败,错误码将会从AsyncCallback中的err字段返回。错误码参考[Response错误码](#response常用错误码)。 |
| header | Object | 是 | 发起HTTP请求返回来的响应头。当前返回的是JSON格式字符串,如需具体字段内容,需开发者自行解析。常见字段及解析方式如下:<br/>- Content-Type:header['Content-Type'];<br />- Status-Line:header['Status-Line'];<br />- Date:header.Date/header['Date'];<br />- Server:header.Server/header['Server']; | | header | Object | 是 | 发起HTTP请求返回来的响应头。当前返回的是JSON格式字符串,如需具体字段内容,需开发者自行解析。常见字段及解析方式如下:<br/>- Content-Type:header['Content-Type'];<br />- Status-Line:header['Status-Line'];<br />- Date:header.Date/header['Date'];<br />- Server:header.Server/header['Server']; |
| cookies<sup>8+</sup> | Array\<string\> | 是 | 服务器返回的 cookies。 | | cookies<sup>8+</sup> | Array\<string\> | 是 | 服务器返回的 cookies。 |
......
...@@ -64,7 +64,7 @@ constructor(locale: string, options?: LocaleOptions) ...@@ -64,7 +64,7 @@ constructor(locale: string, options?: LocaleOptions)
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| ------- | ------------- | ---- | ---------------------------- | | ------- | ------------- | ---- | ---------------------------- |
| locale | string | 是 | 包含区域设置信息的字符串,包括语言以及可选的脚本和区域。 | | locale | string | 是 | 包含区域设置信息的字符串,包括语言以及可选的脚本和区域。 |
| options | LocaleOptions | 否 | 用于创建区域对象的选项。 | | options<sup>9+</sup> | [LocaleOptions](#localeoptions9) | 否 | 用于创建区域对象的选项。 |
**示例:** **示例:**
```js ```js
...@@ -181,7 +181,7 @@ constructor(locale: string | Array&lt;string&gt;, options?: DateTimeOptions) ...@@ -181,7 +181,7 @@ constructor(locale: string | Array&lt;string&gt;, options?: DateTimeOptions)
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| ------- | ----------------------------------- | ---- | ---------------------------- | | ------- | ----------------------------------- | ---- | ---------------------------- |
| locale | string \| Array&lt;string&gt; | 是 | 包含区域设置信息的字符串,包括语言以及可选的脚本和区域。 | | locale | string \| Array&lt;string&gt; | 是 | 包含区域设置信息的字符串,包括语言以及可选的脚本和区域。 |
| options | [DateTimeOptions](#datetimeoptions) | 否 | 用于创建时间日期格式化的选项。 | | options<sup>9+</sup> | [DateTimeOptions](#datetimeoptions9) | 否 | 用于创建时间日期格式化的选项。 |
**示例:** **示例:**
```js ```js
...@@ -265,7 +265,7 @@ resolvedOptions(): DateTimeOptions ...@@ -265,7 +265,7 @@ resolvedOptions(): DateTimeOptions
| 类型 | 说明 | | 类型 | 说明 |
| ----------------------------------- | ----------------------------- | | ----------------------------------- | ----------------------------- |
| [DateTimeOptions](#datetimeoptions) | DateTimeFormat&nbsp;对象的格式化选项。 | | [DateTimeOptions](#datetimeoptions9) | DateTimeFormat&nbsp;对象的格式化选项。 |
**示例:** **示例:**
```js ```js
...@@ -333,7 +333,7 @@ constructor(locale: string | Array&lt;string&gt;, options?: NumberOptions) ...@@ -333,7 +333,7 @@ constructor(locale: string | Array&lt;string&gt;, options?: NumberOptions)
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| ------- | ------------------------------- | ---- | ---------------------------- | | ------- | ------------------------------- | ---- | ---------------------------- |
| locale | string \| Array&lt;string&gt; | 是 | 包含区域设置信息的字符串,包括语言以及可选的脚本和区域。 | | locale | string \| Array&lt;string&gt; | 是 | 包含区域设置信息的字符串,包括语言以及可选的脚本和区域。 |
| options | [NumberOptions](#numberoptions) | 否 | 用于创建数字格式化的选项。 | | options<sup>9+</sup> | [NumberOptions](#numberoptions9) | 否 | 用于创建数字格式化的选项。 |
**示例:** **示例:**
```js ```js
...@@ -381,7 +381,7 @@ resolvedOptions(): NumberOptions ...@@ -381,7 +381,7 @@ resolvedOptions(): NumberOptions
| 类型 | 说明 | | 类型 | 说明 |
| ------------------------------- | --------------------------- | | ------------------------------- | --------------------------- |
| [NumberOptions](#numberoptions) | NumberFormat&nbsp;对象的格式化选项。 | | [NumberOptions](#numberoptions9) | NumberFormat&nbsp;对象的格式化选项。 |
**示例:** **示例:**
...@@ -450,7 +450,7 @@ constructor(locale: string | Array&lt;string&gt;, options?: CollatorOptions) ...@@ -450,7 +450,7 @@ constructor(locale: string | Array&lt;string&gt;, options?: CollatorOptions)
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| ------- | ----------------------------------- | ---- | ---------------------------- | | ------- | ----------------------------------- | ---- | ---------------------------- |
| locale | string \| Array&lt;string&gt; | 是 | 包含区域设置信息的字符串,包括语言以及可选的脚本和区域。 | | locale | string \| Array&lt;string&gt; | 是 | 包含区域设置信息的字符串,包括语言以及可选的脚本和区域。 |
| options | [CollatorOptions](#collatoroptions) | 否 | 用于创建排序对象的选项。 | | options<sup>9+</sup> | [CollatorOptions](#collatoroptions9) | 否 | 用于创建排序对象的选项。 |
**示例:** **示例:**
```js ```js
...@@ -498,7 +498,7 @@ resolvedOptions(): CollatorOptions ...@@ -498,7 +498,7 @@ resolvedOptions(): CollatorOptions
| 类型 | 说明 | | 类型 | 说明 |
| ----------------------------------- | ----------------- | | ----------------------------------- | ----------------- |
| [CollatorOptions](#collatoroptions) | 返回的Collator对象的属性。 | | [CollatorOptions](#collatoroptions9) | 返回的Collator对象的属性。 |
**示例:** **示例:**
```js ```js
...@@ -554,7 +554,7 @@ constructor(locale: string | Array&lt;string&gt;, options?: PluralRulesOptions) ...@@ -554,7 +554,7 @@ constructor(locale: string | Array&lt;string&gt;, options?: PluralRulesOptions)
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| ------- | ---------------------------------------- | ---- | ---------------------------- | | ------- | ---------------------------------------- | ---- | ---------------------------- |
| locale | string \| Array&lt;string&gt; | 是 | 包含区域设置信息的字符串,包括语言以及可选的脚本和区域。 | | locale | string \| Array&lt;string&gt; | 是 | 包含区域设置信息的字符串,包括语言以及可选的脚本和区域。 |
| options | [PluralRulesOptions](#pluralrulesoptions) | 否 | 用于创建单复数对象的选项。 | | options<sup>9+</sup> | [PluralRulesOptions](#pluralrulesoptions9) | 否 | 用于创建单复数对象的选项。 |
**示例:** **示例:**
```js ```js
...@@ -636,7 +636,7 @@ constructor(locale: string | Array&lt;string&gt;, options?: RelativeTimeFormatIn ...@@ -636,7 +636,7 @@ constructor(locale: string | Array&lt;string&gt;, options?: RelativeTimeFormatIn
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| ------- | ---------------------------------------- | ---- | ---------------------------- | | ------- | ---------------------------------------- | ---- | ---------------------------- |
| locale | string \| Array&lt;string&gt; | 是 | 包含区域设置信息的字符串,包括语言以及可选的脚本和区域。 | | locale | string \| Array&lt;string&gt; | 是 | 包含区域设置信息的字符串,包括语言以及可选的脚本和区域。 |
| options | [RelativeTimeFormatInputOptions](#relativetimeformatinputoptions) | 否 | 用于创建相对时间格式化对象的选项。 | | options<sup>9+</sup> | [RelativeTimeFormatInputOptions](#relativetimeformatinputoptions9) | 否 | 用于创建相对时间格式化对象的选项。 |
**示例:** **示例:**
```js ```js
...@@ -712,7 +712,7 @@ resolvedOptions(): RelativeTimeFormatResolvedOptions ...@@ -712,7 +712,7 @@ resolvedOptions(): RelativeTimeFormatResolvedOptions
| 类型 | 说明 | | 类型 | 说明 |
| ---------------------------------------- | --------------------------------- | | ---------------------------------------- | --------------------------------- |
| [RelativeTimeFormatResolvedOptions](#relativetimeformatresolvedoptions) | RelativeTimeFormat&nbsp;对象的格式化选项。 | | [RelativeTimeFormatResolvedOptions](#relativetimeformatresolvedoptions8) | RelativeTimeFormat&nbsp;对象的格式化选项。 |
**示例:** **示例:**
```js ```js
......
...@@ -280,8 +280,7 @@ connection.getDefaultNet().then(function (netHandle) { ...@@ -280,8 +280,7 @@ connection.getDefaultNet().then(function (netHandle) {
reportNetConnected(netHandle: NetHandle, callback: AsyncCallback&lt;void&gt;): void reportNetConnected(netHandle: NetHandle, callback: AsyncCallback&lt;void&gt;): void
向网络管理报告网络处于可用状态,调用此接口说明应用程序认为网络的可用性(ohos.net.connection.NetCap.NET_CAPABILITY_VAILDATED) 向网络管理报告网络处于可用状态,调用此接口说明应用程序认为网络的可用性(ohos.net.connection.NetCap.NET_CAPABILITY_VAILDATED)与网络管理不一致。
与连接管理不一致。
使用callback方式作为异步方法。 使用callback方式作为异步方法。
**需要权限**:ohos.permission.GET_NETWORK_INFO 和 ohos.permission.INTERNET **需要权限**:ohos.permission.GET_NETWORK_INFO 和 ohos.permission.INTERNET
...@@ -310,8 +309,7 @@ connection.getDefaultNet().then(function (netHandle) { ...@@ -310,8 +309,7 @@ connection.getDefaultNet().then(function (netHandle) {
reportNetConnected(netHandle: NetHandle): Promise&lt;void&gt; reportNetConnected(netHandle: NetHandle): Promise&lt;void&gt;
向网络管理报告网络处于可用状态,调用此接口说明应用程序认为网络的可用性(ohos.net.connection.NetCap.NET_CAPABILITY_VAILDATED) 向网络管理报告网络处于可用状态,调用此接口说明应用程序认为网络的可用性(ohos.net.connection.NetCap.NET_CAPABILITY_VAILDATED)与网络管理不一致。
与连接管理不一致。
使用promise方式作为异步方法。 使用promise方式作为异步方法。
**需要权限**:ohos.permission.GET_NETWORK_INFO 和 ohos.permission.INTERNET **需要权限**:ohos.permission.GET_NETWORK_INFO 和 ohos.permission.INTERNET
...@@ -344,7 +342,7 @@ connection.getDefaultNet().then(function (netHandle) { ...@@ -344,7 +342,7 @@ connection.getDefaultNet().then(function (netHandle) {
reportNetDisconnected(netHandle: NetHandle, callback: AsyncCallback&lt;void&gt;): void reportNetDisconnected(netHandle: NetHandle, callback: AsyncCallback&lt;void&gt;): void
向网络管理报告网络处于不可用状态,调用此接口说明应用程序认为网络的可用性(ohos.net.connection.NetCap.NET_CAPABILITY_VAILDATED)与连接管理不一致。 向网络管理报告网络处于不可用状态,调用此接口说明应用程序认为网络的可用性(ohos.net.connection.NetCap.NET_CAPABILITY_VAILDATED)与网络管理不一致。
使用callback方式作为异步方法。 使用callback方式作为异步方法。
**需要权限**:ohos.permission.GET_NETWORK_INFO 和 ohos.permission.INTERNET **需要权限**:ohos.permission.GET_NETWORK_INFO 和 ohos.permission.INTERNET
...@@ -373,7 +371,7 @@ connection.getDefaultNet().then(function (netHandle) { ...@@ -373,7 +371,7 @@ connection.getDefaultNet().then(function (netHandle) {
reportNetDisconnected(netHandle: NetHandle): Promise&lt;void&gt; reportNetDisconnected(netHandle: NetHandle): Promise&lt;void&gt;
向网络管理报告网络处于不可用状态,调用此接口说明应用程序认为网络的可用性(ohos.net.connection.NetCap.NET_CAPABILITY_VAILDATED)与连接管理不一致。 向网络管理报告网络处于不可用状态,调用此接口说明应用程序认为网络的可用性(ohos.net.connection.NetCap.NET_CAPABILITY_VAILDATED)与网络管理不一致。
使用promise方式作为异步方法。 使用promise方式作为异步方法。
**需要权限**:ohos.permission.GET_NETWORK_INFO 和 ohos.permission.INTERNET **需要权限**:ohos.permission.GET_NETWORK_INFO 和 ohos.permission.INTERNET
...@@ -956,7 +954,7 @@ connection.getDefaultNet().then(function (netHandle) { ...@@ -956,7 +954,7 @@ connection.getDefaultNet().then(function (netHandle) {
| NET_CAPABILITY_NOT_METERED | 11 | 表示网络流量未被计费。 | | NET_CAPABILITY_NOT_METERED | 11 | 表示网络流量未被计费。 |
| NET_CAPABILITY_INTERNET | 12 | 表示该网络应具有访问Internet的能力,该能力由网络提供者设置。 | | NET_CAPABILITY_INTERNET | 12 | 表示该网络应具有访问Internet的能力,该能力由网络提供者设置。 |
| NET_CAPABILITY_NOT_VPN | 15 | 表示网络不使用VPN(Virtual&nbsp;Private&nbsp;Network,虚拟专用网络)。 | | NET_CAPABILITY_NOT_VPN | 15 | 表示网络不使用VPN(Virtual&nbsp;Private&nbsp;Network,虚拟专用网络)。 |
| NET_CAPABILITY_VALIDATED | 16 | 表示该网络访问Internet的能力被连接管理成功验证,该能力由连接管理模块设置。 | | NET_CAPABILITY_VALIDATED | 16 | 表示该网络访问Internet的能力被网络管理成功验证,该能力由网络管理模块设置。 |
## NetBearType ## NetBearType
......
...@@ -232,61 +232,46 @@ lockScreen(): Promise&lt;boolean&gt; ...@@ -232,61 +232,46 @@ lockScreen(): Promise&lt;boolean&gt;
}); });
``` ```
## EventType
## screenlock.on<sup>9+</sup> 定义系统事件类型。
on(type: 'beginWakeUp' | 'endWakeUp' | 'beginScreenOn' | 'endScreenOn' | 'beginScreenOff' | 'endScreenOff' | 'unlockScreen' | 'beginExitAnimation', callback: Callback\<void\>): void
注册锁屏状态变化回调。
**系统能力**: SystemCapability.MiscServices.ScreenLock **系统能力**: SystemCapability.MiscServices.ScreenLock
**系统接口**:此接口为系统接口,三方应用不支持调用。 | 名称 | 说明 |
| -------- | -------- |
**参数** | beginWakeUp | 表示事件开始时开始唤醒。 |
| endWakeUp | 表示事件结束时结束唤醒。 |
| 参数名 | 类型 | 必填 | 说明 | | beginScreenOn | 表示事件开始时开始亮屏。 |
| -------- | -------- | -------- | -------- | | endScreenOn | 表示事件结束时结束亮屏。 |
| type | string | 是 | 设置事件类型。<br/>- type为"beginWakeUp",表示事件开始时开始唤醒。<br/>- type为"endWakeUp",表示事件结束时结束唤醒。<br/>- type为"beginScreenOn",表示事件开始时开始亮屏。<br/>- type为"endScreenOn",表示事件结束时结束亮屏。<br/>- type为"beginScreenOff",表示事件开始时开始灭屏。<br/>- type为"endScreenOff",表示事件结束时结束灭屏。<br/>- type为"unlockScreen",表示请求解锁。<br/>- type为"beginExitAnimation",表示动画开始退场。 | | beginScreenOff | 表示事件开始时开始灭屏。 |
| callback | Callback\<void\> | 是 | 事件回调方法。 | | endScreenOff | 表示事件结束时结束灭屏。 |
| unlockScreen | 表示请求解锁屏幕。 |
**示例** | lockScreen | 表示请求锁定屏幕。 |
| beginExitAnimation | 表示动画开始退场。 |
```js | beginSleep | 表示开始休眠。 |
screenlock.on('beginWakeUp', () => { | endSleep | 表示结束休眠。 |
console.log('beginWakeUp triggered'); | changeUser | 表示切换用户。 |
}); | screenlockEnabled | 表示锁屏是否启用。 |
``` | serviceRestart | 表示锁屏服务进行重启。 |
## screenlock.on<sup>9+</sup>
## SystemEvent
on(type: 'beginSleep' | 'endSleep' | 'changeUser', callback: Callback\<number\>): void
定义系统事件回调参数结构。
注册锁屏状态变化回调。
**系统能力**: SystemCapability.MiscServices.ScreenLock **系统能力**: SystemCapability.MiscServices.ScreenLock
**系统接口**:此接口为系统接口,三方应用不支持调用。 | 名称 | 说明 |
| -------- | -------- |
| eventType | 系统事件类型。 |
| params | 系统事件的事件参数。 |
**参数** ## screenlock.onSystemEvent<sup>9+</sup>
| 参数名 | 类型 | 必填 | 说明 | onSystemEvent(callback: Callback\<SystemEvent\>): boolean
| -------- | -------- | -------- | -------- |
| type | string | 是 | 设置事件类型。<br/>- type为"beginSleep",表示开始休眠。<br/>- type为"endSleep",表示结束休眠。<br/>- type为"changeUser",表示切换用户。 |
| callback | Callback\<number\> | 是 | 事件回调方法。<br/>返回事件相应的状态。 |
**示例** 注册锁屏相关的系统事件。
```js
screenlock.on('beginSleep', (why) => {
console.log('beginSleep triggered:' + why);
});
```
## screenlock.on<sup>9+</sup>
on(type: 'screenlockEnabled', callback: Callback\<boolean\>): void
注册锁屏状态变化回调。
**系统能力**: SystemCapability.MiscServices.ScreenLock **系统能力**: SystemCapability.MiscServices.ScreenLock
...@@ -296,41 +281,26 @@ on(type: 'screenlockEnabled', callback: Callback\<boolean\>): void ...@@ -296,41 +281,26 @@ on(type: 'screenlockEnabled', callback: Callback\<boolean\>): void
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| type | string | 是 | 设置事件类型。<br/>- type为"screenlockEnabled",表示锁屏是否启用。 | | callback | Callback\<SystemEvent\> | 是 | 锁屏相关的系统事件回调函数 |
| callback | Callback\<boolean\> | 是 | 注册成功的回调。<br/>回调结果用true/false表示。 |
**示例**
```js
screenlock.on('screenlockEnabled', (isEnabled) => {
console.log('screenlockEnabled triggered, result:' + isEnabled);
});
```
## screenlock.off<sup>9+</sup>
off(type: 'beginWakeUp' | 'endWakeUp' | 'beginScreenOn' | 'endScreenOn' | 'beginScreenOff' | 'endScreenOff' **返回值:**
| 'unlockScreen' | 'beginExitAnimation' | 'screenlockEnabled' | 'beginSleep' | 'endSleep' | 'changeUser', callback: Callback\<void\>): void
取消注册锁屏状态变化回调。 | 类型 | 说明 |
| ------- | -------------------------------------------- |
**系统能力**: SystemCapability.MiscServices.ScreenLock | boolean | 返回true表示锁屏系统事件注册成功,否则返回false|
**系统接口**:此接口为系统接口,三方应用不支持调用。
**参数**
| 参数名 | 类型 | 必填 | 说明 |
| -------- | -------- | -------- | -------- |
| type | string | 是 | 设置事件类型。<br/>- type为"beginWakeUp",表示事件开始时开始唤醒。<br/>- type为"endWakeUp",表示事件结束时结束唤醒。<br/>- type为"beginScreenOn",表示事件开始时开始亮屏。<br/>- type为"endScreenOn",表示事件结束时结束亮屏。<br/>- type为"beginScreenOff",表示事件开始时开始灭屏。<br/>- type为"endScreenOff",表示事件结束时结束灭屏。<br/>- type为"unlockScreen",表示请求解锁。<br/>- type为"beginExitAnimation",表示动画开始退场。<br/>- type为"screenlockEnabled",表示锁屏是否启用。<br/>- type为"beginSleep",表示开始休眠。<br/>- type为"endSleep",表示结束休眠。<br/>- type为"changeUser",表示切换用户。 |
| callback | Callback\<void\> | 是 | 注册成功的回调。 |
**示例** **示例**
```js ```js
screenlock.off('beginWakeUp', () => { let isSuccess = screenlock.onSystemEvent((err, event)=>{
console.log("callback"); console.log(`onSystemEvent:callback:${event.eventType}`)
}); if (err) {
console.log(`onSystemEvent callback error -> ${JSON.stringify(err)}`);
}
});
if (!isSuccess) {
console.log(`onSystemEvent result is false`)
}
``` ```
## screenlock.sendScreenLockEvent<sup>9+</sup> ## screenlock.sendScreenLockEvent<sup>9+</sup>
......
...@@ -55,7 +55,7 @@ import screenshot from '@ohos.screenshot'; ...@@ -55,7 +55,7 @@ import screenshot from '@ohos.screenshot';
## screenshot.save ## screenshot.save
save(options?: ScreenshotOptions, callback: AsyncCallback&lt;image.PixelMap&gt;): void save(options: ScreenshotOptions, callback: AsyncCallback&lt;image.PixelMap&gt;): void
获取屏幕截图。 获取屏幕截图。
...@@ -67,7 +67,7 @@ save(options?: ScreenshotOptions, callback: AsyncCallback&lt;image.PixelMap&gt;) ...@@ -67,7 +67,7 @@ save(options?: ScreenshotOptions, callback: AsyncCallback&lt;image.PixelMap&gt;)
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| -------- | --------------------------------------- | ---- | ------------------------------------------------------------ | | -------- | --------------------------------------- | ---- | ------------------------------------------------------------ |
| options | [ScreenshotOptions](#screenshotoptions) | 否 | 该类型的参数包含screenRect,imageSize,rotation, displayId四个参数,可以分别设置这四个参数。 | | options | [ScreenshotOptions](#screenshotoptions) | 是 | 该类型的参数包含screenRect、imageSize、rotation、displayId四个参数,可以分别设置这四个参数。 |
| callback | AsyncCallback&lt;[image.PixelMap](js-apis-image.md#pixelmap7)&gt; | 是 | 回调函数。返回一个PixelMap对象。 | | callback | AsyncCallback&lt;[image.PixelMap](js-apis-image.md#pixelmap7)&gt; | 是 | 回调函数。返回一个PixelMap对象。 |
**示例:** **示例:**
...@@ -97,6 +97,35 @@ save(options?: ScreenshotOptions, callback: AsyncCallback&lt;image.PixelMap&gt;) ...@@ -97,6 +97,35 @@ save(options?: ScreenshotOptions, callback: AsyncCallback&lt;image.PixelMap&gt;)
## screenshot.save ## screenshot.save
save(callback: AsyncCallback&lt;image.PixelMap&gt;): void
获取屏幕截图。
**系统能力:** SystemCapability.WindowManager.WindowManager.Core
**需要权限**:ohos.permission.CAPTURE_SCREEN,仅系统应用可用。
**参数:**
| 参数名 | 类型 | 必填 | 说明 |
| -------- | --------------------------------------- | ---- | ------------------------------------------------------------ |
| callback | AsyncCallback&lt;[image.PixelMap](js-apis-image.md#pixelmap7)&gt; | 是 | 回调函数。返回一个PixelMap对象。 |
**示例:**
```js
screenshot.save((err, pixelMap) => {
if (err) {
console.log('Failed to save screenshot: ' + JSON.stringify(err));
return;
}
console.log('Succeeded in saving sreenshot. Pixel bytes number: ' + pixelMap.getPixelBytesNumber());
pixelMap.release(); // PixelMap使用完后及时释放内存
});
```
## screenshot.save
save(options?: ScreenshotOptions): Promise&lt;image.PixelMap&gt; save(options?: ScreenshotOptions): Promise&lt;image.PixelMap&gt;
获取屏幕截图。 获取屏幕截图。
......
...@@ -316,7 +316,7 @@ udp.bind({address: '192.168.xx.xxx', port: xxxx, family: 1}, err => { ...@@ -316,7 +316,7 @@ udp.bind({address: '192.168.xx.xxx', port: xxxx, family: 1}, err => {
return; return;
} }
console.log('bind success'); console.log('bind success');
let promise = udp.getState({}); let promise = udp.getState();
promise.then(data => { promise.then(data => {
console.log('getState success:' + JSON.stringify(data)); console.log('getState success:' + JSON.stringify(data));
}).catch(err => { }).catch(err => {
...@@ -626,7 +626,7 @@ UDPSocket发送参数。 ...@@ -626,7 +626,7 @@ UDPSocket发送参数。
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| ------- | ---------------------------------- | ---- | -------------- | | ------- | ---------------------------------- | ---- | -------------- |
| data | string \| ArrayBuffer<sup>8+</sup> | 是 | 发送的数据。 | | data | string \| ArrayBuffer<sup>7+</sup> | 是 | 发送的数据。 |
| address | [NetAddress](#netaddress) | 是 | 目标地址信息。 | | address | [NetAddress](#netaddress) | 是 | 目标地址信息。 |
## UDPExtraOptions ## UDPExtraOptions
...@@ -1434,7 +1434,7 @@ TCPSocket发送请求的参数。 ...@@ -1434,7 +1434,7 @@ TCPSocket发送请求的参数。
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| -------- | ------ | ---- | ------------------------------------------------------------ | | -------- | ------ | ---- | ------------------------------------------------------------ |
| data | string\| ArrayBuffer<sup>8+</sup> | 是 | 发送的数据。 | | data | string\| ArrayBuffer<sup>7+</sup> | 是 | 发送的数据。 |
| encoding | string | 否 | 字符编码(UTF-8,UTF-16BE,UTF-16LE,UTF-16,US-AECII,ISO-8859-1),默认为UTF-8。 | | encoding | string | 否 | 字符编码(UTF-8,UTF-16BE,UTF-16LE,UTF-16,US-AECII,ISO-8859-1),默认为UTF-8。 |
## TCPExtraOptions ## TCPExtraOptions
......
...@@ -395,7 +395,7 @@ bulkTransfer(pipe: USBDevicePipe, endpoint: USBEndpoint, buffer: Uint8Array, tim ...@@ -395,7 +395,7 @@ bulkTransfer(pipe: USBDevicePipe, endpoint: USBEndpoint, buffer: Uint8Array, tim
| pipe | [USBDevicePipe](#usbdevicepipe) | 是 | 用于确定设备。 | | pipe | [USBDevicePipe](#usbdevicepipe) | 是 | 用于确定设备。 |
| endpoint | [USBEndpoint](#usbendpoint) | 是 | 用于确定传输的端口。 | | endpoint | [USBEndpoint](#usbendpoint) | 是 | 用于确定传输的端口。 |
| buffer | Uint8Array | 是 | 用于写入或读取的缓冲区。 | | buffer | Uint8Array | 是 | 用于写入或读取的缓冲区。 |
| timeout | number | 否 | 超时时间(单位:ms),可选参数,默认为0不超时。,可选参数,默认为0不超时。 | | timeout | number | 否 | 超时时间(单位:ms),可选参数,默认为0不超时。|
**返回值:** **返回值:**
......
...@@ -30,7 +30,6 @@ Worker构造函数的选项信息,用于为Worker添加其他信息。 ...@@ -30,7 +30,6 @@ Worker构造函数的选项信息,用于为Worker添加其他信息。
| 名称 | 参数类型 | 可读 | 可写 | 说明 | | 名称 | 参数类型 | 可读 | 可写 | 说明 |
| ------ | --------- | ---- | ---- | ---------------------- | | ------ | --------- | ---- | ---- | ---------------------- |
| name | string | 是 | 是 | Worker的名称。 | | name | string | 是 | 是 | Worker的名称。 |
| shared | boolean | 是 | 是 | Worker是否可以被分享。 |
## Worker ## Worker
...@@ -50,7 +49,7 @@ Worker构造函数。 ...@@ -50,7 +49,7 @@ Worker构造函数。
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| --------- | ------------------------------- | ---- | ------------------------------------------------------------ | | --------- | ------------------------------- | ---- | ------------------------------------------------------------ |
| scriptURL | string | 是 | Worker执行脚本的url。<br/>在FA和Stage模型下,DevEco Studio新建Worker工程路径分别存在以下两种情况:<br/>(a) workers目录与pages目录同级。<br/>(b) workers目录与pages目录不同级。 | scriptURL | string | 是 | Worker执行脚本的路径。<br/>在FA和Stage模型下,DevEco Studio新建Worker工程路径分别存在以下两种情况:<br/>(a) worker脚本所在目录与pages目录同级。<br/>(b) worker脚本所在目录与pages目录不同级。
| options | [WorkerOptions](#workeroptions) | 否 | Worker构造的选项。 | | options | [WorkerOptions](#workeroptions) | 否 | Worker构造的选项。 |
**返回值:** **返回值:**
...@@ -66,22 +65,23 @@ import worker from '@ohos.worker'; ...@@ -66,22 +65,23 @@ import worker from '@ohos.worker';
// worker线程创建 // worker线程创建
// FA模型-目录同级 // FA模型-目录同级
const workerFAModel01 = new worker.Worker("workers/worker.js", {name:"first worker"}); const workerFAModel01 = new worker.Worker("workers/worker.js", {name:"first worker in FA model"});
// FA模型-目录不同级(以workers目录放置pages目录前一级为例) // FA模型-目录不同级(以workers目录放置pages目录前一级为例)
const workerFAModel02 = new worker.Worker("../workers/worker.js", {name:"first worker"}); const workerFAModel02 = new worker.Worker("../workers/worker.js");
// Stage模型-目录同级 // Stage模型-目录同级
const workerStageModel01 = new worker.Worker('entry/ets/workers/worker.ts'); const workerStageModel01 = new worker.Worker('entry/ets/workers/worker.ts', {name:"first worker in Stage model"});
// Stage模型-目录不同级(以workers目录放置pages目录后一级为例) // Stage模型-目录不同级(以workers目录放置pages目录后一级为例)
const workerStageModel02 = new worker.Worker('entry/ets/pages/workers/worker.ts'); const workerStageModel02 = new worker.Worker('entry/ets/pages/workers/worker.ts');
// scriptURL——"entry/ets/workers/worker.ts"的解释 // 理解Stage模型scriptURL的"entry/ets/workers/worker.ts"
// entry: 为module.json5中module中name属性的值; // entry: 为module.json5文件中module的name属性对应的值;
// ets: 表明当前使用的语言。 // ets: 表明当前使用的语言。
``` ```
同时,需在工程目录下build-profile.json5文件的buildOption属性中添加配置信息,主要分为下面两种情况: 同时,需在工程的模块级build-profile.json5文件的buildOption属性中添加配置信息,主要分为下面两种情况:
(1) 目录同级( **不添加也可以** ) (1) 目录同级( **不添加也可以** )
FA模型: FA模型:
```json ```json
...@@ -104,6 +104,7 @@ Stage模型: ...@@ -104,6 +104,7 @@ Stage模型:
} }
``` ```
(2) 目录不同级( **必须添加** ) (2) 目录不同级( **必须添加** )
FA模型: FA模型:
```json ```json
"buildOption": { "buildOption": {
...@@ -128,7 +129,7 @@ Stage模型: ...@@ -128,7 +129,7 @@ Stage模型:
postMessage(message: Object, options?: PostMessageOptions): void postMessage(message: Object, options?: PostMessageOptions): void
向Worker线程发送消息,数据的传输采用结构化克隆算法 向Worker线程发送数据,数据类型必须是序列化所支持的类型。序列化支持类型见其他说明
**系统能力:** SystemCapability.Utils.Lang **系统能力:** SystemCapability.Utils.Lang
...@@ -163,8 +164,8 @@ on(type: string, listener: EventListener): void ...@@ -163,8 +164,8 @@ on(type: string, listener: EventListener): void
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| -------- | ------------------------------- | ---- | ---------------- | | -------- | ------------------------------- | ---- | ---------------- |
| type | string | 是 | 监听事件的type。 | | type | string | 是 | 监听的事件类型。 |
| listener | [EventListener](#eventlistener) | 是 | 回调的事件。 | | listener | [EventListener](#eventlistener) | 是 | 回调事件。 |
**示例:** **示例:**
...@@ -188,8 +189,8 @@ once(type: string, listener: EventListener): void ...@@ -188,8 +189,8 @@ once(type: string, listener: EventListener): void
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| -------- | ------------------------------- | ---- | ---------------- | | -------- | ------------------------------- | ---- | ---------------- |
| type | string | 是 | 监听事件的type。 | | type | string | 是 | 监听的事件类型。 |
| listener | [EventListener](#eventlistener) | 是 | 回调的事件。 | | listener | [EventListener](#eventlistener) | 是 | 回调事件。 |
**示例:** **示例:**
...@@ -205,7 +206,7 @@ workerInstance.once("alert", (e)=>{ ...@@ -205,7 +206,7 @@ workerInstance.once("alert", (e)=>{
off(type: string, listener?: EventListener): void off(type: string, listener?: EventListener): void
删除Worker的事件监听。 删除类型为type的事件监听。
**系统能力:** SystemCapability.Utils.Lang **系统能力:** SystemCapability.Utils.Lang
...@@ -213,8 +214,8 @@ off(type: string, listener?: EventListener): void ...@@ -213,8 +214,8 @@ off(type: string, listener?: EventListener): void
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| -------- | ------------------------------- | ---- | ---------------------- | | -------- | ------------------------------- | ---- | ---------------------- |
| type | string | 是 | 需要删除事件的type。 | | type | string | 是 | 需要删除的事件类型。 |
| listener | [EventListener](#eventlistener) | 否 | 需要删除的回调的事件。 | | listener | [EventListener](#eventlistener) | 否 | 删除的回调事件。 |
**示例:** **示例:**
...@@ -228,7 +229,7 @@ workerInstance.off("alert"); ...@@ -228,7 +229,7 @@ workerInstance.off("alert");
terminate(): void terminate(): void
关闭Worker线程,终止Worker接收消息。 销毁Worker线程,终止Worker接收消息。
**系统能力:** SystemCapability.Utils.Lang **系统能力:** SystemCapability.Utils.Lang
...@@ -244,7 +245,7 @@ workerInstance.terminate(); ...@@ -244,7 +245,7 @@ workerInstance.terminate();
onexit?: (code: number) =&gt; void onexit?: (code: number) =&gt; void
Worker对象的onexit属性表示Worker退出时被调用的事件处理程序,处理程序在宿主线程中执行。 Worker对象的onexit属性表示Worker销毁时被调用的事件处理程序,处理程序在宿主线程中执行。
**系统能力:** SystemCapability.Utils.Lang **系统能力:** SystemCapability.Utils.Lang
...@@ -353,7 +354,7 @@ addEventListener(type: string, listener: EventListener): void ...@@ -353,7 +354,7 @@ addEventListener(type: string, listener: EventListener): void
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| -------- | ------------------------------- | ---- | ---------------- | | -------- | ------------------------------- | ---- | ---------------- |
| type | string | 是 | 监听事件的type。 | | type | string | 是 | 监听的事件类型。 |
| listener | [EventListener](#eventlistener) | 是 | 回调的事件。 | | listener | [EventListener](#eventlistener) | 是 | 回调的事件。 |
**示例:** **示例:**
...@@ -378,8 +379,8 @@ removeEventListener(type: string, callback?: EventListener): void ...@@ -378,8 +379,8 @@ removeEventListener(type: string, callback?: EventListener): void
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| -------- | ------------------------------- | ---- | ---------------------- | | -------- | ------------------------------- | ---- | ---------------------- |
| type | string | 是 | 需要删除事件的type。 | | type | string | 是 | 需要删除的监听事件类型。 |
| callback | [EventListener](#eventlistener) | 否 | 需要删除的回调的事件。 | | callback | [EventListener](#eventlistener) | 否 | 删除的回调事件。 |
**示例:** **示例:**
...@@ -421,7 +422,7 @@ workerInstance.dispatchEvent({type:"alert"}); ...@@ -421,7 +422,7 @@ workerInstance.dispatchEvent({type:"alert"});
removeAllListener(): void removeAllListener(): void
删除Worker的所有事件监听。 删除Worker所有的事件监听。
**系统能力:** SystemCapability.Utils.Lang **系统能力:** SystemCapability.Utils.Lang
...@@ -435,14 +436,14 @@ workerInstance.removeAllListener(); ...@@ -435,14 +436,14 @@ workerInstance.removeAllListener();
## DedicatedWorkerGlobalScope ## DedicatedWorkerGlobalScope
Worker线程用于与宿主线程通信的类,通过postMessage接口发送消息给宿主线程、close接口关闭Worker线程,DedicatedWorkerGlobalScope类继承[WorkerGlobalScope](#workerglobalscope) Worker线程用于与宿主线程通信的类,通过postMessage接口发送消息给宿主线程、close接口销毁Worker线程。DedicatedWorkerGlobalScope类继承[WorkerGlobalScope](#workerglobalscope)
### postMessage ### postMessage
postMessage(messageObject: Object, options?: PostMessageOptions): void postMessage(messageObject: Object, options?: PostMessageOptions): void
Worker向宿主线程发送消息。 Worker线程向宿主线程发送消息。
**系统能力:** SystemCapability.Utils.Lang **系统能力:** SystemCapability.Utils.Lang
...@@ -450,7 +451,7 @@ Worker向宿主线程发送消息。 ...@@ -450,7 +451,7 @@ Worker向宿主线程发送消息。
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| ------- | ----------------------------------------- | ---- | ------------------------------------------------------------ | | ------- | ----------------------------------------- | ---- | ------------------------------------------------------------ |
| message | Object | 是 | 发送至Worker的数据。 | | message | Object | 是 | 发送至宿主线程的数据。 |
| options | [PostMessageOptions](#postmessageoptions) | 否 | 可转移对象是ArrayBuffer的实例对象。transferList数组中不可传入null。 | | options | [PostMessageOptions](#postmessageoptions) | 否 | 可转移对象是ArrayBuffer的实例对象。transferList数组中不可传入null。 |
**示例:** **示例:**
...@@ -480,7 +481,7 @@ parentPort.onmessage = function(e){ ...@@ -480,7 +481,7 @@ parentPort.onmessage = function(e){
close(): void close(): void
关闭Worker线程,终止Worker接收消息。 销毁Worker线程,终止Worker接收消息。
**系统能力:** SystemCapability.Utils.Lang **系统能力:** SystemCapability.Utils.Lang
...@@ -505,7 +506,7 @@ parentPort.onmessage = function(e) { ...@@ -505,7 +506,7 @@ parentPort.onmessage = function(e) {
onmessage?: (event: MessageEvent\<T>) =&gt; void onmessage?: (event: MessageEvent\<T>) =&gt; void
DedicatedWorkerGlobalScope的onmessage属性表示Worker线程收到来自其宿主线程通过worker.postMessage接口发送的消息时被调用的事件处理程序,处理程序在Worker线程中执行。 DedicatedWorkerGlobalScope的onmessage属性表示Worker线程收到来自其宿主线程通过postMessage接口发送的消息时被调用的事件处理程序,处理程序在Worker线程中执行。
**系统能力:** SystemCapability.Utils.Lang **系统能力:** SystemCapability.Utils.Lang
...@@ -513,7 +514,7 @@ DedicatedWorkerGlobalScope的onmessage属性表示Worker线程收到来自其宿 ...@@ -513,7 +514,7 @@ DedicatedWorkerGlobalScope的onmessage属性表示Worker线程收到来自其宿
| 参数名 | 类型 | 必填 | 说明 | | 参数名 | 类型 | 必填 | 说明 |
| ------ | ----------------------------- | ---- | ---------------------- | | ------ | ----------------------------- | ---- | ---------------------- |
| event | [MessageEvent](#messageevent) | 否 | 收到的Worker消息数据。 | | event | [MessageEvent](#messageevent) | 否 | 收到宿主线程发送的数据。 |
**示例:** **示例:**
...@@ -583,7 +584,7 @@ parentPort.onmessageerror= function(e) { ...@@ -583,7 +584,7 @@ parentPort.onmessageerror= function(e) {
| 名称 | 参数类型 | 可读 | 可写 | 说明 | | 名称 | 参数类型 | 可读 | 可写 | 说明 |
| --------- | -------- | ---- | ---- | ---------------------------------- | | --------- | -------- | ---- | ---- | ---------------------------------- |
| type | string | 是 | 否 | 指定事件的type。 | | type | string | 是 | 否 | 指定事件的类型。 |
| timeStamp | number | 是 | 否 | 事件创建时的时间戳(精度为毫秒)。 | | timeStamp | number | 是 | 否 | 事件创建时的时间戳(精度为毫秒)。 |
...@@ -653,7 +654,7 @@ Worker线程自身的运行环境,WorkerGlobalScope类继承[EventTarget](#eve ...@@ -653,7 +654,7 @@ Worker线程自身的运行环境,WorkerGlobalScope类继承[EventTarget](#eve
| 名称 | 参数类型 | 可读 | 可写 | 说明 | | 名称 | 参数类型 | 可读 | 可写 | 说明 |
| ---- | ------------------------------------------------------------ | ---- | ---- | --------------------------------------- | | ---- | ------------------------------------------------------------ | ---- | ---- | --------------------------------------- |
| name | string | 是 | 否 | Worker的名字,new&nbsp;Worker时指定。 | | name | string | 是 | 否 | Worker的名字,new&nbsp;Worker时指定。 |
| self | [WorkerGlobalScope](#workerglobalscope)&nbsp;&amp;&nbsp;typeof&nbsp;globalThis | 是 | 否 | WorkerGlobalScope本身。 | | self | [WorkerGlobalScope](#workerglobalscope)&nbsp;&amp;&nbsp;typeof&nbsp;globalThis | 是 | 否 | WorkerGlobalScope本身。 |
...@@ -689,6 +690,20 @@ parentPort.onerror = function(e){ ...@@ -689,6 +690,20 @@ parentPort.onerror = function(e){
## 其他说明 ## 其他说明
### 序列化支持类型
| Type | 备注 | 是否支持 |
| ------------------- | -------------------------------------------------------- | -------------------- |
| All Primitive Type | 不包括symbol | 是 |
| Date | | 是 |
| String | | 是 |
| RegExp | | 是 |
| Array | | 是 |
| Map | | 是 |
| Set | | 是 |
| Object | 只支持Create from literal的简单Object,不支持带function的 | 是 |
| ArrayBuffer | 提供transfer能力 | 是 |
| TypedArray | | 是 |
### 内存模型 ### 内存模型
Worker基于Actor并发模型实现。在Worker的交互流程中,JS主线程可以创建多个Worker子线程,各个Worker线程间相互隔离,并通过序列化传递对象,等到Worker线程完成计算任务,再把结果返回给主线程。 Worker基于Actor并发模型实现。在Worker的交互流程中,JS主线程可以创建多个Worker子线程,各个Worker线程间相互隔离,并通过序列化传递对象,等到Worker线程完成计算任务,再把结果返回给主线程。
......
...@@ -28,6 +28,7 @@ export default { ...@@ -28,6 +28,7 @@ export default {
```html ```html
<!-- xxx.hml --> <!-- xxx.hml -->
<element name='comp' src='../../common/comp/comp.hml'></element>
<div class="container"> <div class="container">
<text>父组件:{{text}}</text> <text>父组件:{{text}}</text>
<comp @event-type1="textClicked"></comp> <comp @event-type1="textClicked"></comp>
...@@ -46,3 +47,5 @@ export default { ...@@ -46,3 +47,5 @@ export default {
}, },
} }
``` ```
![EventParameters](figures/EventParameters.gif)
\ No newline at end of file
...@@ -80,12 +80,16 @@ struct PatternLockExample { ...@@ -80,12 +80,16 @@ struct PatternLockExample {
.backgroundColor(Color.White) .backgroundColor(Color.White)
.autoReset(true) .autoReset(true)
.onPatternComplete((input: Array<number>) => { .onPatternComplete((input: Array<number>) => {
if (input == null || input == undefined || input.length < 5) { // 判断输出的密码格式
if (input === null || input === undefined || input.length < 5) {
this.message = 'The password length needs to be greater than 5.' this.message = 'The password length needs to be greater than 5.'
// 重新触发该回调
return return
} }
// 判断密码长度是否大于0
if (this.passwords.length > 0) { if (this.passwords.length > 0) {
if (this.passwords.toString() == input.toString()) { // 判断俩次输入的密码是否相等
if (this.passwords.toString() === input.toString()) {
this.passwords = input this.passwords = input
this.message = 'Set password successfully: ' + this.passwords.toString() this.message = 'Set password successfully: ' + this.passwords.toString()
} else { } else {
......
...@@ -24,7 +24,7 @@ Scroll(scroller?: Scroller) ...@@ -24,7 +24,7 @@ Scroll(scroller?: Scroller)
| 名称 | 参数类型 | 描述 | | 名称 | 参数类型 | 描述 |
| -------------- | ---------------------------------------- | --------- | | -------------- | ---------------------------------------- | --------- |
| scrollable | ScrollDirection | 设置滚动方<br/>默认值:ScrollDirection.Vertical | | scrollable | ScrollDirection | 设置滚动方<br/>默认值:ScrollDirection.Vertical |
| scrollBar | [BarState](ts-appendix-enums.md#barstate) | 设置滚动条状态。<br/>默认值:BarState.Off | | scrollBar | [BarState](ts-appendix-enums.md#barstate) | 设置滚动条状态。<br/>默认值:BarState.Off |
| scrollBarColor | string&nbsp;\|&nbsp;number&nbsp;\|&nbsp;Color | 设置滚动条的颜色。 | | scrollBarColor | string&nbsp;\|&nbsp;number&nbsp;\|&nbsp;Color | 设置滚动条的颜色。 |
| scrollBarWidth | string&nbsp;\|&nbsp;number | 设置滚动条的宽度。 | | scrollBarWidth | string&nbsp;\|&nbsp;number | 设置滚动条的宽度。 |
...@@ -140,7 +140,7 @@ scrollToIndex(value: number): void ...@@ -140,7 +140,7 @@ scrollToIndex(value: number): void
| value | number | 是 | 要滑动到的列表项在列表中的索引值。 | | value | number | 是 | 要滑动到的列表项在列表中的索引值。 |
### scrollBy ### scrollBy<sup>9+</sup>
scrollBy(dx: Length, dy: Length): void scrollBy(dx: Length, dy: Length): void
......
...@@ -74,8 +74,8 @@ ...@@ -74,8 +74,8 @@
| 名称 | 类型 | 描述 | | 名称 | 类型 | 描述 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
| id | number | 手指的索引编号。 | | id | number | 手指的索引编号。 |
| globalX | number | 相对于设备屏幕左上角的x轴坐标。 | | globalX | number | 相对于应用窗口左上角的x轴坐标。 |
| globalY | number | 相对于设备屏幕左上角的y轴坐标。 | | globalY | number | 相对于应用窗口左上角的y轴坐标。 |
| localX | number | 相对于当前组件元素左上角的x轴坐标。 | | localX | number | 相对于当前组件元素左上角的x轴坐标。 |
| localY | number | 相对于当前组件元素左上角的y轴坐标。 | | localY | number | 相对于当前组件元素左上角的y轴坐标。 |
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
| height | [Length](ts-types.md#length) | 设置组件自身的高度,缺省时使用元素自身内容需要的高度。若子组件的高大于父组件的高,则会画出父组件的范围。 | | height | [Length](ts-types.md#length) | 设置组件自身的高度,缺省时使用元素自身内容需要的高度。若子组件的高大于父组件的高,则会画出父组件的范围。 |
| size | {<br/>width?:&nbsp;[Length](ts-types.md#length),<br/>height?:&nbsp;[Length](ts-types.md#length)<br/>} | 设置高宽尺寸。 | | size | {<br/>width?:&nbsp;[Length](ts-types.md#length),<br/>height?:&nbsp;[Length](ts-types.md#length)<br/>} | 设置高宽尺寸。 |
| padding | [Padding](ts-types.md#padding)&nbsp;\|&nbsp;[Length](ts-types.md#length) | 设置内边距属性。<br/>参数为Length类型时,四个方向内边距同时生效。<br>默认值:0 <br>padding设置百分比时,上下左右内边距均以父容器的width作为基础值。 | | padding | [Padding](ts-types.md#padding)&nbsp;\|&nbsp;[Length](ts-types.md#length) | 设置内边距属性。<br/>参数为Length类型时,四个方向内边距同时生效。<br>默认值:0 <br>padding设置百分比时,上下左右内边距均以父容器的width作为基础值。 |
| margin | [Margin](ts-types.md#margin))&nbsp;\|&nbsp;[Length](ts-types.md#length) | 设置外边距属性。<br/>参数为Length类型时,四个方向外边距同时生效。<br>默认值:0 <br>margin设置百分比时,上下左右边距均以父容器的width作为基础值。| | margin | [Margin](ts-types.md#margin))&nbsp;\|&nbsp;[Length](ts-types.md#length) | 设置外边距属性。<br/>参数为Length类型时,四个方向外边距同时生效。<br>默认值:0 <br>margin设置百分比时,上下左右边距均以父容器的width作为基础值。|
| constraintSize | {<br/>minWidth?:&nbsp;[Length](ts-types.md#length),<br/>maxWidth?:&nbsp;[Length](ts-types.md#length),<br/>minHeight?:&nbsp;[Length](ts-types.md#length),<br/>maxHeight?:&nbsp;[Length](ts-types.md#length)<br/>} | 设置约束尺寸,组件布局时,进行尺寸范围限制。constraintSize的优先级高于Width和Height。<br>默认值:<br>{<br/>minWidth:&nbsp;0,<br/>maxWidth:&nbsp;Infinity,<br/>minHeight:&nbsp;0,<br/>maxHeight:&nbsp;Infinity<br/>} | | constraintSize | {<br/>minWidth?:&nbsp;[Length](ts-types.md#length),<br/>maxWidth?:&nbsp;[Length](ts-types.md#length),<br/>minHeight?:&nbsp;[Length](ts-types.md#length),<br/>maxHeight?:&nbsp;[Length](ts-types.md#length)<br/>} | 设置约束尺寸,组件布局时,进行尺寸范围限制。constraintSize的优先级高于Width和Height。<br>默认值:<br>{<br/>minWidth:&nbsp;0,<br/>maxWidth:&nbsp;Infinity,<br/>minHeight:&nbsp;0,<br/>maxHeight:&nbsp;Infinity<br/>} |
| layoutWeight | number&nbsp;\|&nbsp;string | 容器尺寸确定时,元素与兄弟节点主轴布局尺寸按照权重进行分配,忽略本身尺寸设置,表示自适应占满剩余空间。<br>**说明:**<br/>仅在Row/Column/Flex布局中生效。<br>默认值:0 | | layoutWeight | number&nbsp;\|&nbsp;string | 容器尺寸确定时,元素与兄弟节点主轴布局尺寸按照权重进行分配,忽略本身尺寸设置,表示自适应占满剩余空间。<br>**说明:**<br/>仅在Row/Column/Flex布局中生效。<br>默认值:0 |
......
...@@ -14,15 +14,14 @@ ...@@ -14,15 +14,14 @@
| onClick(event:&nbsp;(event?:&nbsp;ClickEvent)&nbsp;=&gt;&nbsp;void) | 否 | 点击动作触发该方法调用,event参数见ClickEvent介绍。 | | onClick(event:&nbsp;(event?:&nbsp;ClickEvent)&nbsp;=&gt;&nbsp;void) | 否 | 点击动作触发该方法调用,event参数见ClickEvent介绍。 |
## ClickEvent对象说明 ## ClickEvent对象说明
| 属性名称 | 类型 | 描述 |
| 属性名称 | 类型 | 描述 | | ------------------- | ------------------------------------ | -------------------------------------------------------- |
| ------------------- | -------------------------------- | ------------------- | | screenX | number | 点击点相对于应用窗口左上角的X坐标。 |
| screenX | number | 点击点相对于设备屏幕左边沿的X坐标。 | | screenY | number | 点击点相对于应用窗口左上角的Y坐标。 |
| screenY | number | 点击点相对于设备屏幕上边沿的Y坐标。 | | x | number | 点击点相对于被点击元素左上角的X坐标。 |
| x | number | 点击点相对于被点击元素左边沿的X坐标。 | | y | number | 点击点相对于被点击元素左上角的Y坐标。 |
| y | number | 点击点相对于被点击元素上边沿的Y坐标。 | | target<sup>8+</sup> | [EventTarget](#eventtarget8对象说明) | 被点击元素对象。 |
| target<sup>8+</sup> | [EventTarget](#eventtarget8对象说明) | 被点击元素对象。 | | timestamp | number | 事件时间戳。触发事件时距离系统启动的时间间隔,单位纳秒。 |
| timestamp | number | 事件时间戳。 |
## EventTarget<sup>8+</sup>对象说明 ## EventTarget<sup>8+</sup>对象说明
......
...@@ -16,27 +16,27 @@ ...@@ -16,27 +16,27 @@
## TouchEvent对象说明 ## TouchEvent对象说明
| 名称 | 类型 | 描述 | | 名称 | 类型 | 描述 |
| ------------------- | ---------------------------------------- | ------------ | | ------------------- | ---------------------------------------- | ------------ |
| type | [TouchType](ts-appendix-enums.md#touchtype) | 触摸事件的类型。 | | type | [TouchType](ts-appendix-enums.md#touchtype) | 触摸事件的类型。 |
| touches | Array&lt;[TouchObject](#touchobject对象说明)&gt; | 全部手指信息。 | | touches | Array&lt;[TouchObject](#touchobject对象说明)&gt; | 全部手指信息。 |
| changedTouches | Array&lt;[TouchObject](#touchobject对象说明)&gt; | 当前发生变化的手指信息。 | | changedTouches | Array&lt;[TouchObject](#touchobject对象说明)&gt; | 当前发生变化的手指信息。 |
| stopPropagation | () => void | 阻塞事件冒泡。 | | stopPropagation | () => void | 阻塞事件冒泡。 |
| timestamp<sup>8+</sup> | number | 事件时间戳。 | | timestamp<sup>8+</sup> | number | 事件时间戳。触发事件时距离系统启动的时间间隔,单位纳秒。 |
| target<sup>8+</sup> | [EventTarget](ts-universal-events-click.md) | 触发手势事件的元素对象显示区域。 | | target<sup>8+</sup> | [EventTarget](ts-universal-events-click.md) | 触发手势事件的元素对象显示区域。 |
| source<sup>8+</sup> | [SourceType](ts-gesture-settings.md) | 事件输入设备。 | | source<sup>8+</sup> | [SourceType](ts-gesture-settings.md) | 事件输入设备。 |
## TouchObject对象说明 ## TouchObject对象说明
| 名称 | 类型 | 描述 | | 名称 | 类型 | 描述 |
| ------- | --------------------------- | ------------------- | | ------- | ------------------------------------------- | ------------------------------------- |
| type | [TouchType](ts-appendix-enums.md#touchtype) | 触摸事件的类型。 | | type | [TouchType](ts-appendix-enums.md#touchtype) | 触摸事件的类型。 |
| id | number | 手指唯一标识符。 | | id | number | 手指唯一标识符。 |
| screenX | number | 触摸点相对于设备屏幕左边沿的X坐标。 | | screenX | number | 触摸点相对于应用窗口左上角的X坐标。 |
| screenY | number | 触摸点相对于设备屏幕上边沿的Y坐标。 | | screenY | number | 触摸点相对于应用窗口左上角的Y坐标。 |
| x | number | 触摸点相对于被触摸元素左边沿的X坐标。 | | x | number | 触摸点相对于被触摸元素左上角的X坐标。 |
| y | number | 触摸点相对于被触摸元素上边沿的Y坐标。 | | y | number | 触摸点相对于被触摸元素左上角的Y坐标。 |
## 示例 ## 示例
......
...@@ -19,14 +19,14 @@ ...@@ -19,14 +19,14 @@
| 名称 | 属性类型 | 描述 | | 名称 | 属性类型 | 描述 |
| --------- | ------------------------------- | -------------------- | | --------- | ------------------------------- | -------------------- |
| screenX | number | 点击触点相对于屏幕左上角的x轴坐标。 | | screenX | number | 点击触点相对于应用窗口左上角的x轴坐标。 |
| screenY | number | 点击触点相对于屏幕左上角的y轴坐标。 | | screenY | number | 点击触点相对于应用窗口左上角的y轴坐标。 |
| x | number | 点击触点相对于当前组件左上角的x轴坐标。 | | x | number | 点击触点相对于当前组件左上角的x轴坐标。 |
| y | number | 点击触点相对于当前组件左上角的y轴坐标。 | | y | number | 点击触点相对于当前组件左上角的y轴坐标。 |
| button | [MouseButton](ts-appendix-enums.md#mousebutton) | 鼠标按键。 | | button | [MouseButton](ts-appendix-enums.md#mousebutton) | 鼠标按键。 |
| action | [MouseAction](ts-appendix-enums.md#mouseaction) | 事件动作。 | | action | [MouseAction](ts-appendix-enums.md#mouseaction) | 事件动作。 |
| stopPropagation | () => void | 阻塞事件冒泡。 | | stopPropagation | () => void | 阻塞事件冒泡。 |
| timestamp<sup>8+</sup> | number | 事件时间戳。 | | timestamp<sup>8+</sup> | number | 事件时间戳。触发事件时距离系统启动的时间间隔,单位纳秒。 |
| target<sup>8+</sup> | [EventTarget](ts-universal-events-click.md) | 触发手势事件的元素对象显示区域。 | | target<sup>8+</sup> | [EventTarget](ts-universal-events-click.md) | 触发手势事件的元素对象显示区域。 |
| source<sup>8+</sup> | [SourceType](ts-gesture-settings.md) | 事件输入设备。 | | source<sup>8+</sup> | [SourceType](ts-gesture-settings.md) | 事件输入设备。 |
......
...@@ -391,12 +391,12 @@ OpenHarmony系统内置密钥库文件,文件名称为OpenHarmony.p12,内含 ...@@ -391,12 +391,12 @@ OpenHarmony系统内置密钥库文件,文件名称为OpenHarmony.p12,内含
- **现象描述** - **现象描述**
执行命令后提示:`NOT_SUPPORT_ERROR, code: 105. Details: SignAlg params is incorrect, signature algorithms include SHA256withECDSA,SHA384withECDSA` 执行命令后提示:`NOT_SUPPORT_ERROR, code: 105. Details: SignAlg params is incorrect, signature algorithms include SHA256withECDSA,SHA384withECDSA`
- **可能原因** - **可能原因**
签名算法不支持,signAlg参数填写错误 签名算法不支持,signAlg参数填写错误
- **解决办法** - **解决办法**
最终实体证书密钥对推荐使用ECC生成,hap签名算法修改为ECC对应的SHA256withECDSA,SHA384withECDSA 最终实体证书密钥对推荐使用ECC生成,hap签名算法修改为ECC对应的SHA256withECDSA,SHA384withECDSA
...@@ -136,8 +136,10 @@ export default { ...@@ -136,8 +136,10 @@ export default {
- 绑定并阻止冒泡事件向上冒泡:grab:{event}.bubble。grab:{event}等价于grab:{event}.bubble。 - 绑定并阻止冒泡事件向上冒泡:grab:{event}.bubble。grab:{event}等价于grab:{event}.bubble。
> **说明:** > **说明:**
>
> 冒泡事件是指多个组件嵌套时,组件之间会有层次关系,当这些组件注册了相同的事件时,这个事件会首先运行在该元素上的处理程序,然后运行其父元素上的处理程序,一直向上到其他祖先上的处理程序。如果当一个组件触发了这个事件,它会首先触发该组件的回调函数,然后触发其父元素上的回调函数,然后触发其他祖先上的处理程序。
>
> 详细冒泡事件说明参见[通用事件](../reference/arkui-js/js-components-common-events.md)章节。 > 详细冒泡事件说明参见[通用事件](../reference/arkui-js/js-components-common-events.md)章节。
- 示例 - 示例
```html ```html
<!-- xxx.hml --> <!-- xxx.hml -->
......
...@@ -64,21 +64,35 @@ struct ComponentA { ...@@ -64,21 +64,35 @@ struct ComponentA {
} }
build() { build() {
Row({ space: 20 }) { Column(){
Row({ space: 20 }) {
Button(`${this.label}: ${this.varA}`) Button(`${this.label}: ${this.varA}`)
.onClick(() => { .onClick(() => {
AppStorage.Set<number>('varA', AppStorage.Get<number>('varA') + 1) AppStorage.Set<number>('varA', AppStorage.Get<number>('varA') + 1)
}) })
Button(`lang: ${this.lang}`) Button(`lang: ${this.lang}`)
.onClick(() => { .onClick(() => {
if (this.lang === 'zh') { if (this.lang === 'zh') {
AppStorage.Set<string>('languageCode', 'en') AppStorage.Set<string>('languageCode', 'en')
} else { } else {
AppStorage.Set<string>('languageCode', 'zh') AppStorage.Set<string>('languageCode', 'zh')
} }
this.label = (this.lang === 'zh') ? '' : 'Count' this.label = (this.lang === 'zh') ? '' : 'Count'
}) })
}
.margin({ bottom: 50 })
Row(){
Button(`更改@StorageLink修饰的变量:${this.varA}`).fontSize(10)
.onClick(() => {
this.varA++
})
}.margin({ bottom: 50 })
Row(){
Button(`更改@StorageProp修饰的变量:${this.lang}`).fontSize(10)
.onClick(() => {
this.lang = 'test'
})
}
} }
} }
} }
......
# @Builder # @Builder
@Builder装饰的方法用于定义组件的声明式UI描述,在一个自定义组件内快速生成多个布局内容。\@Builder装饰方法的功能和语法规范与[build函数](ts-function-build.md)相同。 @Builder装饰的方法用于定义组件的声明式UI描述,在一个自定义组件内快速生成多个布局内容。如果\@Builder装饰的方法中使用了自定义组件,那么该方法每次被调用时,对应的自定义组件均会重新创建。\@Builder装饰方法的功能和语法规范与[build函数](ts-function-build.md)相同。
```ts ```ts
// xxx.ets // xxx.ets
@Component
struct CompB {
@State CompValue: string = '';
aboutToAppear() {
console.info('CompB aboutToAppear.');
}
aboutToDisappear() {
console.info('CompB aboutToDisappear.');
}
build() {
Column() {
Button(this.CompValue);
}
}
}
@Entry @Entry
@Component @Component
struct CompA { struct CompA {
size1 : number = 100; size1: number = 100;
@State CompValue1: string = "Hello,CompValue1";
@State CompValue2: string = "Hello,CompValue2";
@State CompValue3: string = "Hello,CompValue3";
// @Builder装饰的函数内使用自定义组件
@Builder CompC(value: string) {
CompB({ CompValue: value });
}
@Builder SquareText(label: string) { @Builder SquareText(label: string) {
Text(label) Text(label)
...@@ -35,7 +63,16 @@ struct CompA { ...@@ -35,7 +63,16 @@ struct CompA {
} }
.width(2 * this.size1) .width(2 * this.size1)
.height(1 * this.size1) .height(1 * this.size1)
this.RowOfSquareTexts("C", "D") this.RowOfSquareTexts("C", "D")
Column() {
// 使用三次@Builder装饰的自定义组件
this.CompC(this.CompValue1);
this.CompC(this.CompValue2);
this.CompC(this.CompValue3);
}
.width(2 * this.size1)
.height(2 * this.size1)
} }
.width(2 * this.size1) .width(2 * this.size1)
.height(2 * this.size1) .height(2 * this.size1)
......
...@@ -9,8 +9,8 @@ ...@@ -9,8 +9,8 @@
| ---------------- | ------------------------------------------------------------ | | ---------------- | ------------------------------------------------------------ |
| aboutToAppear | 函数在创建自定义组件的新实例后,在执行其build函数之前执行。允许在aboutToAppear函数中改变状态变量,更改将在后续执行build函数中生效。 | | aboutToAppear | 函数在创建自定义组件的新实例后,在执行其build函数之前执行。允许在aboutToAppear函数中改变状态变量,更改将在后续执行build函数中生效。 |
| aboutToDisappear | 函数在自定义组件析构销毁之前执行。不允许在aboutToDisappear函数中改变状态变量,特别是@Link变量的修改可能会导致应用程序行为不稳定。 | | aboutToDisappear | 函数在自定义组件析构销毁之前执行。不允许在aboutToDisappear函数中改变状态变量,特别是@Link变量的修改可能会导致应用程序行为不稳定。 |
| onPageShow | 页面显示时触发一次,包括路由过程、应用进入前后台等场景,仅@Entry修饰的自定义组件生效。 | | onPageShow | 页面每次显示时触发一次,包括路由过程、应用进入前后台等场景,仅@Entry修饰的自定义组件生效。 |
| onPageHide | 页面消失时触发一次,包括路由过程、应用进入前后台等场景,仅@Entry修饰的自定义组件生效。 | | onPageHide | 页面每次隐藏时触发一次,包括路由过程、应用进入前后台等场景,仅@Entry修饰的自定义组件生效。 |
| onBackPress | 当用户点击返回按钮时触发,仅\@Entry修饰的自定义组件生效。<br/>-&nbsp;返回true表示页面自己处理返回逻辑,&nbsp;不进行页面路由。<br/>-&nbsp;返回false表示使用默认的返回逻辑。<br/>-&nbsp;不返回值会作为false处理。 | | onBackPress | 当用户点击返回按钮时触发,仅\@Entry修饰的自定义组件生效。<br/>-&nbsp;返回true表示页面自己处理返回逻辑,&nbsp;不进行页面路由。<br/>-&nbsp;返回false表示使用默认的返回逻辑。<br/>-&nbsp;不返回值会作为false处理。 |
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
| 4 | 目录修改 | 新增文件,需要修改对应的Readme,即`docs/zh-cn/application-dev/reference/apis/Readme-CN.md`。 | | 4 | 目录修改 | 新增文件,需要修改对应的Readme,即`docs/zh-cn/application-dev/reference/apis/Readme-CN.md`。 |
| 5 | 文档结构 | - 模块说明<br/>- 起始版本说明<br/>- 导入模块/使用说明<br/>- 接口(属性、方法、枚举、自定义类型)<br/> 描述顺序和代码保持一致,如果某些接口具有逻辑顺序,请注意排列。 | | 5 | 文档结构 | - 模块说明<br/>- 起始版本说明<br/>- 导入模块/使用说明<br/>- 接口(属性、方法、枚举、自定义类型)<br/> 描述顺序和代码保持一致,如果某些接口具有逻辑顺序,请注意排列。 |
| 6 | 接口版本说明 | 1. 每个模块要有起始版本说明,使用引用语法“>”对接口的起始版本进行说明。接口没有标记的,默认与模块同一个起始版本。<br/>2. 已有模块新增接口使用\<sup>标签标记对应版本号。写法:`<sup>版本号+</sup>`<br/> 例如`<sup>7+</sup>`<br/> 示例:API 6已有的模块,在API 7新增了一个属性字段,则在属性后加标记,即newAttribute<sup>7+</sup><br/>如果新增了一个方法,则在方法标题后增加标记,即 sim.getSimIccId<sup>7+</sup>,interface、class、枚举等同理。 | | 6 | 接口版本说明 | 1. 每个模块要有起始版本说明,使用引用语法“>”对接口的起始版本进行说明。接口没有标记的,默认与模块同一个起始版本。<br/>2. 已有模块新增接口使用\<sup>标签标记对应版本号。写法:`<sup>版本号+</sup>`<br/> 例如`<sup>7+</sup>`<br/> 示例:API 6已有的模块,在API 7新增了一个属性字段,则在属性后加标记,即newAttribute<sup>7+</sup><br/>如果新增了一个方法,则在方法标题后增加标记,即 sim.getSimIccId<sup>7+</sup>,interface、class、枚举等同理。 |
| 7 | 废弃接口说明 | 废弃内容不能直接删去,在废弃内容后面加标注deprecated,并使用“>”引用语法建议使用的替代方式,加上对应的链接。<br/>示例:abandonmentMethod<sup>(deprecated) </sup><br/>> 从API Version 7 开始不再维护,建议使用[newMethod]\(#newmethod)替代。 | | 7 | 废弃接口说明 | 废弃内容不能直接删去,在废弃内容后面加标注deprecated,并使用“>”引用语法建议使用的替代方式,加上对应的链接。<br/>示例:abandonmentMethod<sup>(deprecated) </sup><br/>> 从API version 7 开始不再维护,建议使用[newMethod]\(#newmethod)替代。 |
| 8 | 权限说明 | 与代码保持一致,下沉到各个方法、枚举、属性字段中。<br/>1. 如果仅系统应用可申请,格式:<br/> **需要权限:** ohos.permission.xxxx,仅系统应用可用。<br/>2. 如果该权限所有应用可申请,格式:<br/> **需要权限:** ohos.permission.xxxx <br/>3. 如果该接口涉及多个权限,则采用“和、或”进行分割,格式:<br/> **需要权限:** ohos.permission.A 和 ohos.permission.B<br/> **需要权限:** ohos.permission.A 或 ohos.permission.B | | 8 | 权限说明 | 与代码保持一致,下沉到各个方法、枚举、属性字段中。<br/>1. 如果仅系统应用可申请,格式:<br/> **需要权限:** ohos.permission.xxxx,仅系统应用可用。<br/>2. 如果该权限所有应用可申请,格式:<br/> **需要权限:** ohos.permission.xxxx <br/>3. 如果该接口涉及多个权限,则采用“和、或”进行分割,格式:<br/> **需要权限:** ohos.permission.A 和 ohos.permission.B<br/> **需要权限:** ohos.permission.A 或 ohos.permission.B |
| 9 | @syscap | 1. 每个方法都需要进行描述,格式:<br/> **系统能力**:SystemCapability.xxx.xxx<br/>2. 每个表格(属性、枚举、常量、变量)可统一进行说明,分两种情况:<br/> 1)每个表格下系统能力无差异的,同方法的写法:<br/> **系统能力**:SystemCapability.xxx.xxx<br/> 2)有差异的:在每一个表格项里进行描述。 | | 9 | @syscap | 1. 每个方法都需要进行描述,格式:<br/> **系统能力**:SystemCapability.xxx.xxx<br/>2. 每个表格(属性、枚举、常量、变量)可统一进行说明,分两种情况:<br/> 1)每个表格下系统能力无差异的,同方法的写法:<br/> **系统能力**:SystemCapability.xxx.xxx<br/> 2)有差异的:在每一个表格项里进行描述。 |
| 10 | @system api | 1. 如果某个模块全部接口均为system api,则在模块开头的版本说明下一行,增加:<br/> - 本模块接口为系统接口。<br/>2. 如果某个接口为system api,仅供OEM厂商使用,则需要在描述中增加:<br/> **系统接口:** 此接口为系统接口。 | | 10 | @system api | 1. 如果某个模块全部接口均为system api,则在模块开头的版本说明下一行,增加:<br/> - 本模块接口为系统接口。<br/>2. 如果某个接口为system api,仅供OEM厂商使用,则需要在描述中增加:<br/> **系统接口:** 此接口为系统接口。 |
......
...@@ -186,31 +186,29 @@ _[API差异报告](api-change/v3.2-beta1/readme.md)_ ...@@ -186,31 +186,29 @@ _[API差异报告](api-change/v3.2-beta1/readme.md)_
| 子系统 | 名称 | 简介 | 开发语言 | | 子系统 | 名称 | 简介 | 开发语言 |
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| ArkUI | MouseEvent | 本示例模拟了简单的扫雷游戏调用了鼠标事件的相关接口 | eTS | | ArkUI | [MouseEvent](https://gitee.com/openharmony/applications_app_samples/tree/master/ETSUI/MouseEvent) | 本示例模拟了简单的扫雷游戏调用了鼠标事件的相关接口 | eTS |
| ArkUI | Vibrator | 本示例模拟倒计时场景,展示振动接口的使用方法。 | eTS | | ArkUI | [Vibrator](https://gitee.com/openharmony/applications_app_samples/tree/master/device/Vibrator) | 本示例模拟倒计时场景,展示振动接口的使用方法。 | eTS |
| DFX | FaultLogger | 本示例展示了在eTS中如何获取应用故障相关信息。 | eTS | | DFX | [FaultLogger](https://gitee.com/openharmony/applications_app_samples/tree/master/DFX/FaultLogger) | 本示例展示了在eTS中如何获取应用故障相关信息。 | eTS |
| ArkUI | Gallery | 本Demo通过不同示例向用户介绍通用事件、通用属性、手势处理等不同组件的功能。 | eTS | | ArkUI | [Gallery](https://gitee.com/openharmony/applications_app_samples/tree/master/ETSUI/Gallery) | 本Demo通过不同示例向用户介绍通用事件、通用属性、手势处理等不同组件的功能。 | eTS |
| 图形 | JsWebGL | 本示例调用GPU资源绘制了五角星和矩形,展示WebGL相关接口的使用方法。 | JS | | 图形 | [JsWebGL](https://gitee.com/openharmony/applications_app_samples/tree/master/Graphics/JsWebGL) | 本示例调用GPU资源绘制了五角星和矩形,展示WebGL相关接口的使用方法。 | JS |
| ArkUI | Clock | 本示例使用eTS&nbsp;UI能力实现一个简单的时钟应用。 | eTS | | ArkUI | [Clock](https://gitee.com/openharmony/applications_app_samples/tree/master/Preset/Clock) | 本示例使用eTS&nbsp;UI能力实现一个简单的时钟应用。 | eTS |
| 网络管理 | Http | 本示例仿postman输入API接口地址,获取相应数据,介绍数据请求接口的用法。 | eTS | | 网络管理 | [Http](https://gitee.com/openharmony/applications_app_samples/tree/master/Network/Http) | 本示例仿postman输入API接口地址,获取相应数据,介绍数据请求接口的用法。 | eTS |
| ArkUI | FlishLight | 本示例通过屏幕的亮度变化来模拟手电筒功能,屏幕变亮模拟手电筒打开,屏幕变暗模拟手电筒关闭。 | eTS | | 网络管理 | [Socket](https://gitee.com/openharmony/applications_app_samples/tree/master/Network/Socket) | 本示例主要演示了Socket在网络通信方面的应用,展示了Socket在两端设备的连接验证、聊天通信方面的应用。 | eTS |
| 网络管理 | Socket | 本示例主要演示了Socket在网络通信方面的应用,展示了Socket在两端设备的连接验证、聊天通信方面的应用。 | eTS | | 分布式数据管理 | [DistributedRdb](https://gitee.com/openharmony/applications_app_samples/tree/master/data/DistributedRdb) | 本示例展示了在eTS中分布式关系型数据库的使用,在增、删、改、查的基本操作外,还包括分布式数据库的数据同步能力。 | eTS |
| 分布式数据管理 | DistributedRdb | 本示例展示了在eTS中分布式关系型数据库的使用,在增、删、改、查的基本操作外,还包括分布式数据库的数据同步能力。 | eTS | | 元能力 | [BackgroundTaskManager](https://gitee.com/openharmony/applications_app_samples/tree/master/ResourcesSchedule/BackgroundTaskManager) | 本示例模拟下载功能,将下载任务通过后台任务管理进行处理,实现退出应用后任务仍能够执行,直至任务结束。 | eTS |
| 元能力 | BackgroundTaskManager | 本示例模拟下载功能,将下载任务通过后台任务管理进行处理,实现退出应用后任务仍能够执行,直至任务结束。 | eTS | | 元能力 | [BringApp](https://gitee.com/openharmony/applications_app_samples/tree/master/ETSUI/BringApp) | 本示例使用FeatureAbility接口,通过应用的包名与Ability名,拉起系统应用。 | eTS |
| 元能力 | BringApp | 本示例使用FeatureAbility接口,通过应用的包名与Ability名,拉起系统应用。 | eTS | | 媒体 | [VideoPlayer](https://gitee.com/openharmony/applications_app_samples/tree/master/media/VideoPlayer) | 本示例展示了在eTS中VideoPlayer如何播放视频,同时提供一个可供其他应用调用播放视频的Ability。 | eTS |
| 媒体 | VideoPlayer | 本示例展示了在eTS中VideoPlayer如何播放视频,同时提供一个可供其他应用调用播放视频的Ability。 | eTS | | 元能力 | [DistributeCalc](https://gitee.com/openharmony/applications_app_samples/tree/master/Preset/DistributeCalc) | 本示例使用JS分布式能力实现了一个简单的计算器应用,可以进行简单的数值计算,支持远程拉起另一个计算器FA,两个FA进行协同计算。 | eTS |
| 元能力 | DistributeCalc | 本示例使用JS分布式能力实现了一个简单的计算器应用,可以进行简单的数值计算,支持远程拉起另一个计算器FA,两个FA进行协同计算。 | eTS | | Web | [Browser](https://gitee.com/openharmony/applications_app_samples/tree/master/device/Browser) | 本示例运用OpenHarmony系统提供的Stage模型与相关接口展示了一个简易的浏览器。 | eTS |
| 媒体 | JSRecorder | 本示例通过调用媒体相关接口来实现音频录制和播放的功能。 | eTS | | 元能力 | [DeviceUsageStatistics](https://gitee.com/openharmony/applications_app_samples/tree/master/device/DeviceUsageStatistics) | 本示例主要展示了设备使用信息情况。 | eTS |
| Web | Browser | 本示例运用OpenHarmony系统提供的Stage模型与相关接口展示了一个简易的浏览器。 | eTS | | ArkUI | [AdaptiveCapabilities](https://gitee.com/openharmony/applications_app_samples/tree/master/MultiDeviceAppDev/AdaptiveCapabilities) | 本示例展示在eTS中的多设备自适应能力,包括资源限定词、原子布局和响应式布局。 | eTS |
| 元能力 | DeviceUsageStatistics | 本示例主要展示了设备使用信息情况。 | eTS | | ArkUI | [Game2048](https://gitee.com/openharmony/applications_app_samples/tree/master/ETSUI/Game2048) | 2048是一款比较流行的数字游戏,此游戏demo是grid组件基础上进行开发完成的。 | eTS |
| ArkUI | AdaptiveCapabilities | 本示例展示在eTS中的多设备自适应能力,包括资源限定词、原子布局和响应式布局。 | eTS | | 窗口 | [Window](https://gitee.com/openharmony/applications_app_samples/tree/master/Graphics/Window) | 本示例展示了创建新窗口,将应用悬浮在其他界面,及应用分屏等功能 | eTS |
| ArkUI | Game2048 | 2048是一款比较流行的数字游戏,此游戏demo是grid组件基础上进行开发完成的。 | eTS | | 分布式数据管理 | [Preference](https://gitee.com/openharmony/applications_app_samples/tree/master/data/Preferences) | 本示例主要展示了首选项在主题切换方面的功能。 | eTS |
| 窗口 | Window | 本示例展示了创建新窗口,将应用悬浮在其他界面,及应用分屏等功能 | eTS | | ArkUI | [NativeAPI](https://gitee.com/openharmony/applications_app_samples/tree/master/Native/NativeAPI) | 本示例展示了在eTS中如何调用C++的接口以及C++如何回调JS,完成了一个简单的五子棋游戏,在native层完成计算逻辑,eTS完成界面绘制和刷新。 | eTS/C++ |
| 分布式数据管理 | Preference | 本示例主要展示了首选项在主题切换方面的功能。 | eTS | | 全球化 | [International](https://gitee.com/openharmony/applications_app_samples/tree/master/common/International) | 本示例展示了i18n,intl,resourceManager在eTS中的使用,使用相关api实现系统语言和地区设置、时间和时区设置,展示了区域格式化示例。 | eTS |
| ArkUI | NativeAPI | 本示例展示了在eTS中如何调用C++的接口以及C++如何回调JS,完成了一个简单的五子棋游戏,在native层完成计算逻辑,eTS完成界面绘制和刷新。 | eTS/C++ |
| 全球化 | International | 本示例展示了i18n,intl,resourceManager在eTS中的使用,使用相关api实现系统语言和地区设置、时间和时区设置,展示了区域格式化示例。 | eTS | 请访问[Samples](https://gitee.com/openharmony/applications_app_samples)仓了解更多信息。
请访问[Samples](https://gitee.com/openharmony/app_samples)仓了解更多信息。
## 修复缺陷列表 ## 修复缺陷列表
...@@ -228,5 +226,4 @@ _[API差异报告](api-change/v3.2-beta1/readme.md)_ ...@@ -228,5 +226,4 @@ _[API差异报告](api-change/v3.2-beta1/readme.md)_
| ISSUE | 问题描述 | 影响 | 计划解决日期 | | ISSUE | 问题描述 | 影响 | 计划解决日期 |
| ------------------------------------------------------------ | ---------------------------------------------------------- | ------------------------------------------------------------ | ------------ | | ------------------------------------------------------------ | ---------------------------------------------------------- | ------------------------------------------------------------ | ------------ |
| [I4Z3G9](https://gitee.com/openharmony/graphic_graphic_2d/issues/I4Z3G9) | 【RK3568】打开沉浸式主窗口和在主窗口上打开辅助窗口出现闪屏 | 影响开发者体验 | 2022-06-15 | | [I4Z3G9](https://gitee.com/openharmony/graphic_graphic_2d/issues/I4Z3G9) | 【RK3568】打开沉浸式主窗口和在主窗口上打开辅助窗口出现闪屏 | 影响开发者体验 | 2022-06-15 |
| [I59M4Q](https://gitee.com/openharmony/developtools_hdc/issues/I59M4Q) | 使用API 9的hdc_std连接设备小概率断连 | 存在低概率断连(几率小于1/30)。可通过重启IDE或者hdc_std恢复。 | 2022-06-30 | | [I59M4Q](https://gitee.com/openharmony/developtools_hdc/issues/I59M4Q) | 使用API 9的hdc_std连接设备小概率断连 | 存在低概率断连(几率小于1/30)。可通过重启IDE或者hdc_std恢复。 | 2022-06-30 |
| [I54D32](https://gitee.com/openharmony/multimedia_camera_standard/issues/I54D32) | 【RK3568】相机连续多次录像出现黑屏 | 影响开发者体验 | 2022-06-15 | \ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册