未验证 提交 abf41ecf 编写于 作者: O openharmony_ci 提交者: Gitee

!23793 【Monthly分支】23644+23215+23597+22745+22781+23629+23610+22780:文档整改

Merge pull request !23793 from ester.zhou/M-0904
......@@ -101,7 +101,7 @@ class PointVector extends Array<Point> implements AnimatableArithmetic<PointVect
let result = new PointVector([])
const len = Math.min(this.length, rhs.length)
for (let i = 0; i < len; i++) {
result.push(this[i].plus(rhs[i]))
result.push((this as Array<Point>)[i].plus((rhs as Array<Point>)[i]))
}
return result
}
......@@ -109,14 +109,14 @@ class PointVector extends Array<Point> implements AnimatableArithmetic<PointVect
let result = new PointVector([])
const len = Math.min(this.length, rhs.length)
for (let i = 0; i < len; i++) {
result.push(this[i].subtract(rhs[i]))
result.push((this as Array<Point>)[i].subtract((rhs as Array<Point>)[i]))
}
return result
}
multiply(scale: number): PointVector {
let result = new PointVector([])
for (let i = 0; i < this.length; i++) {
result.push(this[i].multiply(scale))
result.push((this as Array<Point>)[i].multiply(scale))
}
return result
}
......@@ -125,14 +125,14 @@ class PointVector extends Array<Point> implements AnimatableArithmetic<PointVect
return false
}
for (let i = 0; i < this.length; i++) {
if (!this[i].equals(rhs[i])) {
if (!(this as Array<Point>)[i].equals((rhs as Array<Point>)[i])) {
return false
}
}
return true
}
get():Array<[x: number, y: number]> {
let result = []
get(): Array<Object[]> {
let result: Array<Object[]> = []
this.forEach(p => result.push([p.x, p.y]))
return result
}
......
......@@ -142,23 +142,24 @@ Since AppStorage is a singleton, its APIs are all static ones. How these APIs wo
```ts
AppStorage.SetOrCreate('PropA', 47);
AppStorage.setOrCreate('PropA', 47);
let storage: LocalStorage = new LocalStorage({ 'PropA': 17 });
let propA: number = AppStorage.Get('PropA') // propA in AppStorage == 47, propA in LocalStorage == 17
var link1: SubscribedAbstractProperty<number> = AppStorage.Link('PropA'); // link1.get() == 47
var link2: SubscribedAbstractProperty<number> = AppStorage.Link('PropA'); // link2.get() == 47
var prop: SubscribedAbstractProperty<number> = AppStorage.Prop('PropA'); // prop.get() = 47
let storage: LocalStorage = new LocalStorage();
storage['PropA'] = 17;
let propA: number | undefined = AppStorage.get('PropA') // propA in AppStorage == 47, propA in LocalStorage == 17
let link1: SubscribedAbstractProperty<number> = AppStorage.link('PropA'); // link1.get() == 47
let link2: SubscribedAbstractProperty<number> = AppStorage.link('PropA'); // link2.get() == 47
let prop: SubscribedAbstractProperty<number> = AppStorage.prop('PropA'); // prop.get() = 47
link1.set(48); // two-way sync: link1.get() == link2.get() == prop.get() == 48
prop.set(1); // one-way sync: prop.get()=1; but link1.get() == link2.get() == 48
link1.set(49); // two-way sync: link1.get() == link2.get() == prop.get() == 49
storage.get('PropA') // == 17
storage.get<number>('PropA') // == 17
storage.set('PropA', 101);
storage.get('PropA') // == 101
storage.get<number>('PropA') // == 101
AppStorage.Get('PropA') // == 49
AppStorage.get<number>('PropA') // == 49
link1.get() // == 49
link2.get() // == 49
prop.get() // == 49
......@@ -171,8 +172,9 @@ prop.get() // == 49
```ts
AppStorage.SetOrCreate('PropA', 47);
let storage = new LocalStorage({ 'PropA': 48 });
AppStorage.setOrCreate('PropA', 47);
let storage = new LocalStorage();
storage['PropA'] = 48;
@Entry(storage)
@Component
......@@ -196,7 +198,7 @@ struct CompA {
Compared with the common mechanism for event notification, the two-way synchronization mechanism of @StorageLink and AppStorage is far less cost efficient and therefore not recommended. This is because AppStorage stores UI-related data, and its changes will cause costly UI refresh.
In the following example, any tap event in the **TapImage** component will trigger a change of the **tapIndex** attribute. As @StorageLink establishes a two-way data synchronization with AppStorage, the local change is synchronized to AppStorage. As a result, all visible custom components owning the **tapIndex** attribute bound to AppStorage are notified to refresh the UI.
In the following example, any tap event in the **TapImage** component will trigger a change of the **tapIndex** attribute. As @StorageLink establishes a two-way data synchronization with AppStorage, the local change is synchronized to AppStorage. As a result, all custom components owning the **tapIndex** attribute bound to AppStorage are notified to refresh the UI.
```ts
......@@ -242,8 +244,13 @@ struct Gallery2 {
export struct TapImage {
@StorageLink('tapIndex') @Watch('onTapIndexChange') tapIndex: number = -1;
@State tapColor: Color = Color.Black;
private index: number;
private uri: Resource;
private index: number = 0;
private uri: Resource = {
id: 0,
type: 0,
moduleName: "",
bundleName: ""
};
// Check whether the component is selected.
onTapIndexChange() {
......@@ -313,9 +320,9 @@ struct Gallery2 {
if (this.preIndex === item.id) {
return
}
var innerEvent = { eventId: item.id }
let innerEvent: emitter.InnerEvent = { eventId: item.id }
// Selected: from black to red
var eventData = {
let eventData: emitter.EventData = {
data: {
"colorTag": 1
}
......@@ -324,9 +331,9 @@ struct Gallery2 {
if (this.preIndex != -1) {
console.info(`preIndex: ${this.preIndex}, index: ${item.id}, black`)
var innerEvent = { eventId: this.preIndex }
let innerEvent: emitter.InnerEvent = { eventId: this.preIndex }
// Deselected: from red to black
var eventData = {
let eventData: emitter.EventData = {
data: {
"colorTag": 0
}
......@@ -335,7 +342,6 @@ struct Gallery2 {
}
this.preIndex = item.id
})
}, (item: ViewData) => JSON.stringify(item))
}.columnsTemplate('1fr 1fr')
}
......@@ -346,17 +352,26 @@ struct Gallery2 {
@Component
export struct TapImage {
@State tapColor: Color = Color.Black;
private index: number;
private uri: Resource;
private index: number = 0;
private uri: Resource = {
id: 0,
type: 0,
moduleName: "",
bundleName: ""
};
onTapIndexChange(colorTag: emitter.EventData) {
this.tapColor = colorTag.data.colorTag ? Color.Red : Color.Black
if (colorTag.data != null) {
this.tapColor = colorTag.data.colorTag ? Color.Red : Color.Black
}
}
aboutToAppear() {
// Define the event ID.
var innerEvent = { eventId: this.index }
emitter.on(innerEvent, this.onTapIndexChange.bind(this))
let innerEvent: emitter.InnerEvent = { eventId: this.index }
emitter.on(innerEvent, data => {
this.onTapIndexChange(data)
})
}
build() {
......@@ -414,8 +429,13 @@ struct Gallery2 {
export struct TapImage {
@StorageLink('tapIndex') tapIndex: number = -1;
@State tapColor: Color = Color.Black;
private index: number;
private uri: Resource;
private index: number = 0;
private uri: Resource = {
id: 0,
type: 0,
moduleName: "",
bundleName: ""
};
build() {
Column() {
......@@ -440,9 +460,9 @@ export struct TapImage {
When using AppStorage together with [PersistentStorage](arkts-persiststorage.md) and [Environment](arkts-environment.md), pay attention to the following:
- A call to **PersistentStorage.PersistProp()** after creating the attribute in AppStorage uses the type and value in AppStorage and overwrites any attribute with the same name in PersistentStorage. In light of this, the opposite order of calls is recommended. For an example of incorrect usage, see [Accessing Attribute in AppStorage Before PersistentStorage](arkts-persiststorage.md#accessing-attribute-in-appstorage-before-persistentstorage).
- A call to **PersistentStorage.persistProp()** after creating the attribute in AppStorage uses the type and value in AppStorage and overwrites any attribute with the same name in PersistentStorage. In light of this, the opposite order of calls is recommended. For an example of incorrect usage, see [Accessing Attribute in AppStorage Before PersistentStorage](arkts-persiststorage.md#accessing-attribute-in-appstorage-before-persistentstorage).
- A call to **Environment.EnvProp()** after creating the attribute in AppStorage will fail. This is because AppStorage already has an attribute with the same name, and the environment variable will not be written into AppStorage. Therefore, you are advised not to use the preset environment variable name in AppStorage.
- A call to **Environment.envProp()** after creating the attribute in AppStorage will fail. This is because AppStorage already has an attribute with the same name, and the environment variable will not be written into AppStorage. Therefore, you are advised not to use the preset environment variable name in AppStorage.
- Changes to the variables decorated by state decorators will cause UI re-render. If the changes are for message communication, rather than for UI re-render, the emitter mode is recommended. For the example, see [Unrecommended: Using @StorageLink to Implement Event Notification](#unrecommended-using-storagelink-to-implement-event-notification).
<!--no_check-->
......@@ -77,13 +77,22 @@ In by-reference parameter passing, the passed parameters can be state variables,
```ts
ABuilder( $$ : { paramA1: string, paramB1 : string } );
class ABuilderParam {
paramA1: string = ''
paramB1: string = ''
}
ABuilder($$ : ABuilderParam);
```
```ts
@Builder function ABuilder($$: { paramA1: string }) {
class ABuilderParam {
paramA1: string = ''
}
@Builder function ABuilder($$: ABuilderParam) {
Row() {
Text(`UseStateVarByReference: ${$$.paramA1} `)
}
......
......@@ -34,70 +34,80 @@ An \@BuildParam decorated method can be initialized only by an \@Builder functio
- Initialization from the parent component
```ts
@Component
struct Child {
@BuilderParam aBuilder0: () => void;
@Component
struct Child {
@Builder componentBuilder() {
Text(`Parent builder `)
}
build() {
Column() {
this.aBuilder0()
}
@BuilderParam aBuilder0: () => void = this.componentBuilder;
build() {
Column() {
this.aBuilder0()
}
}
}
@Entry
@Component
struct Parent {
@Builder componentBuilder() {
Text(`Parent builder `)
}
@Entry
@Component
struct Parent {
@Builder componentBuilder() {
Text(`Parent builder `)
}
build() {
Column() {
Child({ aBuilder0: this.componentBuilder })
}
build() {
Column() {
Child({ aBuilder0: this.componentBuilder })
}
}
}
```
- **this** in the function body points to the correct object.
In the following example, when the **Parent** component calls **this.componentBuilder()**, **this.label** points to the owning component, that is, **Parent**. With **\@BuilderParam aBuilder0** passed to the **Child** component from **\@Builder componentBuilder()**, when the **Child** component calls **this.aBuilder0()**, **this.label** points to the label of the **Child** component, that is, **Child**.
In the following example, when the **Parent** component calls **this.componentBuilder()**, **this.label** points to the owning component, that is, **Parent**. With **\@BuilderParam aBuilder0** passed to the **Child** component from **\@Builder componentBuilder()**, when the **Child** component calls **this.aBuilder0()**, **this.label** points to the label of the child component, that is, **Child**. For **\@BuilderParam aBuilder1**, when **this.componentBuilder** is passed to **aBuilder1**, **bind** is called to bind **this**. Therefore, **this.label** points to the label of the parent component.
> **NOTE**
>
> Exercise caution when using **bind** to change the context of function invoking, which may cause **this** to point to an incorrect object.
```ts
@Component
struct Child {
label: string = `Child`
@BuilderParam aBuilder0: () => void;
@Component
struct Child {
@Builder componentBuilder() {
Text(`Child builder `)
}
build() {
Column() {
this.aBuilder0()
}
label: string = `Child`
@BuilderParam aBuilder0: () => void = this.componentBuilder;
@BuilderParam aBuilder1: () => void = this.componentBuilder;
build() {
Column() {
this.aBuilder0()
this.aBuilder1()
}
}
}
@Entry
@Component
struct Parent {
label: string = `Parent`
@Entry
@Component
struct Parent {
label: string = `Parent`
@Builder componentBuilder() {
Text(`${this.label}`)
}
@Builder componentBuilder() {
Text(`${this.label}`)
}
build() {
Column() {
this.componentBuilder()
Child({ aBuilder0: this.componentBuilder })
}
build() {
Column() {
this.componentBuilder()
Child({ aBuilder0: this.componentBuilder, aBuilder1: this.componentBuilder })
}
}
}
```
......@@ -110,7 +120,11 @@ An \@BuilderParam decorated method can be a method with or without parameters. W
```ts
@Builder function GlobalBuilder1($$ : {label: string }) {
class GlobalBuilderParam {
label: string = ""
}
@Builder function GlobalBuilder1($$ : GlobalBuilderParam) {
Text($$.label)
.width(400)
.height(50)
......@@ -119,11 +133,15 @@ An \@BuilderParam decorated method can be a method with or without parameters. W
@Component
struct Child {
@Builder componentBuilder() {
Text(`Child builder `)
}
label: string = 'Child'
// Without parameters. The pointed componentBuilder is also without parameters.
@BuilderParam aBuilder0: () => void;
@BuilderParam aBuilder0: () => void = this.componentBuilder;
// With parameters. The pointed GlobalBuilder1 is also with parameters.
@BuilderParam aBuilder1: ($$ : { label : string}) => void;
@BuilderParam aBuilder1: ($$ : GlobalBuilderParam) => void = this.componentBuilder;
build() {
Column() {
......@@ -157,6 +175,7 @@ struct Parent {
In a custom component, the \@BuilderParam decorated attribute can be initialized using a trailing closure. During initialization, the component name is followed by a pair of braces ({}) to form a trailing closure.
> **NOTE**
>
> In this scenario, the custom component has one and only one \@BuilderParam decorated attribute.
You can pass the content in the trailing closure to \@BuilderParam as an \@Builder decorated method. Example:
......@@ -164,10 +183,17 @@ You can pass the content in the trailing closure to \@BuilderParam as an \@Build
```ts
// xxx.ets
class CustomContainerParam {
header: string = '';
}
@Component
struct CustomContainer {
@Prop header: string;
@BuilderParam closer: () => void
@Builder componentCloser() {
Text(`Custom closer `)
}
@Prop header: string = '';
@BuilderParam closer: () => void = this.componentCloser;
build() {
Column() {
......@@ -191,12 +217,15 @@ struct CustomContainer {
@Component
struct CustomContainerUser {
@State text: string = 'header';
param: CustomContainerParam = {
header: this.text
};
build() {
Column() {
// Create the CustomContainer component. During initialization, append a pair of braces ({}) to the component name to form a trailing closure.
// Used as the parameter passed to CustomContainer @BuilderParam closer: () => void.
CustomContainer({ header: this.text }) {
CustomContainer(this.param) {
Column() {
specificParam('testA', 'testB')
}.backgroundColor(Color.Yellow)
......
......@@ -42,15 +42,23 @@ Multiple **HelloComponent** instances can be created in the **build()** function
```ts
class HelloComponentParam {
message: string = ""
}
@Entry
@Component
struct ParentComponent {
param: HelloComponentParam = {
message: 'Hello, World!'
}
build() {
Column() {
Text('ArkUI message')
HelloComponent({ message: 'Hello, World!' });
HelloComponent(param);
Divider()
HelloComponent ({ message: 'Hello!' });
HelloComponent(param);
}
}
}
......@@ -131,14 +139,14 @@ To fully understand the preceding example, a knowledge of the following concepts
```
- \@Recycle: A custom component decorated with \@Recycle can be reused.
- \@Reusable: Custom components decorated by \@Reusable can be reused.
> **NOTE**
>
> Since API version 10, this decorator is supported in ArkTS widgets.
```ts
@Recycle
@Reusable
@Component
struct MyComponent {
}
......
......@@ -12,11 +12,11 @@ Environment is a singleton object created by the ArkUI framework at application
### Accessing Environment Parameters from UI
- Use **Environment.EnvProp** to save the environment variables of the device to AppStorage.
- Use **Environment.envProp** to save the environment variables of the device to AppStorage.
```ts
// Save languageCode to AppStorage. The default value is en.
Environment.EnvProp('languageCode', 'en');
Environment.envProp('languageCode', 'en');
```
- Decorate the variables with \@StorageProp to link them with components.
......@@ -34,8 +34,8 @@ The chain of updates is as follows: Environment > AppStorage > Component.
```ts
// Save the device language code to AppStorage.
Environment.EnvProp('languageCode', 'en');
let enable = AppStorage.Get('languageCode');
Environment.envProp('languageCode', 'en');
let enable: undefined = AppStorage.get<undefined>('languageCode');
@Entry
@Component
......@@ -59,9 +59,9 @@ struct Index {
```ts
// Use Environment.EnvProp to save the device language code to AppStorage.
Environment.EnvProp('languageCode', 'en');
Environment.envProp('languageCode', 'en');
// Obtain the one-way bound languageCode variable from AppStorage.
const lang: SubscribedAbstractProperty<string> = AppStorage.Prop('languageCode');
const lang: SubscribedAbstractProperty<string> = AppStorage.prop('languageCode');
if (lang.get() === 'en') {
console.info('Hi');
......@@ -89,7 +89,7 @@ export default class EntryAbility extends UIAbility {
window.then(window => {
let uicontext = window.getUIContext()
uicontext.runScopedTask(() => {
Environment.EnvProp('languageCode', 'en');
Environment.envProp('languageCode', 'en');
})
})
}
......
......@@ -82,7 +82,7 @@ Apart from\@Styles used to extend styles, AkrUI also provides \@Extend, which al
build() {
Row({ space: 10 }) {
Text(`${this.label}`)
.makeMeClick(this.onClickHandler.bind(this))
.makeMeClick(this.onClickHandler)
}
}
}
......
......@@ -227,10 +227,10 @@ struct Parent {
Column() {
Child({ items: $arr })
ForEach(this.arr,
item => {
(item: void) => {
Text(`${item}`)
},
item => item.toString()
(item: ForEachInterface) => item.toString()
)
}
}
......
......@@ -167,11 +167,12 @@ By decorating a variable with \@LocalStorageProp(key), a one-way data synchroniz
```ts
let storage = new LocalStorage({ 'PropA': 47 }); // Create a new instance and initialize it with the given object.
let propA = storage.get('PropA') // propA == 47
let link1 = storage.link('PropA'); // link1.get() == 47
let link2 = storage.link('PropA'); // link2.get() == 47
let prop = storage.prop('PropA'); // prop.get() = 47
let storage = new LocalStorage(); // Create a new instance and initialize it with the given object.
storage['PropA'] = 47
let propA = storage.get<number>('PropA') // propA == 47
let link1 = storage.link<number>('PropA'); // link1.get() == 47
let link2 = storage.link<number>('PropA'); // link2.get() == 47
let prop = storage.prop<number>('PropA'); // prop.get() = 47
link1.set(48); // two-way sync: link1.get() == link2.get() == prop.get() == 48
prop.set(1); // one-way sync: prop.get()=1; but link1.get() == link2.get() == 48
link1.set(49); // two-way sync: link1.get() == link2.get() == prop.get() == 49
......@@ -191,36 +192,37 @@ This example uses \@LocalStorage as an example to show how to:
- Use \@LocalStorageLink to create a two-way data synchronization with the given attribute in LocalStorage.
```ts
// Create a new instance and initialize it with the given object.
let storage = new LocalStorage({ 'PropA': 47 });
@Component
struct Child {
// @LocalStorageLink creates a two-way data synchronization with the ProA attribute in LocalStorage.
@LocalStorageLink('PropA') storLink2: number = 1;
build() {
Button(`Child from LocalStorage ${this.storLink2}`)
// The changes will be synchronized to ProA in LocalStorage and with Parent.storLink1.
.onClick(() => this.storLink2 += 1)
}
// Create a new instance and initialize it with the given object.
let storage = new LocalStorage();
storage['PropA'] = 47;
@Component
struct Child {
// @LocalStorageLink creates a two-way data synchronization with the PropA attribute in LocalStorage.
@LocalStorageLink('PropA') storLink2: number = 1;
build() {
Button(`Child from LocalStorage ${this.storLink2}`)
// The changes will be synchronized to PropA in LocalStorage and with Parent.storLink1.
.onClick(() => this.storLink2 += 1)
}
// Make LocalStorage accessible from the @Component decorated component.
@Entry(storage)
@Component
struct CompA {
// @LocalStorageLink creates a two-way data synchronization with the ProA attribute in LocalStorage.
@LocalStorageLink('PropA') storLink1: number = 1;
build() {
Column({ space: 15 }) {
Button(`Parent from LocalStorage ${this.storLink1}`) // initial value from LocalStorage will be 47, because 'PropA' initialized already
.onClick(() => this.storLink1 += 1)
// The @Component decorated child component automatically obtains access to the CompA LocalStorage instance.
Child()
}
}
// Make LocalStorage accessible from the @Component decorated component.
@Entry(storage)
@Component
struct CompA {
// @LocalStorageLink creates a two-way data synchronization with the PropA attribute in LocalStorage.
@LocalStorageLink('PropA') storLink1: number = 1;
build() {
Column({ space: 15 }) {
Button(`Parent from LocalStorage ${this.storLink1}`) // initial value from LocalStorage will be 47, because 'PropA' initialized already
.onClick(() => this.storLink1 += 1)
// The @Component decorated child component automatically obtains access to the CompA LocalStorage instance.
Child()
}
}
}
```
......@@ -233,37 +235,39 @@ In this example, the **CompA** and **Child** components create local data that i
- In the **Child** component, the value of **storProp2** bound to **Text** is still 47.
```ts
// Create a new instance and initialize it with the given object.
let storage = new LocalStorage({ 'PropA': 47 });
// Make LocalStorage accessible from the @Component decorated component.
@Entry(storage)
@Component
struct CompA {
// @LocalStorageProp creates a one-way data synchronization with the ProA attribute in LocalStorage.
@LocalStorageProp('PropA') storProp1: number = 1;
build() {
Column({ space: 15 }) {
// The initial value is 47. After the button is clicked, the value is incremented by 1. The change takes effect only in storProp1 in the current component and is not synchronized to LocalStorage.
Button(`Parent from LocalStorage ${this.storProp1}`)
.onClick(() => this.storProp1 += 1)
Child()
}
// Create a new instance and initialize it with the given object.
let storage = new LocalStorage();
storage['PropA'] = 47;
// Make LocalStorage accessible from the @Component decorated component.
@Entry(storage)
@Component
struct CompA {
// @LocalStorageProp creates a one-way data synchronization with the PropA attribute in LocalStorage.
@LocalStorageProp('PropA') storProp1: number = 1;
build() {
Column({ space: 15 }) {
// The initial value is 47. After the button is clicked, the value is incremented by 1. The change takes effect only in storProp1 in the current component and is not synchronized to LocalStorage.
Button(`Parent from LocalStorage ${this.storProp1}`)
.onClick(() => this.storProp1 += 1)
Child()
}
}
}
@Component
struct Child {
// @LocalStorageProp creates a one-way data synchronization with the ProA attribute in LocalStorage.
@LocalStorageProp('PropA') storProp2: number = 2;
@Component
struct Child {
// @LocalStorageProp creates a one-way data synchronization with the PropA attribute in LocalStorage.
@LocalStorageProp('PropA') storProp2: number = 2;
build() {
Column({ space: 15 }) {
// When CompA changes, the current storProp2 does not change, and 47 is displayed.
Text(`Parent from LocalStorage ${this.storProp2}`)
}
build() {
Column({ space: 15 }) {
// When CompA changes, the current storProp2 does not change, and 47 is displayed.
Text(`Parent from LocalStorage ${this.storProp2}`)
}
}
}
```
......@@ -274,9 +278,10 @@ This example shows how to create a two-way data synchronization between an \@Loc
```ts
// Create a LocalStorage instance.
let storage = new LocalStorage({ 'PropA': 47 });
let storage = new LocalStorage();
storage['PropA'] = 47;
// Invoke the link9+ API to create a two-way data synchronization with PropA. linkToPropA is a global variable.
let linkToPropA = storage.link('PropA');
let linkToPropA = storage.link<number>('PropA');
@Entry(storage)
@Component
......@@ -317,63 +322,71 @@ Changes in the **Child** custom component:
1. The update of **playCountLink** is synchronized to LocalStorage, and the parent and sibling child custom components are re-rendered accordingly.
```ts
let storage = new LocalStorage({ countStorage: 1 });
@Component
struct Child {
// Name the child component instance.
label: string = 'no name';
// Two-way synchronization with countStorage in LocalStorage.
@LocalStorageLink('countStorage') playCountLink: number = 0;
build() {
Row() {
Text(this.label)
.width(50).height(60).fontSize(12)
Text(`playCountLink ${this.playCountLink}: inc by 1`)
.onClick(() => {
this.playCountLink += 1;
})
.width(200).height(60).fontSize(12)
}.width(300).height(60)
}
}
@Entry(storage)
@Component
struct Parent {
@LocalStorageLink('countStorage') playCount: number = 0;
build() {
Column() {
Row() {
Text('Parent')
.width(50).height(60).fontSize(12)
Text(`playCount ${this.playCount} dec by 1`)
.onClick(() => {
this.playCount -= 1;
})
.width(250).height(60).fontSize(12)
}.width(300).height(60)
Row() {
Text('LocalStorage')
.width(50).height(60).fontSize(12)
Text(`countStorage ${this.playCount} incr by 1`)
.onClick(() => {
storage.set<number>('countStorage', 1 + storage.get<number>('countStorage'));
})
.width(250).height(60).fontSize(12)
}.width(300).height(60)
Child({ label: 'ChildA' })
Child({ label: 'ChildB' })
Text(`playCount in LocalStorage for debug ${storage.get<number>('countStorage')}`)
.width(300).height(60).fontSize(12)
}
}
}
class Data {
countStorage: number = 0;
}
let data: Data = { countStorage: 1 }
let storage = new LocalStorage(data);
@Component
struct Child {
// Name the child component instance.
label: string = 'no name';
// Two-way synchronization with countStorage in LocalStorage.
@LocalStorageLink('countStorage') playCountLink: number = 0;
build() {
Row() {
Text(this.label)
.width(50).height(60).fontSize(12)
Text(`playCountLink ${this.playCountLink}: inc by 1`)
.onClick(() => {
this.playCountLink += 1;
})
.width(200).height(60).fontSize(12)
}.width(300).height(60)
}
}
@Entry(storage)
@Component
struct Parent {
@LocalStorageLink('countStorage') playCount: number = 0;
build() {
Column() {
Row() {
Text('Parent')
.width(50).height(60).fontSize(12)
Text(`playCount ${this.playCount} dec by 1`)
.onClick(() => {
this.playCount -= 1;
})
.width(250).height(60).fontSize(12)
}.width(300).height(60)
Row() {
Text('LocalStorage')
.width(50).height(60).fontSize(12)
Text(`countStorage ${this.playCount} incr by 1`)
.onClick(() => {
let countStorage: number | undefined = storage.get<number>('countStorage');
if (countStorage != undefined){
countStorage += 1;
storage.set<number>('countStorage', countStorage);
}
})
.width(250).height(60).fontSize(12)
}.width(300).height(60)
Child({ label: 'ChildA' })
Child({ label: 'ChildB' })
Text(`playCount in LocalStorage for debug ${storage.get<number>('countStorage')}`)
.width(300).height(60).fontSize(12)
}
}
}
```
......@@ -388,22 +401,21 @@ import UIAbility from '@ohos.app.ability.UIAbility';
import window from '@ohos.window';
export default class EntryAbility extends UIAbility {
storage: LocalStorage = new LocalStorage({
'PropA': 47
});
storage: LocalStorage = new LocalStorage();
onWindowStageCreate(windowStage: window.WindowStage) {
this.storage['PropA'] = 47;
windowStage.loadContent('pages/Index', this.storage);
}
}
```
On the page, call the **GetShared** API to obtain the LocalStorage instance shared through **loadContent**.
On the page, call the **getShared** API to obtain the LocalStorage instance shared through **loadContent**.
```ts
// Use the GetShared API to obtain the LocalStorage instance shared by stage.
let storage = LocalStorage.GetShared()
// Use the getShared API to obtain the LocalStorage instance shared by stage.
let storage = LocalStorage.getShared()
@Entry(storage)
@Component
......
......@@ -35,7 +35,7 @@ Using \@Observed to decorate a class changes the original prototype chain of the
| ----------------- | ---------------------------------------- |
| Decorator parameters | None. |
| Synchronization type | No synchronization with the parent component. |
| Allowed variable types | Objects of \@Observed decorated classes. The type must be specified.<br>Simple type variables are not supported. Use [\@Prop](arkts-prop.md) instead.<br>An \@ObjectLink decorated variable accepts changes to its attributes, but assignment is not allowed. In other words, an \@ObjectLink decorated variable is read-only and cannot be changed.|
| Allowed variable types | Objects of \@Observed decorated classes. The type must be specified.<br>Simple type variables are not supported. Use [\@Prop](arkts-prop.md) instead.<br>Instances of classes that inherit **Date** or **Array** are supported. For details, see [Observed Changes](#observed-changes).<br>An \@ObjectLink decorated variable accepts changes to its attributes, but assignment is not allowed. In other words, an \@ObjectLink decorated variable is read-only and cannot be changed.|
| Initial value for the decorated variable | Not allowed. |
Example of a read-only \@ObjectLink decorated variable:
......@@ -121,6 +121,67 @@ this.b.a.c = 5
- Replacement of array items for the data source of an array and changes of class attributes for the data source of a class. For details, see [Object Array](#object-array).
For an instance of the class that inherits **Date**, the value assignment of **Date** can be observed. In addition, you can call the following APIs to update the attributes of **Date**: setFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSeconds, setUTCMilliseconds.
```ts
@Observed
class DateClass extends Date {
constructor(args: number | string) {
super(args)
}
}
@Observed
class ClassB {
public a: DateClass;
constructor(a: DateClass) {
this.a = a;
}
}
@Component
struct ViewA {
label: string = 'date';
@ObjectLink a: DateClass;
build() {
Column() {
Button(`child increase the day by 1`)
.onClick(() => {
this.a.setDate(this.a.getDate() + 1);
})
DatePicker({
start: new Date('1970-1-1'),
end: new Date('2100-1-1'),
selected: this.a
})
}
}
}
@Entry
@Component
struct ViewB {
@State b: ClassB = new ClassB(new DateClass('2023-1-1'));
build() {
Column() {
ViewA({ label: 'date', a: this.b.a })
Button(`parent update the new date`)
.onClick(() => {
this.b.a = new DateClass('2023-07-07');
})
Button(`ViewB: this.b = new ClassB(new DateClass('2023-08-20'))`)
.onClick(() => {
this.b = new ClassB(new DateClass('2023-08-20'));
})
}
}
}
```
### Framework Behavior
......@@ -282,10 +343,10 @@ struct ViewB {
build() {
Column() {
ForEach(this.arrA,
(item) => {
(item: ClassA) => {
ViewA({ label: `#${item.id}`, a: item })
},
(item) => item.id.toString()
(item: ClassA): string => item.id.toString()
)
// Initialize the @ObjectLink decorated variable using the array item in the @State decorated array, which is an instance of ClassA decorated by @Observed.
ViewA({ label: `ViewA this.arrA[first]`, a: this.arrA[0] })
......@@ -358,11 +419,11 @@ struct ItemPage {
.width(100).height(100)
ForEach(this.itemArr,
item => {
(item: string | Resource) => {
Text(item)
.width(100).height(100)
},
item => item
(item: string) => item
)
}
}
......@@ -378,14 +439,14 @@ struct IndexPage {
ItemPage({ itemArr: this.arr[0] })
ItemPage({ itemArr: this.arr[1] })
ItemPage({ itemArr: this.arr[2] })
Divider()
ForEach(this.arr,
itemArr => {
(itemArr: StringArray) => {
ItemPage({ itemArr: itemArr })
},
itemArr => itemArr[0]
(itemArr: string) => itemArr[0]
)
Divider()
......@@ -393,7 +454,7 @@ struct IndexPage {
Button('update')
.onClick(() => {
console.error('Update all items in arr');
if (this.arr[0][0] !== undefined) {
if ((this.arr[0] as Array<String>)[0] !== undefined) {
// We should have a real ID to use with ForEach, but we do no.
// Therefore, we need to make sure the pushed strings are unique.
this.arr[0].push(`${this.arr[0].slice(-1).pop()}${this.arr[0].slice(-1).pop()}`);
......
......@@ -34,13 +34,13 @@ PersistentStorage can be called to persist data only when the [UIContext](../ref
1. Initialize the PersistentStorage instance.
```ts
PersistentStorage.PersistProp('aProp', 47);
PersistentStorage.persistProp('aProp', 47);
```
2. Obtain the corresponding attribute from AppStorage.
```ts
AppStorage.Get('aProp'); // returns 47
AppStorage.get<number>('aProp'); // returns 47
```
Alternatively, apply local definition within the component:
......@@ -54,7 +54,7 @@ The complete code is as follows:
```ts
PersistentStorage.PersistProp('aProp', 47);
PersistentStorage.persistProp('aProp', 47);
@Entry
@Component
......@@ -78,7 +78,7 @@ struct Index {
```
- First running after fresh application installation:
1. **PersistProp** is called to initialize PersistentStorage. A search for the **aProp** attribute on the PersistentStorage disk returns no result, because the application has just been installed.
1. **persistProp** is called to initialize PersistentStorage. A search for the **aProp** attribute on the PersistentStorage disk returns no result, because the application has just been installed.
2. A search for the attribute **aProp** in AppStorage still returns no result.
3. Create the **aProp** attribute of the number type in AppStorge and initialize it with the value 47.
4. PersistentStorage writes the **aProp** attribute and its value **47** to the disk. The value of **aProp** in AppStorage and its subsequent changes are persisted.
......@@ -95,21 +95,21 @@ struct Index {
4. Because the attribute corresponding to **aProp** has been persisted, the change of the **aProp** attribute in AppStorage triggers PersistentStorage to write the attribute and its new value to the device disk.
- Subsequent application running:
1. **PersistentStorage.PersistProp('aProp', 47)** is called. A search for the **aProp** attribute on the PersistentStorage disk succeeds.
1. **PersistentStorage.persistProp('aProp', 47)** is called. A search for the **aProp** attribute on the PersistentStorage disk succeeds.
2. The attribute is added to AppStorage with the value found on the PersistentStorage disk.
3. In the **\<Index>** component, the value of the @StorageLink decorated **aProp** attribute is the value written by PersistentStorage to AppStorage, that is, the value stored when the application was closed last time.
### Accessing Attribute in AppStorage Before PersistentStorage
This example is an incorrect use. It is incorrect to use the API to access the attributes in AppStorage before calling **PersistentStorage.PersistProp** or **PersistProps**, because such a call sequence will result in loss of the attribute values used in the previous application run:
This example is an incorrect use. It is incorrect to use the API to access the attributes in AppStorage before calling **PersistentStorage.persistProp** or **persistProps**, because such a call sequence will result in loss of the attribute values used in the previous application run:
```ts
let aProp = AppStorage.SetOrCreate('aProp', 47);
PersistentStorage.PersistProp('aProp', 48);
let aProp = AppStorage.setOrCreate('aProp', 47);
PersistentStorage.persistProp('aProp', 48);
```
**AppStorage.SetOrCreate('aProp', 47)**: The **aProp** attribute is created in AppStorage, its type is number, and its value is set to the specified default value **47**. **aProp** is a persisted attribute. Therefore, it is written back to the PersistentStorage disk, and the value stored in the PersistentStorage disk from the previous run is lost.
**AppStorage.setOrCreate('aProp', 47)**: The **aProp** attribute is created in AppStorage, its type is number, and its value is set to the specified default value **47**. **aProp** is a persisted attribute. Therefore, it is written back to the PersistentStorage disk, and the value stored in the PersistentStorage disk from the previous run is lost.
**PersistentStorage.PersistProp('aProp', 48)**: An attribute with same name **aProp** is available in PersistentStorage.
**PersistentStorage.persistProp('aProp', 48)**: An attribute with same name **aProp** is available in PersistentStorage.
......@@ -5,61 +5,58 @@ A Harmony Archive (HAR) is a static shared package that can contain code, C++ li
You can [create a HAR module in DevEco Studio](https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/creating_har_api9-0000001518082393-V3#section143510369612).
To better protect your source code, enable obfuscation for the HAR module so that DevEco Studio compiles, obfuscates, and compresses code during HAR building.
> **NOTE**
>
> Obfuscation is only available for ArkTS projects in the stage model.
### Obfuscation in API Version 9
Whether obfuscation is enabled by default varies by version.
In API version 9, obfuscation is disabled by default, and can be enabled by setting **artifactType** to **obfuscation** in the **build-profile.json5** file of the HAR module. The configuration is as follows:
- In API version 9, obfuscation is disabled by default, and can be enabled by setting **artifactType** to **obfuscation** in the **build-profile.json5** file of the HAR module. The configuration is as follows:
```json
{
"apiType": "stageMode",
"buildOption": {
"artifactType": "obfuscation"
```json
{
"apiType": "stageMode",
"buildOption": {
"artifactType": "obfuscation"
}
}
}
```
The value options of **artifactType** are as follows, with the default value being **original**:
- **original**: Code is not obfuscated.
- **obfuscation**: Code is obfuscated using Uglify.
```
The value options of **artifactType** are as follows, with the default value being **original**:
- **original**: Code is not obfuscated.
- **obfuscation**: Code is obfuscated using Uglify.
### Obfuscation in API Version 10
- In API version 10, obfuscation is enabled by default, and can be set through the **enable** field under **ruleOptions** in the **build-profile.json5** file of the HAR module. The configuration is as follows:
In API version 10, obfuscation is enabled by default, and can be set through the **enable** field under **ruleOptions** in the **build-profile.json5** file of the HAR module. The configuration is as follows:
```json
{
"apiType": "stageMode",
"buildOption": {
},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": true,
"files": [
"./obfuscation-rules.txt"
```json
{
"apiType": "stageMode",
"buildOption": {
},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": true,
"files": [
"./obfuscation-rules.txt"
]
},
"consumerFiles": [
"./consumer-rules.txt"
]
},
"consumerFiles": [
"./consumer-rules.txt"
]
}
}
},
],
"targets": [
{
"name": "default"
}
},
],
"targets": [
{
"name": "default"
}
]
}
```
]
}
```
### Adaptation Guide
The **artifactType** field is forward compatible, and the original function is not affected. Yet, it is deprecated since API version 10, and you are advised to use the substitute as soon as possible.
......@@ -108,7 +105,7 @@ Use **export** to export TS classes and methods. Multiple TS classes and methods
```js
// library/src/main/ts/test.ets
export class Log {
static info(msg) {
static info(msg: string) {
console.info(msg);
}
}
......
......@@ -48,7 +48,7 @@ In addition to the [universal attributes](ts-universal-attributes-size.md), the
| vertical | boolean | Whether vertical swiping is used.<br>Default value: **false** |
| itemSpace | number \| string | Space between child components.<br>Default value: **0**<br>**NOTE**<br>This parameter cannot be set in percentage.|
| displayMode | SwiperDisplayMode | Mode in which elements are displayed along the main axis. This attribute takes effect only when **displayCount** is not set.<br>Default value: **SwiperDisplayMode.Stretch**|
| cachedCount<sup>8+</sup> | number | Number of child components to be cached.<br>Default value: **1**<br>**NOTE**<br>This attribute applies only when the **\<Swiper>** component uses [LazyForEach](../../quick-start/arkts-rendering-control-lazyforeach.md).|
| cachedCount<sup>8+</sup> | number | Number of child components to be cached.<br>Default value: **1**|
| disableSwipe<sup>8+</sup> | boolean | Whether to disable the swipe feature.<br>Default value: **false** |
| curve<sup>8+</sup> | [Curve](ts-appendix-enums.md#curve) \| string | Animation curve. The ease-in/ease-out curve is used by default. For details about common curves, see [Curve](ts-appendix-enums.md#curve). You can also create custom curves (interpolation curve objects) by using the API provided by the [interpolation calculation](../apis/js-apis-curve.md) module.<br>Default value: **Curve.Linear**|
| indicatorStyle<sup>(deprecated)</sup> | {<br>left?: [Length](ts-types.md#length),<br>top?: [Length](ts-types.md#length),<br>right?: [Length](ts-types.md#length),<br>bottom?: [Length](ts-types.md#length),<br>size?: [Length](ts-types.md#length),<br>mask?: boolean,<br>color?: [ResourceColor](ts-types.md),<br>selectedColor?: [ResourceColor](ts-types.md)<br>} | Style of the navigation point indicator.<br>\- **left**: distance between the navigation point indicator and the left edge of the **\<Swiper>** component.<br>\- **top**: distance between the navigation point indicator and the top edge of the **\<Swiper>** component.<br>\- **right**: distance between the navigation point indicator and the right edge of the **\<Swiper>** component.<br>\- **bottom**: distance between the navigation point indicator and the bottom edge of the **\<Swiper>** component.<br>\- **size**: diameter of the navigation point indicator. The value cannot be in percentage. Default value: **6vp**<br>\- **mask**: whether to enable the mask for the navigation point indicator.<br>\- **color**: color of the navigation point indicator.<br>\- **selectedColor**: color of the selected navigation dot.<br>This API is supported since API version 8 and is deprecated since API version 10. You are advised to use [indicator](#indicator10) instead.|
......@@ -112,10 +112,10 @@ Defines the navigation point indicator of the dot style, which inherits attribut
| Name | Type | Mandatory. | Description |
| ------------------ | ---------------------------------------- | ---- | ---------------------------------------- |
| itemWidth | [Length](ts-types.md#length) | No | Width of the navigation point indicator of the dot style.<br>Default value: **6**<br>Unit: vp|
| itemHeight | [Length](ts-types.md#length) | No | Height of the navigation point indicator of the dot style.<br>Default value: **6**<br>Unit: vp|
| selectedItemWidth | [Length](ts-types.md#length) | No | Width of the selected navigation point indicator of the dot style.<br>Default value: **6**<br>Unit: vp|
| selectedItemHeight | [Length](ts-types.md#length) | No | Height of the selected navigation point indicator of the dot style.<br>Default value: **6**<br>Unit: vp|
| itemWidth | [Length](ts-types.md#length) | No | Width of the navigation point indicator of the dot style. This parameter cannot be set in percentage.<br>Default value: **6**<br>Unit: vp|
| itemHeight | [Length](ts-types.md#length) | No | Height of the navigation point indicator of the dot style. This parameter cannot be set in percentage.<br>Default value: **6**<br>Unit: vp|
| selectedItemWidth | [Length](ts-types.md#length) | No | Width of the selected navigation point indicator of the dot style. This parameter cannot be set in percentage.<br>Default value: **6**<br>Unit: vp|
| selectedItemHeight | [Length](ts-types.md#length) | No | Height of the selected navigation point indicator of the dot style. This parameter cannot be set in percentage.<br>Default value: **6**<br>Unit: vp|
| mask | boolean | No | Whether to enable the mask for the navigation point indicator of the dot style.<br>Default value: **false**|
| color | [ResourceColor](ts-types.md#resourcecolor) | No | Color of the navigation point indicator of the dot style.<br>Default value: **'\#182431'** (10% opacity)|
| selectedColor | [ResourceColor](ts-types.md#resourcecolor) | No | Color of the selected indicator dot.<br>Default value: **'\#007DFF'**|
......@@ -128,8 +128,8 @@ Defines the navigation point indicator of the digit style, which inherits attrib
| ----------------- | ---------------------------------------- | ---- | ---------------------------------------- |
| fontColor | [ResourceColor](ts-types.md#resourcecolor) | No | Font color of the navigation point indicator of the digit style.<br>Default value: **'\#ff182431'**|
| selectedFontColor | [ResourceColor](ts-types.md#resourcecolor) | No | Font color of the selected navigation point indicator of the digit style.<br>Default value: **'\#ff182431'**|
| digitFont | {<br>size?:[Length](ts-types.md#length)<br>weight?:number \| [FontWeight](ts-appendix-enums.md#fontweight) \| string<br>} | No | Font style of the navigation point indicator of the digit style.<br>\- **size**: font size.<br>Default value: **14vp**<br>\- **weight**: font weight.|
| selectedDigitFont | {<br>size?:[Length](ts-types.md#length)<br>weight?:number \| [FontWeight](ts-appendix-enums.md#fontweight) \| string<br>} | No | Font style of the selected navigation point indicator of the digit style.<br>\- **size**: font size.<br>Default value: **14vp**<br>\- **weight**: font weight.|
| digitFont | {<br>size?:[Length](ts-types.md#length)<br>weight?:number \| [FontWeight](ts-appendix-enums.md#fontweight) \| string<br>} | No | Font style of the navigation point indicator of the digit style.<br>\- **size**:font size. It cannot be set in percentage.<br>Default value: **14vp**<br>\- **weight**: font weight.|
| selectedDigitFont | {<br>size?:[Length](ts-types.md#length)<br>weight?:number \| [FontWeight](ts-appendix-enums.md#fontweight) \| string<br>} | No | Font style of the selected navigation point indicator of the digit style.<br>\- **size**:font size. It cannot be set in percentage.<br>Default value: **14vp**<br>\- **weight**: font weight.|
## ArrowStyle<sup>10+</sup>
Describes the left and right arrow attributes.
......
......@@ -27,13 +27,15 @@ Data sources of the archived type can be classified into local resources, online
- Local resources
To load local images, create an **ets** folder and place the local images in any position in the folder. Then, in the **\<Image>** component, set **src** to the local image path, with the root directory being the **ets** folder.
To load local images, create an **ets** folder and place the local images in any position in the folder.
Then, in the **\<Image>** component, set **src** to the local image path, with the root directory being the **ets** folder.
```ts
Image('images/view.jpg')
Image('images/view.jpg')
.width(200)
```
- Online resources
To use online images, first apply for the **ohos.permission.INTERNET** permission. For details, see [Applying for Permissions](../security/accesstoken-guidelines.md). Then, in the **\<Image>** component, set **src** to the URL of the online image.
......@@ -46,9 +48,9 @@ Image('images/view.jpg')
**Resource** objects can be used to import images across bundles and modules.
To load **Resource** objects, place images in the **resources** folder, which can then be read and converted to the **Resource** objects through **$r**.
To load **Resource** objects, place images in the **resources** folder, which can be read and converted to the **Resource** objects through **$r**.
**Figure 1** resources folder
**Figure 1** resources folder
![image-resource](figures/image-resource.jpg)
......@@ -75,17 +77,15 @@ Image('images/view.jpg')
To load images from the media library, use a path string that starts with **file://**.
1. Call the API to obtain the image URL in the media library.
```ts
import picker from '@ohos.file.picker';
@Entry
@Component
struct Index {
@State imgDatas: string[] = [];
// Obtain the image URL set.
getAllImg() {
let photoPicker = new picker.PhotoViewPicker();
let result = new Array<string>();
try {
let PhotoSelectOptions = new picker.PhotoSelectOptions();
......@@ -101,7 +101,7 @@ Image('images/view.jpg')
} catch (err) {
console.error(`PhotoViewPicker failed with. Code: ${err.code}, message: ${err.message}`); }
}
// Call the preceding function in aboutToAppear to obtain the image URL set and store the URLs in imgDatas.
async aboutToAppear() {
this.getAllImg();
......@@ -121,8 +121,8 @@ Image('images/view.jpg')
}
}
```
2. Check the format of the URL obtained from the media library:
```ts
Image('file://media/Photos/5')
.width(200)
......@@ -150,14 +150,12 @@ A pixel map is a pixel image obtained after image decoding. For details, see [Im
Request an online image and implement transcoding to generate a pixel map.
1. Reference the network and media library access permissions.
```ts
import http from '@ohos.net.http';
import ResponseCode from '@ohos.net.http';
import image from '@ohos.multimedia.image';
```
2. Enter the online image address.
```ts
http.createHttp().request("https://www.example.com/xxx.png",
(error, data) => {
......@@ -168,25 +166,25 @@ A pixel map is a pixel image obtained after image decoding. For details, see [Im
}
)
```
3. Transcode the data returned by the online image address to a pixel map.
3. Transcode the data returned by the online image address to a pixel map.
```ts
let code = data.responseCode;
if(ResponseCode.ResponseCode.OK === code) {
let imageSource = image.createImageSource(data.result);
if (ResponseCode.ResponseCode.OK === code) {
let res: any = data.result
let imageSource = image.createImageSource(res);
let options = {
alphaType: 0, // Alpha type.
editable: false, // Whether the image is editable.
pixelFormat: 3, // Pixel format.
scaleMode: 1, // Scale mode.
size: {height: 100, width: 100}
} // Image size.
imageSource.createPixelMap(options).then((pixelMap) => {
alphaType: 0, // Alpha type.
editable: false, // Whether the image is editable.
pixelFormat: 3, // Pixel format.
scaleMode: 1, // Scale mode.
size: { height: 100, width: 100 }
} // Image size.
imageSource.createPixelMap(options).then((pixelMap) => {
this.image = pixelMap
})
})
}
```
4. Display the image.
```ts
Button ("Get Online Image")
.onClick(() => {
......
......@@ -46,7 +46,7 @@ When used in horizontal layout, the list can contain one or more scrollable rows
The main axis direction of a list refers to the direction in which the child component columns are laid out and in which the list scrolls. An axis perpendicular to the main axis is referred to as a cross axis, and the direction of the cross axis is perpendicular to a direction of the main axis.
As shown below, the main axis of a vertical list is in the vertical direction, and the cross axis is in the horizontal direction. The main axis of a horizontal list is in the horizontal direction, and the cross axis is in the horizontal direction.
As shown below, the main axis of a vertical list is in the vertical direction, and the cross axis is in the horizontal direction. The main axis of a horizontal list is in the horizontal direction, and the cross axis is in the vertical direction.
**Figure 4** Main axis and cross axis of the list
......@@ -615,7 +615,7 @@ struct MessageList {
## Adding a Mark to a List Item
A mark is an intuitive, unintrusive visual indicator to draw attention and convey a specific message. For example, when a new message is received in the message list, a mark is displayed in the upper right corner of the contact's profile picture, indicating that there is a new message from that contact, as shown in the following figure.
A mark is an intuitive, unobtrusive visual indicator to draw attention and convey a specific message. For example, when a new message is received in the message list, a mark is displayed in the upper right corner of the contact's profile picture, indicating that there is a new message from that contact, as shown in the following figure.
**Figure 16** Adding a mark to a list item
......
......@@ -76,7 +76,7 @@ Row({ space: 35 }) {
In the layout container, use the **alignItems** attribute to set the alignment mode of child elements along the cross axis. The alignment performance is consistent across screens of various sizes. The value is of the [VerticalAlign Type](../reference/arkui-ts/ts-appendix-enums.md#verticalalign) type when the cross axis is in the vertical direction and the [HorizontalAlign](../reference/arkui-ts/ts-appendix-enums.md#horizontalalign) type when the cross axis is in the horizontal direction.
The layout container also provides the **alignSelf** attribute to control the alignment mode of a single child element along the main axis. This attribute has a higher priority than the **alignItems** attribute. This means that, if **alignSelf** is set, it will overwrite the **alignItems** setting on the corresponding child element.
The layout container also provides the **alignSelf** attribute to control the alignment mode of a single child element along the cross axis. This attribute has a higher priority than the **alignItems** attribute. This means that, if **alignSelf** is set, it will overwrite the **alignItems** setting on the corresponding child element.
### Horizontal Alignment of Layout Child Elements in \<Column> Container
......
......@@ -26,13 +26,13 @@ A child element does not necessarily adopt the dependency shown above to determi
### Setting the Anchor
By setting the anchor, you set a position dependency relationship between a child element and its parent element or sibling elements. In the horizontal direction, you can set the left, middle, and right anchors. In the vertical direction, you can set the top, center, and bottom anchors. To specify anchors, you must set IDs for the **\<RelativeContainer>** component and its child elements. The default ID is **container**. The ID is set through the **id** attribute. Child elements whose IDs are not set are not displayed in the **\<RelativeContainer>** component.
By setting the anchor, you set a position dependency relationship between a child element and its parent element or sibling elements. In the horizontal direction, you can set the left, middle, and right anchors. In the vertical direction, you can set the top, center, and bottom anchors. To specify anchors, you must set IDs for the **\<RelativeContainer>** component and its child elements. The default ID is **__container__**. The ID is set through the **id** attribute. Child elements whose IDs are not set are not displayed in the **\<RelativeContainer>** component.
>**NOTE**
>
>When using anchors, pay attention to the relative positions of child elements to avoid misplacement or blocking.
- The ID of the **\<RelativeContainer>** parent component is **container**.
- The ID of the **\<RelativeContainer>** parent component is **__container__**.
```ts
RelativeContainer() {
......@@ -81,7 +81,7 @@ Alignment modes in the horizontal direction can be left, center, or right, achie
![alignment-relative-anchor-horizontal](figures/alignment-relative-anchor-horizontal.png)
Alignment modes in the vertical direction can be top, center, or bottom, achieved by the **HorizontalAlign.Top**, **HorizontalAlign.Center**, and **HorizontalAlign.Bottom** attributes, respectively.
Alignment modes in the vertical direction can be top, center, or bottom, achieved by the **VerticalAlign.Top**, **VerticalAlign.Center**, and **VerticalAlign.Bottom** attributes, respectively.
![alignment-relative-anchor-vertical](figures/alignment-relative-anchor-vertical.png)
......@@ -114,7 +114,7 @@ struct Index {
.height(100).width(100)
.alignRules({
top: { anchor: 'row1', align: VerticalAlign.Bottom }, // Use row1 as the anchor and align with its bottom vertically.
left: { anchor: 'row1', align: HorizontalAlign.Start } // Use row1 as the anchor and align with its left horizontally.
left: { anchor: 'row1', align: HorizontalAlign.Start } // Use row1 as the anchor and align with its start edge horizontally.
})
.id('row2') // Set the anchor to row2.
......
......@@ -10,7 +10,7 @@ When developing a long list, use of loop rendering, as in the code snippet below
@Entry
@Component
struct MyComponent {
@State arr: number[] = Array.from(Array(100), (v,k) =>k); // Construct an array of 0 to 99.
@State arr: number[] = Array.from(Array<number>(100), (v,k) =>k); // Construct an array of 0 to 99.
build() {
List() {
ForEach(this.arr, (item: number) => {
......@@ -33,8 +33,8 @@ class BasicDataSource implements IDataSource {
return 0
}
public getData(index: number): any {
return undefined
public getData(index: number): string {
return ''
}
registerDataChangeListener(listener: DataChangeListener): void {
......@@ -90,7 +90,7 @@ class MyDataSource extends BasicDataSource {
return this.dataArray.length
}
public getData(index: number): any {
public getData(index: number): string {
return this.dataArray[index]
}
......@@ -121,7 +121,7 @@ struct MyComponent {
.onClick(() => {
this.data.pushData('item value: ' + this.data.totalCount())
})
}, item => item)
}, (item:string) => item)
}
}
}
......@@ -155,8 +155,8 @@ class BasicDataSource implements IDataSource {
return 0
}
public getData(index: number): any {
return undefined
public getData(index: number): string {
return ''
}
registerDataChangeListener(listener: DataChangeListener): void {
......@@ -212,7 +212,7 @@ class MyDataSource extends BasicDataSource {
return this.dataArray.length
}
public getData(index: number): any {
public getData(index: number): string {
return this.dataArray[index]
}
......@@ -235,10 +235,10 @@ struct MyComponent {
build() {
Scroll() {
List() {
LazyForEach(this.data, (item: string, index: number) => {
LazyForEach(this.data, (item: string, index?: number) => {
ListItem() {
Row() {
Text('item value: ' + item + (index + 1)).fontSize(20).margin(10)
Text('item value: ' + item + (index as number + 1)).fontSize(20).margin(10)
}
}
})
......@@ -258,8 +258,8 @@ class BasicDataSource implements IDataSource {
return 0
}
public getData(index: number): any {
return undefined
public getData(index: number): string {
return ''
}
registerDataChangeListener(listener: DataChangeListener): void {
......@@ -315,7 +315,7 @@ class MyDataSource extends BasicDataSource {
return this.dataArray.length
}
public getData(index: number): any {
public getData(index: number): string {
return this.dataArray[index]
}
......@@ -338,9 +338,9 @@ struct MyComponent {
build() {
Scroll() {
List() {
LazyForEach(this.data, (item: string, index: number) => {
LazyForEach(this.data, (item: string, index?: number) => {
ListItem() {
Text('item value: ' + item + (index + 1)).fontSize(20).margin(10)
Text('item value: ' + item + (index as number + 1)).fontSize(20).margin(10)
}.width('100%')
})
}.width('100%').height(500)
......@@ -453,7 +453,7 @@ struct MyComponent {
build() {
List() {
LazyForEach(this.source, item => {
LazyForEach(this.source, (item:number) => {
ListItem() {
Text("Hello" + item)
.fontSize(50)
......@@ -473,7 +473,7 @@ class MyDataSource implements IDataSource {
return this.data.length
}
public getData(index: number): any {
public getData(index: number): number {
return this.data[index]
}
......
......@@ -28,7 +28,7 @@ Button('click for Menu')
## Creating a Menu in a Custom Style
If the default style does not meet requirements, you can use \@CustomBuilder to customize menu content. Menus can also be customized through the **bindMenu** API.
If the default style does not meet requirements, you can use [\@Builder](../quick-start/arkts-builder.md) to customize menu content. You can also use the **bindMenu** API to bind a custom menu to a component.
### \@Builder: Customizing Menu Content
......@@ -56,7 +56,7 @@ MyMenu(){
content: "Menu option",
endIcon: $r("app.media.arrow_right_filled"),
// When the builder parameter is set, it indicates that a submenu is bound to a menu item. When the user hovers the cursor over the menu item, the submenu is displayed.
builder: this.SubMenu.bind(this),
builder: this.SubMenu,
})
MenuItemGroup ({ header: 'Subtitle' }) {
MenuItem ({ content: "Menu option" })
......@@ -70,7 +70,7 @@ MyMenu(){
startIcon: $r("app.media.view_list_filled"),
content: "Menu option",
endIcon: $r("app.media.arrow_right_filled"),
builder: this.SubMenu.bind(this)
builder: this.SubMenu
})
}
MenuItem({
......
......@@ -124,21 +124,25 @@ If you need to transfer data to the target page during redirection, you can add
```ts
class DataModelInfo {
age: number;
constructor(age: number) {
this.age = age;
}
}
class DataModel {
id: number;
info: DataModelInfo;
constructor(id: number, info: DataModelInfo) {
this.id = id;
this.info = info;
}
}
function onJumpClick(): void {
// On the Home page
let paramsInfo: DataModel = {
id: 123,
info: {
age: 20
}
};
let paramsInfo: DataModel = new DataModel(123, new DataModelInfo(20));
router.pushUrl({
url: 'pages/Detail', // Target URL.
......@@ -157,9 +161,9 @@ On the target page, you can call the [getParams()](../reference/apis/js-apis-rou
```ts
const params = router.getParams(); // Obtain the passed parameters.
const id = params['id']; // Obtain the value of the id attribute.
const age = params['info'].age; // Obtain the value of the age attribute.
const params:DataModel = router.getParams() as DataModel; // Obtain the passed parameter object.
const id:number = params.id; // Obtain the value of the id attribute.
const age:number = params.info.age; // Obtain the value of the age attribute.
```
......@@ -204,11 +208,17 @@ You can use any of the following methods to return to a page:
```ts
class routerParam {
info: string;
constructor(info: string) {
this.info = info;
}
}
router.back({
url: 'pages/Home',
params: {
info:'From Home Page'
}
params: new routerParam ('From Home Page')
});
```
......@@ -219,8 +229,8 @@ On the target page, call the **router.getParams()** API at the position where pa
```ts
onPageShow() {
const params = router.getParams(); // Obtain the passed parameters.
const info = params['info']; // Obtain the value of the info attribute.
const params = router.getParams() as routerParam; // Obtain the passed parameter object.
const info = params.info; // Obtain the value of the info attribute.
}
```
......@@ -257,6 +267,8 @@ To enable the confirmation dialog box for page return, call the [router.showAler
```ts
import {BusinessError} from '@ohos.base';
// Define a click event processing function for the back button.
function onBackClick(): void {
// Invoke the router.showAlertBeforeBackPage() API to set the information about the confirmation dialog box.
......@@ -265,7 +277,7 @@ function onBackClick(): void {
message: 'Payment not completed yet. Are you sure you want to return?' // Set the content of the confirmation dialog box.
});
} catch (err) {
console.error(`Invoke showAlertBeforeBackPage failed, code is ${err.code}, message is ${err.message}`);
console.error(`Invoke showAlertBeforeBackPage failed, code is ${(err as BusinessError).code}, message is ${(err as BusinessError).message}`);
}
// Invoke the router.back() API to return to the previous page.
......@@ -276,7 +288,7 @@ function onBackClick(): void {
The **router.showAlertBeforeBackPage()** API receives an object as a parameter. The object contains the following attributes:
**message**: content of the dialog box. The value is of the string type.
If the API is successfully called, the confirmation dialog box is displayed on the target page. Otherwise, an exception is thrown and the error code and error information is obtained through **err.code** and **err.message**.
If the API is called successfully, the confirmation dialog box is displayed on the target page. Otherwise, an exception is thrown and the error code and error information is obtained through **err.code** and **err.message**.
When the user clicks the back button, a confirmation dialog box is displayed, prompting the user to confirm their operation. If the user selects Cancel, the application stays on the current page. If the user selects OK, the **router.back()** API is triggered and the redirection is performed based on the parameters.
......@@ -295,6 +307,9 @@ In the event callback, call the [promptAction.showDialog()](../reference/apis/js
```ts
import { BusinessError } from '@ohos.base';
import promptAction from '@ohos.promptAction';
function onBackClick() {
// Display a custom confirmation dialog box.
promptAction.showDialog({
......@@ -319,7 +334,7 @@ function onBackClick() {
// Invoke the router.back() API to return to the previous page.
router.back();
}
}).catch((err) => {
}).catch((err:BusinessError) => {
console.error(`Invoke showDialog failed, code is ${err.code}, message is ${err.message}`);
})
}
......@@ -342,6 +357,7 @@ In the target page in the [shared package](../quick-start/shared-guide.md), name
```ts
// library/src/main/ets/pages/Index.ets
// library is the custom name of the new shared package.
@Entry({ routeName : 'myPage' })
@Component
struct MyComponent {
......@@ -353,7 +369,26 @@ When the configuration is successful, import the named route page to the page fr
```ts
// entry/src/main/ets/pages/Index.ets
import router from '@ohos.router';
import 'library/src/main/ets/Index.ets' // Import the named route page from the shared package library.
import'library/src/main/ets/pages/Index' // Import the named route page from the library of the shared package.
import { BusinessError } from '@ohos.base';
class innerParams {
data3: number[];
constructor(tuple: number[]) {
this.data3 = tuple;
}
}
class routerParams {
data1: string;
data2: innerParams;
constructor(data1: string, data2: number[]) {
this.data1 = data1;
this.data2 = new innerParams(data2);
}
}
@Entry
@Component
......@@ -369,15 +404,10 @@ struct Index {
try {
router.pushNamedRoute({
name: 'myPage',
params: {
data1: 'message',
data2: {
data3: [123, 456, 789]
}
}
params: new routerParams('message', [123, 456, 789])
})
} catch (err) {
console.error(`pushNamedRoute failed, code is ${err.code}, message is ${err.message}`);
console.error(`pushNamedRoute failed, code is ${(err as BusinessError).code}, message is ${(err as BusinessError).message}`);
}
})
}
......
......@@ -86,7 +86,7 @@ export struct share_transition_expand {
build() {
Column() {
List() {
ForEach(this.listArray, (item, index) => {
ForEach(this.listArray, (item:number, index) => {
// Customize the expanded component as required.
if (!this.isExpand || this.curIndex == index) {
ListItem() {
......@@ -128,7 +128,7 @@ export struct share_transition_expand {
.onClick(() => {
// Define the animation parameters for expanding and collapsing.
animateTo({ curve: curves.springMotion(0.6, 0.9) }, () => {
this.curIndex = index;
this.curIndex = index as number;
this.isExpand = !this.isExpand;
})
})
......@@ -216,12 +216,12 @@ export struct share_zIndex_expand {
@Link isExpand: boolean;
@Link curIndex: number;
@State listArray: Array<number> = [1, 2, 3, 4, 5, 6];
private parentScroller: Scroller; // Upper-layer scroller controller.
private parentScroller: Scroller = new Scroller(); // Upper-layer scroller
build() {
Column() {
List() {
ForEach(this.listArray, (item, index) => {
ForEach(this.listArray, (item: number, index) => {
// Customize the expanded component as required.
if (!this.isExpand || this.curIndex == index) {
ListItem() {
......@@ -271,7 +271,7 @@ export struct share_zIndex_expand {
.onClick(() => {
// Define the animation parameters for expanding and collapsing.
animateTo({ curve: curves.springMotion(0.6, 0.9) }, () => {
this.curIndex = index;
this.curIndex = index as number;
this.isExpand = !this.isExpand;
})
})
......@@ -540,7 +540,7 @@ struct AutoAchieveShareTransitionDemo {
Stack() {
Scroll() {
Column({ space: 20 }) {
ForEach(this.items, (item, index) => {
ForEach(this.items, (item:string, index) => {
Row() {
Column() {
Text('Shared element ' + item)
......@@ -567,15 +567,7 @@ struct AutoAchieveShareTransitionDemo {
.onClick(() => {
// Obtain the position and size of the corresponding component.
let strJson = getInspectorByKey(item);
let obj = JSON.parse(strJson);
let rectInfo = JSON.parse('[' + obj.$rect + ']');
let rect_left = JSON.parse('[' + rectInfo[0] + ']')[0];
let rect_top = JSON.parse('[' + rectInfo[0] + ']')[1];
let rect_right = JSON.parse('[' + rectInfo[1] + ']')[0];
let rect_bottom = JSON.parse('[' + rectInfo[1] + ']')[1];
let rect_value = {
"left": rect_left, "top": rect_top, "right": rect_right, "bottom": rect_bottom
};
let rect_top:number = JSON.parse('[' + JSON.parse('[' + JSON.parse(strJson).$rect + ']')[0] + ']')[1];
// Set the location, content, and status of the shared element.
this.rect_top = rect_top;
......
# Spring Curve
In a damped spring system corresponding to a damped spring curve (spring curve for short), an object that deviates from the equilibrium position is forced to oscillate due to a reverse force generated by spring deformation; this oscillation is resisted by the damping force. Except for the special case where the damping is 0, the oscillation gradually decays in amplitude towards 0, and the resultant animation curve is naturally continuous.
In a damped spring system corresponding to a damped spring curve (spring curve for short), an object that deviates from the equilibrium position is forced to oscillate due to a reverse force generated by spring deformation; this oscillation is resisted by the damping force. Except for the special case where the damping is 0, the oscillation gradually decays in amplitude towards 0, and the resultant animation curve is natural and continuous.
An animation using the spring curve slows down toward the end where the velocity of 0, instead of stopping abruptly.
An animation using the spring curve slows down toward the end until the velocity is 0, instead of stopping abruptly.
ArkUI provides four types of damped spring curve APIs:
......@@ -19,7 +19,7 @@ ArkUI provides four types of damped spring curve APIs:
- [responsiveSpringMotion](../reference/apis/js-apis-curve.md#curvesresponsivespringmotion9): creates a responsive spring animation curve. It is a special case of **springMotion**, with the only difference in the default values. It is typically used to create an animation with a gesture on the screen. You can use **springMotion** to create an animation for when the user lifts their finger off the screen. The created animation automatically inherits the previous velocity for animation transition.
When the **overlapDuration** parameter of the new animation is not **0** and the previous spring animation of the current attribute is not yet complete, **response** and **dampingFracion** transit from the values of the previous animation to that of the new animation within the period specified by **overlapDuration**.
When the **overlapDuration** parameter of the new animation is not **0** and the previous spring animation of the current attribute is not yet complete, **response** and **dampingFracion** transit, over the period specified by **overlapDuration**, from the values of the previous animation to that of the new animation.
```ts
......@@ -46,6 +46,10 @@ ArkUI provides four types of damped spring curve APIs:
The following shows a complete example and effect of spring curves. For details about how to connect gestures and animations, see [Animation Smoothing](arkts-animation-smoothing.md).
```ts
import curves from '@ohos.curves';
......@@ -64,10 +68,10 @@ class Spring {
// Spring component
@Component
struct Motion {
@Prop dRotate: number
private title: string
private subTitle: string
private iCurve: ICurve
@Prop dRotate: number = 0
private title: string = ''
private subTitle: string = ''
private iCurve: ICurve = curves.initCurve()
build() {
Row() {
......@@ -130,11 +134,17 @@ struct Motion {
@Component
export struct SpringDemo {
@State dRotate: number = 0;
private curvelist: ICurve[] = [
curves.springMotion(1, 0.25),
curves.responsiveSpringMotion(1, 0.25),
curves.interpolatingSpring(10, 1, 228, 30),
curves.springCurve(10, 1, 228, 30)
];
private springs: Spring[] = [
new Spring('springMotion()', '(springMotion(1, 0.25): \n\nCycle: 2; damping: 0.25)', curves.springMotion(1, 0.25)),
new Spring('responsiveSpringMotion()', 'responsiveSpringMotion(1, 0.25): \n\nDefault responsive spring curve', curves.responsiveSpringMotion(1, 0.25)),
new Spring('interpolatingSpring()', '(interpolatingSpring(10, 1, 228, 30): \n\nInitial velocity: 100; quality: 1; stiffness: 228; damping: 30)', curves.interpolatingSpring(10, 1, 228, 30)),
new Spring('springCurve()', '(springCurve(10, 1, 228, 30): \n\nInitial velocity: 100; quality: 1; stiffness: 228; damping: 30)', curves.springCurve(10, 1, 228, 30))
new Spring('springMotion()', '(springMotion (1, 0.25): \n\nCycle: 2; damping: 0.25)', this.curvelist[0]),
new Spring('responsiveSpringMotion()', 'responsiveSpringMotion(1, 0.25): \n\nDefault responsive spring curve', this.curvelist[1]),
new Spring('interpolatingSpring()', '(interpolatingSpring(10, 1, 228, 30): \n\nInitial velocity: 100; quality: 1; stiffness: 228; damping: 30)', this.curvelist[2]),
new Spring('springCurve()', '(springCurve(10, 1, 228, 30): \n\nInitial velocity: 100; quality: 1; stiffness: 228; damping: 30)', this.curvelist[3])
];
build() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册