• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Supporting Aging-Friendly Design
2<!--RP1-->
3
4## Basic Concepts
5
6Aging-friendly design offers a method to enlarge selected areas or components through a long-press action with a mouse or finger. Specifically, when the system font is larger than 1x, this action on a component with aging-friendly features extracts data from the component within the selected area and presents it in a dialog box. This way, both the component and its internal data (child components) are enlarged, and the entire component is centered on the screen for better visibility.
7
8## Constraints
9
10* Aging-friendly rules
11
12  To ensure that components enlarge appropriately when the system font size is greater than 1x, you need to configure the [configuration tag](../quick-start/app-configuration-file.md#configuration) for implementing an aging-friendly feature.
13
14* Aging-friendly operations
15
16  Long-pressing a component that supports aging-friendly capabilities triggers a dialog box. The aging-friendly operation ends when the user releases the press. When the system font size is set to be greater than 1x, the component automatically enlarges, and when the system font size returns to 1x, the component returns to its normal state.
17
18* Aging-friendly objects
19
20  The components that trigger the aging-friendly operation and provide the data.
21
22* Aging-friendly dialog box targets
23
24  The components capable of receiving and processing the aging-friendly data.
25
26* Dialog box restrictions
27
28  When users set the system font to more than 2x, the dialog box content, including icons and text, is magnified at a fixed 2x scale.
29
30* Combination with other capabilities
31
32  Aging-friendly capabilities can be integrated with other features (such as swipe and drag). When the bottom tab bar (**tabBar**) component is activated for aging-friendly features, users can swipe their fingers or use a mouse to trigger aging-friendly features for other child components within the tab bar.
33
34## Aging-Friendly Component Adaptation and Activation Methods
35
36| Activation Method            | Component                                                    |
37| -------------------- | ------------------------------------------------------------ |
38| Long press on the component        | [SideBarContainer](../reference/apis-arkui/arkui-ts/ts-container-sidebarcontainer.md), [Bottom Tab Bar (tabBar)](../reference/apis-arkui/arkui-ts/ts-container-tabcontent.md#tabbar9), [Navigation](../reference/apis-arkui/arkui-ts/ts-basic-components-navigation.md), [NavDestination](../reference/apis-arkui/arkui-ts/ts-basic-components-navigation.md#navdestination10), [Tabs](../reference/apis-arkui/arkui-ts/ts-container-tabs.md)|
39| Default system font enlargement| [PickerDialog](../reference/apis-arkui/arkui-ts/ts-methods-calendarpicker-dialog.md), [Button](../reference/apis-arkui/arkui-ts/ts-basic-components-button.md), [Menu](../reference/apis-arkui/arkui-ts/ts-basic-components-menu.md), [Stepper](../reference/apis-arkui/arkui-ts/ts-basic-components-stepper.md), [BindSheet](../reference/apis-arkui/arkui-ts/ts-universal-attributes-sheet-transition.md#bindsheet), [TextInput](../reference/apis-arkui/arkui-ts/ts-basic-components-textinput.md), [TextArea](../reference/apis-arkui/arkui-ts/ts-basic-components-textarea.md), [Search](../reference/apis-arkui/arkui-ts/ts-basic-components-search.md), [SelectionMenu](../reference/apis-arkui/arkui-ts/ohos-arkui-advanced-SelectionMenu.md), [Chip](../reference/apis-arkui/arkui-ts/ohos-arkui-advanced-Chip.md#chip), [Dialog](../reference/apis-arkui/arkui-ts/ohos-arkui-advanced-Dialog.md), [Slider](../reference/apis-arkui/arkui-ts/ts-basic-components-slider.md), [Progress](../reference/apis-arkui/arkui-ts/ts-basic-components-progress.md), [Badge](../reference/apis-arkui/arkui-ts/ts-container-badge.md)|
40
41## Example
42
43This example uses the **SideBarContainer** component to trigger an aging-friendly dialog box through a long press of the control button. Note that the dialog box does not appear if the system font size is at the 1x setting. Instead, it appears only when the system font size is set to greater than 1x.
44
45```ts
46import { abilityManager, Configuration } from '@kit.AbilityKit';
47import { BusinessError } from '@kit.BasicServicesKit';
48
49@Entry
50@Component
51struct SideBarContainerExample {
52  @State currentFontSizeScale: number = 1
53  normalIcon: Resource = $r("app.media.icon") // Example icon. Replace it with the actual image.
54  selectedIcon: Resource = $r("app.media.icon") // Example icon. Replace it with the actual image.
55  @State arr: number[] = [1, 2, 3]
56  @State current: number = 1
57  @State title: string = 'Index01';
58  // Set the font scale.
59  async setFontScale(scale: number): Promise<void> {
60    let configInit: Configuration = {
61      language: 'zh-Ch',
62      fontSizeScale: scale,
63    };
64    // Update the font size.
65    abilityManager.updateConfiguration(configInit, (err: BusinessError) => {
66      if (err) {
67        console.error(`updateConfiguration fail, err: ${JSON.stringify(err)}`);
68      } else {
69        this.currentFontSizeScale = scale;
70        console.log('updateConfiguration success.');
71      }
72    });
73  }
74
75  build() {
76    SideBarContainer(SideBarContainerType.Embed) {
77      Column() {
78        ForEach(this.arr, (item: number) => {
79          Column({ space: 5 }) {
80            Image(this.current === item ? this.selectedIcon : this.normalIcon).width(64).height(64)
81            Text("0" + item)
82              .fontSize(25)
83              .fontColor(this.current === item ? '#0A59F7' : '#999')
84              .fontFamily('source-sans-pro,cursive,sans-serif')
85          }
86          .onClick(() => {
87            this.current = item;
88            this.title = "Index0" + item;
89          })
90        }, (item: string) => item)
91      }.width('100%')
92      .justifyContent(FlexAlign.SpaceEvenly)
93      .backgroundColor($r('sys.color.mask_fifth'))
94
95      Column() {
96        Text(this.title)
97        Button('1x').onClick(() => {
98          this.setFontScale(1)
99        }).margin(10)
100        Button('1.75x').onClick(() => {
101          this.setFontScale(1.75)
102        }).margin(10)
103        Button('2x').onClick(() => {
104          this.setFontScale(2)
105        }).margin(10)
106        Button('3.2x').onClick(() => {
107          this.setFontScale(3.2)
108        }).margin(10)
109      }
110      .margin({ top: 50, left: 20, right: 30 })
111    }
112    .controlButton({
113      icons: {
114        hidden: $r('sys.media.ohos_ic_public_drawer_open_filled'),
115        shown: $r('sys.media.ohos_ic_public_drawer_close')
116      }
117    })
118    .sideBarWidth(150)
119    .minSideBarWidth(50)
120    .maxSideBarWidth(300)
121    .minContentWidth(0)
122    .onChange((value: boolean) => {
123      console.info('status:' + value)
124    })
125    .divider({ strokeWidth: '1vp', color: Color.Gray, startMargin: '4vp', endMargin: '4vp' })
126  }
127}
128```
129
130Switching system font sizes and long-pressing components with aging-friendly capabilities yields the effects as follows.
131
132| System Font at 1x (Before Aging-Friendly Features Are Enabled)| System Font at 1.75x (After Aging-Friendly Features Are Enabled)|
133| ---------------------------------- | ------------------------------------ |
134| ![](figures/aging_01.png)          | ![](figures/aging_02.png)            |
135
136The [TextPickerDialog](../reference/apis-arkui/arkui-ts/ts-methods-textpicker-dialog.md) component triggers an aging-friendly dialog box when the system font is set to greater than 1x, which does not occur at the default 1x setting.
137
138```ts
139import { abilityManager, Configuration } from '@kit.AbilityKit';
140import { BusinessError } from '@kit.BasicServicesKit';
141
142@Entry
143@Component
144struct TextPickerExample {
145  private select: number | number[] = 0;
146  private cascade: TextCascadePickerRangeContent[] = [
147    {
148      text: 'Category 1',
149      children: [{ text: 'Subcategory 1', children: [{ text: 'Subcategory 2' }, { text: 'Subcategory 3' }, { text: 'Subcategory 4' }] },
150        { text: 'Item 1', children: [{ text: 'Item 2' }, { text: 'Item 3' }, { text: 'Item 4' }] }]
151    },
152    {
153      text: 'Category 2',
154      children: [{ text: 'Subcategory 1', children: [{ text: 'Subcategory 2' }, { text: 'Subcategory 3' }, { text: 'Subcategory 4' }] },
155        { text: 'Item 1', children: [{ text: 'Item 2' }, { text: 'Item 3' }, { text: 'Item 4' }] }]
156    },
157    {
158      text: 'Category 3',
159      children: [{ text: 'Subcategory 1', children: [{ text: 'Subcategory 2' }, { text: 'Subcategory 3' }, { text: 'Subcategory 4' }] },
160        { text: 'Item 1', children: [{ text: 'Item 2' }, { text: 'Item 3' }, { text: 'Item 4' }] }]
161    }
162  ]
163  @State v: string = '';
164  @State showTriggered: string = '';
165  private triggered: string = '';
166  private maxLines: number = 3;
167  // Set the font scale.
168  async setFontScale(scale: number): Promise<void> {
169    let configInit: Configuration = {
170      fontSizeScale: scale,
171    };
172
173    abilityManager.updateConfiguration(configInit, (err: BusinessError) => {
174      if (err) {
175        console.error(`updateConfiguration fail, err: ${JSON.stringify(err)}`);
176      } else {
177        console.log('updateConfiguration success.');
178      }
179    });
180  }
181
182  linesNum(max: number): void {
183    let items: string[] = this.triggered.split('\n').filter(item => item != '');
184    if (items.length > max) {
185      this.showTriggered = items.slice(-this.maxLines).join('\n');
186    } else {
187      this.showTriggered = this.triggered;
188    }
189  }
190
191  build() {
192    Column() {
193      Button("TextPickerDialog.show:" + this.v)
194        .onClick(() => {
195          this.getUIContext().showTextPickerDialog({
196            range: this.cascade,
197            selected: this.select,
198            onAccept: (value: TextPickerResult) => {
199              this.select = value.index
200              console.log(this.select + '')
201              this.v = value.value as string
202              console.info("TextPickerDialog:onAccept()" + JSON.stringify(value))
203              if (this.triggered != '') {
204                this.triggered += `\nonAccept(${JSON.stringify(value)})`;
205              } else {
206                this.triggered = `onAccept(${JSON.stringify(value)})`;
207              }
208              this.linesNum(this.maxLines);
209            },
210            onCancel: () => {
211              console.info("TextPickerDialog:onCancel()")
212              if (this.triggered != '') {
213                this.triggered += `\nonCancel()`;
214              } else {
215                this.triggered = `onCancel()`;
216              }
217              this.linesNum(this.maxLines);
218            },
219            onChange: (value: TextPickerResult) => {
220              console.info("TextPickerDialog:onChange()" + JSON.stringify(value))
221              if (this.triggered != '') {
222                this.triggered += `\nonChange(${JSON.stringify(value)})`;
223              } else {
224                this.triggered = `onChange(${JSON.stringify(value)})`;
225              }
226              this.linesNum(this.maxLines);
227            },
228          })
229        })
230        .margin({ top: 60 })
231
232      Row() {
233        Button('1x').onClick(() => {
234          this.setFontScale(1)
235        }).margin(10)
236        Button('1.75x').onClick(() => {
237          this.setFontScale(1.75)
238        }).margin(10)
239
240        Button('2x').onClick(() => {
241          this.setFontScale(2)
242        }).margin(10)
243        Button('3.2x').onClick(() => {
244          this.setFontScale(3.2)
245        }).margin(10)
246      }.margin({ top: 50 })
247    }
248
249  }
250}
251```
252
253| System Font at 1x (Before Aging-Friendly Features Are Enabled)| System Font at 1.75x (After Aging-Friendly Features Are Enabled)|
254| ---------------------------------- | ------------------------------------ |
255| ![](figures/aging_03.png)          | ![](figures/aging_04.png)            |
256<!--RP1End-->
257