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

!20240 新增案例【不需要翻译】

Merge pull request !20240 from duangavin123/master
...@@ -26,6 +26,9 @@ ...@@ -26,6 +26,9 @@
- [常见弹窗的使用](diverse-dialogues.md) - [常见弹窗的使用](diverse-dialogues.md)
- [折叠展开动效](collapse-and-expand.md) - [折叠展开动效](collapse-and-expand.md)
- [列表上拉加载更多内容](list-pullup-loading-data.md) - [列表上拉加载更多内容](list-pullup-loading-data.md)
- [如何删除多选框选项](delete-checkboxgroup-items.md)
- [像素单位转换](pixel-format-transfer.md)
### 装饰器 ### 装饰器
- [控制页面刷新范围](overall-and-part-refresh.md) - [控制页面刷新范围](overall-and-part-refresh.md)
- [如何监听多层状态变化](observed-and-objectlink.md) - [如何监听多层状态变化](observed-and-objectlink.md)
...@@ -38,8 +41,12 @@ ...@@ -38,8 +41,12 @@
- [如何创建悬浮窗](float-window.md) - [如何创建悬浮窗](float-window.md)
- [保持屏幕常亮](keep-screen-on.md) - [保持屏幕常亮](keep-screen-on.md)
### 数据管理
- [用户首选项的基本使用](preferences-data-process.md)
### 媒体 ### 媒体
- [常见图片编辑](image-edit.md) - [常见图片编辑](image-edit.md)
- [图片格式转换](image-format-transfer.md)
### 一次开发,多端部署 ### 一次开发,多端部署
- [Navigation如何实现多场景UI适配](multi-device-app-dev.md) - [Navigation如何实现多场景UI适配](multi-device-app-dev.md)
......
# 如何删除多选框选项
## 场景说明
通常情况下,我们使用多选框都会伴随对选项的操作,比较常见的操作是选中后删除,比如删除购物车的商品、删除账单、删除图片等等。但是,当前OpenHarmony针对多选框组件并没有提供直接的删除其选项的方法,需要开发者自己来实现。本例提供了一种实现方案,供开发者参考。
## 效果呈现
本例最终效果如下:
![delete-checkboxitem](figures/delete-checkboxitem.gif)
## 运行环境
本例基于以下环境开发,开发者也可以基于其他适配的版本进行开发:
- IDE: DevEco Studio 4.0 Beta1
- SDK: Ohos_sdk_public 4.0.7.5 (API Version 10 Beta1)
## 实现思路
本例中涉及的关键特性及实现方案如下:
- 多选框:使用CheckboxGroup组件构建多选框标题,使用Checkbox组件构建多选框选项。
- 删除多选框选项:通过CheckboxGroup的onChange回调获取到各个选项的选中状态,在删除操作中,将选中的选项从选项列表中删除。
- 删除时弹出确认框:使用promptAction模块调用showDialog方法弹出对话框,通过回调获取到用户点击的是取消按钮还是确定按钮,如果是确定按钮则执行删除操作。
## 开发步骤
1. 搭建UI布局。
整体纵向布局,那就采用Column组件;全选框用CheckboxGroup组件,然后每个选项都包括一个选择框(Checkbox组件)和一个文本(Text组件),且为横向布局,那我们可以把它们放在Flex组件中;最后是一个Button组件。这样整体布局就有了,具体代码如下:
```ts
@Component
struct CheckboxDemo{
build(){
Column(){
Flex({}){
CheckboxGroup({})
Text('水果清单')
}
Flex({}){
Checkbox({})
Text('苹果')
}
Flex({}){
Checkbox({})
Text('菠萝')
}
Flex({}){
Checkbox({})
Text('柚子')
}
Button('删除')
}
}
}
```
框架搭好了,看下效果:
![checkbox-before-improve](figures/checkbox-before-improve.PNG)
可以看到主选框和选项对齐了,接下来我们来调整下样式。
先给CheckboxGroup取个名字:fruit_list,然后为各个Checkbox添加相同的group名称,这样就可以将Checkbox挂靠到CheckboxGroup下,剩下的就是给各个组件添加margin、fontSize等通用属性了,不清楚各个组件有哪些属性的请自行查阅组件参考,具体代码如下:
```ts
@Component
struct CheckboxDemo{
build(){
Column(){
Flex({justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center}){
// 将CheckboxGroup命名为'fruit_list'
CheckboxGroup({group: 'fruit_list'})
.selectedColor('#007DFF')
Text('水果清单')
.margin({right:20})
.fontSize(14)
.lineHeight(20)
.fontColor('#182431')
.fontWeight(FontWeight.Bold)
}
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center}){
// 通过group参数将Checkbox挂到CheckboxGroup下
Checkbox({name:'苹果',group:'fruit_list'})
.selectedColor('#007DFF')
Text('苹果')
.margin({right:20})
.fontSize(14)
.lineHeight(20)
.fontColor('#182431')
.fontWeight(500)
}
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center}){
Checkbox({name:'菠萝',group:'fruit_list'})
.selectedColor('#007DFF')
Text('菠萝')
.margin({right:20})
.fontSize(14)
.lineHeight(20)
.fontColor('#182431')
.fontWeight(500)
}
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center}){
Checkbox({name:'柚子',group:'fruit_list'})
.selectedColor('#007DFF')
Text('柚子')
.margin({right:20})
.fontSize(14)
.lineHeight(20)
.fontColor('#182431')
.fontWeight(500)
}
Button('删除')
.margin({top:20,left:35})
.fontSize(15)
.padding({top:5,bottom:5,left:15,right:15})
}
}
}
```
我们再来看下效果,发现多选框的布局已经正常了:
![checkbox-after-improve](figures/checkbox-after-improve.PNG)
2. 简化代码。
当前代码重复性很高,包含Checkbox的三个Flex的结构完全一样,我们可以简化一下。把重复的结构通过@Builder抽取出来作为一个自定义组件,用到的地方进行引用即可;每个Flex呈现的内容不同,那就将不同的内容作为参数传入。具体代码如下:
```ts
@Component
struct CheckboxDemo{
// flexNameList存储checkbox选项的文本内容;使用@State修饰后,flexNameList发生变化,UI会同步刷新
@State flexNameList:string[] = ['苹果','菠萝','柚子']
@Builder
// 将重复内容封装成flexItem,通过参数checkboxName为Text组件传入显示文本,通过groupName绑定CheckboxGroup
flexItem(checkboxName:string,groupName:string){
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Checkbox({ name:checkboxName, group:groupName})
.selectedColor('#007DFF')
Text(checkboxName)
.margin({right:20})
.fontSize(14)
.lineHeight(20)
.fontColor('#182431')
.fontWeight(500)
}.margin({ left: 36 })
}
build(){
Column(){
Flex({justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center}){
CheckboxGroup({group: 'fruit_list'})
.selectedColor('#007DFF')
Text('水果清单')
.margin({right:20})
.fontSize(14)
.lineHeight(20)
.fontColor('#182431')
.fontWeight(FontWeight.Bold)
}
// 通过ForEach遍历flexNameList循环渲染生成UI
ForEach(this.flexNameList,(item:any)=>{
// 引用封装的flexItem模板
this.flexItem(item,'fruit_list')
})
Button('删除')
.margin({top:20,left:35})
.fontSize(15)
.padding({top:5,bottom:5,left:15,right:15})
}.alignItems(HorizontalAlign.Center)
}
}
```
3. 添加删除逻辑。
本例中是通过以下方式实现删除操作的:将选中的水果项从flexNameList中删除(为方便展示,本文直接将数据存储在数组中,实际开发需要对接数据库),由于flexNameList被@State修饰,所以其发生变化时会重新执行Build(),从而完成UI刷新,展示删除后的选项。
要实现上述逻辑,首先需要获取到被选中的水果项。这里可以通过CheckboxGroup的onChange回调获取,当选项的状态发生变化时,会触发回调并返回各选项的选中状态。
具体代码如下:
```ts
@Component
struct CheckboxDemo{
...
// itemStatus用来存储各选项的选中状态
private itemStatus: CheckboxGroupResult
...
build(){
Column(){
Flex({justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center}){
CheckboxGroup({group: 'fruit_list'})
.selectedColor('#007DFF')
// 选项状态发生变化时触发onChange回调,各选项的选中状态储存在itemName中并返回,通过itemStatus.name可以获取到被选中的选项列表
.onChange((itemName: CheckboxGroupResult) => {
this.itemStatus = itemName
})
...
}.alignItems(HorizontalAlign.Center)
}
}
```
将各选项的选中状态存储到itemStatus后,我们就可以通过Button触发删除操作了。当点击删除按钮时,触发删除操作,所以给Button添加onClick事件,并添加删除逻辑。代码如下:
```ts
@Component
struct CheckboxDemo{
......
// itemStatus用来存储各选项的选中状态
private itemStatus: CheckboxGroupResult
......
build(){
Column(){
Flex({justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center}){
CheckboxGroup({group: 'fruit_list'})
.selectedColor('#007DFF')
// 选项状态发生变化时触发onChange回调,各选项的选中状态储存在itemName中并返回,通过itemStatus.name可以获取到被选中的选项列表
.onChange((itemName: CheckboxGroupResult) => {
this.itemStatus = itemName
})
......
Button('删除')
.margin({top:20,left:35})
.fontSize(15)
.padding({top:5,bottom:5,left:15,right:15})
// 点击触发删除操作
.onClick(()=>{
// 被选中的项存储在this.itemStatus.name列表中
for(let i of this.itemStatus.name){
// 从flexNameList中删除被选中的项,刷新UI
this.flexNameList.splice(this.flexNameList.indexOf(i),1)
}
})
}.alignItems(HorizontalAlign.Center)
}
}
```
4. 添加删除确认框。
使用promptAction模块调用showDialog方法弹出对话框,然后将删除操作绑定到对话框的确定按钮,具体代码如下:
```ts
// 导入promptAction模块
import promptAction from '@ohos.promptAction';
@Component
struct CheckboxDemo{
......
// itemStatus用来存储各选项的选中状态
private itemStatus: CheckboxGroupResult
......
build(){
Column(){
Flex({justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center}){
CheckboxGroup({group: 'fruit_list'})
.selectedColor('#007DFF')
// 选项状态发生变化时触发onChange回调,各选项的选中状态储存在itemName中并返回,通过itemStatus.name可以获取到被选中的选项列表
.onChange((itemName: CheckboxGroupResult) => {
this.itemStatus = itemName
})
......
Button('删除')
.margin({top:20,left:35})
.fontSize(15)
.padding({top:5,bottom:5,left:15,right:15})
// 点击触发删除操作
.onClick(()=>{
// 调用对话框
promptAction.showDialog({
title:'',
message:'确定删除吗?',
buttons:[
{text:'取消', color:'#000000'},
{text:'确定', color:'#000000'}
]
})
// 用户选择通过data回传,当data.index为1时,用户选择确定,当data.index为0时,用户选择取消
.then(data=>{
// 当用户选择确定时,进行删除操作
if(data.index===1){
// 被选中的项存储在this.itemStatus.name列表中
for(let i of this.itemStatus.name){
// 从flexNameList中删除被选中的项,刷新UI
this.flexNameList.splice(this.flexNameList.indexOf(i),1)
}
}
})
})
}.alignItems(HorizontalAlign.Center)
}
}
```
## 完整代码
本例完整代码如下:
```ts
import promptAction from '@ohos.promptAction';
@Entry
@Component
struct CheckboxDemo{
@State flexNameList:string[] = ['苹果','菠萝','柚子']
private itemStatus:CheckboxGroupResult
@Builder
flexItem(checkboxName:string,groupName:string){
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Checkbox({ name:checkboxName, group:groupName})
.selectedColor('#007DFF')
Text(checkboxName)
.margin({right:20})
.fontSize(14)
.lineHeight(20)
.fontColor('#182431')
.fontWeight(500)
}.margin({ left: 36 })
}
build() {
Column() {
if (this.flexNameList.length != 0){
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
CheckboxGroup({ group: 'fruit_list' })
.selectedColor('#007DFF')
.onChange((itemName: CheckboxGroupResult) => {
this.itemStatus = itemName
})
Text('水果清单')
.margin({right:20})
.fontSize(14)
.lineHeight(20)
.fontColor('#182431')
.fontWeight(FontWeight.Bold)
}.margin({top:150})
ForEach(this.flexNameList,(item:any)=>{
this.flexItem(item,'fruit_list')
})
Button("删除")
.margin({top:20,left:35})
.fontSize(15)
.padding({top:5,bottom:5,left:15,right:15})
.onClick(()=>{
promptAction.showDialog({
title:'',
message:'确定删除吗?',
buttons:[
{text:'取消', color:'#000000'},
{text:'确定', color:'#000000'}
]
})
.then(data=>{
if(data.index===1){
for(let i of this.itemStatus.name){
this.flexNameList.splice(this.flexNameList.indexOf(i),1)
}
}
})
})
}else{
}
}.alignItems(HorizontalAlign.Center)
}
}
```
## 参考
- [ChecckboxGroup](../application-dev/reference/arkui-ts/ts-basic-components-checkboxgroup.md)
- [Checkbox](../application-dev/reference/arkui-ts/ts-basic-components-checkbox.md)
- [Flex](../application-dev/reference/arkui-ts/ts-container-flex.md)
- [Button](../application-dev/reference/arkui-ts/ts-basic-components-button.md)
- [ohos.promptAction (弹窗)](../application-dev/reference/apis/js-apis-promptAction.md)
- [ForEach循环渲染](../application-dev/quick-start/arkts-rendering-control-foreach.md)
- [@State状态管理](../application-dev/quick-start/arkts-state.md)
- [@Builder动态构建UI元素](../application-dev/quick-start/arkts-builder.md)
\ No newline at end of file
# 如何转换图片格式
## 场景说明
当我们获取到图片或者视频的缩略图后,返回的是pixelMap,此时有开发者会有疑问如何将pixelMap转换成jpeg等其他格式的图片,其实使用image类中的packing方法就可以将pixelMap重新打包成新的格式(当前只支持jpeg,webp格式),再使用文件管理就可以将图片存入到应用的沙箱路径。本例即为大家介绍如何完成图片格式转换。
## 运行环境
本例基于以下环境开发,开发者也可以基于其他适配的版本进行开发:
- IDE: DevEco Studio 4.0 Beta1
- SDK: Ohos_sdk_public 4.0.7.5 (API Version 10 Beta1)
## 效果呈现
本例最终实现效果为:将工程资源文件中png格式的图片转换为jpg格式,并保存在设备中。由于本例不涉及UI讲解,所以不在此提供UI效果。
## 实现思路
本例中完成图片格式转换包含三个关键步骤,相关步骤及实现方案如下:
- 获取到要转换图片的PixelMap数据:使用image的createPixelMap方法获取到图片的PixelMap数据。
- 将图片的PixelMap重新打包转换为其他格式:使用packing方法进行打包,打包时可以设置格式、压缩质量等。
- 将重新打包好的图片保存到应用目录:使用图库选择器photoViewPicker的相关功能以及file读写操作完成图片的保存。
## 开发步骤
由于本例重点讲解图片格式的转换,所以开发步骤会着重讲解相关实现,不相关的内容不做介绍,全量代码可参考完整代码章节。
1. 获取要转换图片的PixelMap数据。
先通过上下文context获取到资源管理器resourceManager,然后通过资源管理器获取到图片数据,然后获取图片的ArrayBuffer,最后通过ArrayBuffer创建imageSource,获取到pixelMap,完成图片解码。
具体代码如下:
```ts
import common from '@ohos.app.ability.common';
@Entry
@Component
struct Index {
...
context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext
...
async getPixelMap(){
// 获取resourceManager资源管理
const resourceMgr = this.context.resourceManager
// 获取rawfile文件夹下imagetransfer.PNG的ArrayBuffer
const fileData = await resourceMgr.getMediaContent($r('app.media.imagetransfer'))
const buffer = fileData.buffer
// 创建imageSource
const imageSource = image.createImageSource(buffer)
// 获取PixelMap
const pixelMap = await imageSource.createPixelMap()
return pixelMap
}
...
}
```
2. 将图片的PixelMap重新打包转换为其他格式。
先通过createImagePacker构建ImagePacker实例,再通过该实例调用packing方法进行打包,打包时传入获取到的PixelMap数据及重新打包的图片格式等相关配置信息。
具体代码如下:
```ts
...
@State src:PixelMap = undefined
...
// 页面加载前将获取到的图片PixelMap数据赋值给状态变量src
async aboutToAppear() {
this.src = await this.getPixelMap()
}
...
// 创建ImagePacker实例
let imagePackerApi = image.createImagePacker();
let options = {
// 设置重新打包的图片格式
format: 'image/jpeg',
quality: 98
};
// 打包时传入图片的PixelMap:src和图片打包选项:option,异步获取打包后的数据data
imagePackerApi.packing(this.src, options).then((data) => {
console.log('Succeeded in packing the image.');
}).catch(error => {
console.log('Failed to pack the image..');
....
})
```
3. 将重新打包好的图片保存到应用目录。
使用图库选择器photoViewPicker保存文件,保存时可以在保存界面选择保存路径并设定文件名。此时保存的是空文件,然后再使用file将重新打包的图片数据写入保存的文件中,保存完成后我们便可以在保存路径下找到转换格式后的图片文件了。
具体代码如下:
```ts
...
// 打包时传入图片的pixelmap:src和图片打包选项:option,异步获取打包后的数据data
imagePackerApi.packing(this.src, options).then((data) => {
// 创建文件管理器保存选项实例
let photoSaveOptions = new picker.PhotoSaveOptions();
// 保存文件名(可选)
photoSaveOptions.newFileNames = ["imageTransfer.jpg"];
let photoViewPicker = new picker.PhotoViewPicker();
// 保存时传入保存的文件名:photoSaveOptions
photoViewPicker.save(photoSaveOptions)
.then((photoSaveResult) => {
setTimeout(() => {
// 获取到保存文件的URI,后续进行文件读取等操作
this.uri = photoSaveResult[0];
fs.open(this.uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE).then((file) => {
// 将图片打包数据data写入保存的文件
fs.write(file.fd, data).then((number) => {
console.info("foo imagetest: write data to file succeed and size is:" + number);
}).catch((err) => {
console.info("foo imagetest: write data to file failed with error:" + err);
});
// 完成文件写入后,关闭文件
fs.close(file, (err) => {
if (err) {
console.info("close file failed with error message: " + err.message + ", error code: " + err.code);
} else {
console.info("close file success");
}
});
}).catch((err) => {
console.info("foo open file failed with error message: " + err.message + ", error code: " + err.code);
});
}, 200)
})
.catch((err) => {
console.error('PhotoViewPicker.save failed with err: ' + err);
})
})
...
```
## 完整代码
本例完整代码如下:
```ts
import image from '@ohos.multimedia.image';
import fs from '@ohos.file.fs';
import common from '@ohos.app.ability.common';
import picker from '@ohos.file.picker';
@Entry
@Component
struct Index {
@State src:PixelMap = undefined
context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext
private uri = null
// 页面加载前将获取到的图片PixelMap数据赋值给状态变量src
async aboutToAppear() {
this.src = await this.getPixelMap()
}
async getPixelMap(){
// 获取resourceManager资源管理
const resourceMgr = this.context.resourceManager
// 获取rawfile文件夹下httpimage.PNG的ArrayBuffer
const fileData = await resourceMgr.getMediaContent($r('app.media.contact6'))
const buffer = fileData.buffer
// 创建imageSource
const imageSource = image.createImageSource(buffer)
// 创建PixelMap
const pixelMap = await imageSource.createPixelMap()
return pixelMap
console.log('pixelMap ' + JSON.stringify(this.src.getPixelBytesNumber()))
}
build() {
Row() {
Column() {
Button('转换图片格式:png->jpeg')
.onClick(() => {
// 创建ImagePacker实例
let imagePackerApi = image.createImagePacker();
// 设置重新打包的图片格式,及图片压缩质量
let options = {
format: 'image/jpeg',
quality: 98
};
// 打包时传入图片的pixelmap:src和图片打包选项:option,异步获取打包后的数据data
imagePackerApi.packing(this.src, options).then((data) => {
// 创建文件管理器保存选项实例
let photoSaveOptions = new picker.PhotoSaveOptions();
// 保存文件名(可选)
photoSaveOptions.newFileNames = ["imageTransfer.jpg"];
let photoViewPicker = new picker.PhotoViewPicker();
// 保存时传入保存的文件名:photoSaveOptions
photoViewPicker.save(photoSaveOptions)
.then((photoSaveResult) => {
console.log('foo start')
setTimeout(() => {
// 获取到图片的URI后进行文件读取等操作
this.uri = photoSaveResult[0];
fs.open(this.uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE).then((file) => {
// 将图片打包数据data写入保存的文件
fs.write(file.fd, data).then((number) => {
console.info("foo imagetest: write data to file succeed and size is:" + number);
}).catch((err) => {
console.info("foo imagetest: write data to file failed with error:" + err);
});
// 完成文件写入后,关闭文件
fs.close(file, (err) => {
if (err) {
console.info("close file failed with error message: " + err.message + ", error code: " + err.code);
} else {
console.info("close file success");
}
});
}).catch((err) => {
console.info("foo open file failed with error message: " + err.message + ", error code: " + err.code);
});
}, 200)
})
.catch((err) => {
console.error('PhotoViewPicker.save failed with err: ' + err);
})
})
})
}
.width('100%')
}
.height('100%')
}
}
```
## 参考
- [@ohos.multimedia.image (图片处理)](../application-dev/reference/apis/js-apis-image.md)
- [@ohos.file.fs (文件管理)](../application-dev/reference/apis/js-apis-file-fs.md)
- [@ohos.file.picker (选择器)](../application-dev/reference/apis/js-apis-file-picker.md)
\ No newline at end of file
此差异已折叠。
# 用户首选项的基本使用
## 场景说明
用户首选项为应用提供Key-Value键值型的数据处理能力,支持应用持久化轻量级数据,并对其修改和查询。当用户希望有一个全局唯一存储的地方,可以采用用户首选项来进行存储。用户首选项会将该数据缓存在内存中,当用户读取的时候,能够快速从内存中获取数据。用户首选项会随着存放的数据量越多而导致应用占用的内存越大,因此,用户首选项不适合存放过多的数据,适用的场景一般为应用保存用户的个性化设置(屏幕亮度,是否开启夜间模式)等。
本例以一个小示例为大家介绍如何使用用户首选项对数据进行存储、获取、删除。
## 效果呈现
本例最终效果如下:
![preference-storage](figures/preference-storage.gif)
## 运行环境
本例基于以下环境开发,开发者也可以基于其他适配的版本进行开发:
- IDE: DevEco Studio 4.0 Beta1
- SDK: Ohos_sdk_public 4.0.7.5 (API Version 10 Beta1)
## 实现思路
本例以设置屏幕亮度为例演示如何使用用户首选项管理数据,主要特性及实现方式如下:
- 当用户在文本框输入数据后,点击保存数据,用户首选项将数据缓存在内存中:通过dataPreferences类的getPreferences方法获取用户首选项实例,然后通过该实例调用put方法将数据写入内存。
- 当用户点击读取数据时,用户首选项将数据从内存中读取出来并显示在输入框中:通过用户首选项实例调用get方法获取到保存的数据,显示在输入框中。
- 当用户点击删除数据时,用户首选项将数据从内存中删除,用户无法继续读取数据:通过用户首选项实例调用delete方法删除保存的数据。
> ![icon-note.gif](../device-dev/public_sys-resources/icon-note.gif) **说明:**
> 用户首选项的使用需要注意以下几点:
> - Key键为string类型,要求非空且长度不超过80个字节。
> - 如果Value值为string类型,请使用UTF-8编码格式,可以为空,不为空时长度不超过8192个字节。
> - 内存会随着存储数据量的增大而增大,所以存储的数据量应该是轻量级的,建议存储的数据不超过一万条,否则会在内存方面产生较大的开销。
## 开发步骤
由于本例重点讲解用户首选项的数据管理操作,所以开发步骤会着重讲解如何通过用户首选项完成数据的存储、读取和删除,全量代码可参考完整代码章节。
1. 首先自定义一个用户首选项类,根据业务封装相关方法方便后续调用。
其中包含数据处理的方法,用于完成数据的存储、读取和删除操作。用户首选项接口的使用方式主要在这部分呈现,需要重点关注。
具体代码如下:
```ts
import dataPreferences from '@ohos.data.preferences';
import promptAction from '@ohos.promptAction';
import ScreenBrightness from '../common/bean/Brightness';
let context = getContext(this);
let preference: dataPreferences.Preferences = null;
// 自定义用户首选项类
class PreferenceModel {
private brightness:ScreenBrightness
// 创建用户首选项实例preference
async getPreferencesFromStorage() {
try {
preference = await dataPreferences.getPreferences(context, 'setting.db');
} catch (err) {
Logger.error('[PreferenceModel]', `Failed to get preferences, Cause: ${err}`);
}
}
// 删除数据,调用dataPreferences的deletePreferences接口
async deletePreferences() {
try {
await dataPreferences.deletePreferences(context, 'setting.db');
} catch(err) {
Logger.error('[PreferenceModel]', `Failed to delete preferences, Cause: ${err}`);
};
preference = null;
this.showToastMessage($r('app.string.delete_success_msg'));
}
// 保存数据
async putPreference(screenBrightness:ScreenBrightness) {
if (preference === null) {
await this.getPreferencesFromStorage();
}
// 将用户输入的亮度数据保存到preference,调用用户首选项实例的put接口
try {
await preference.put('screenBrightness', JSON.stringify(screenBrightness));
} catch (err) {
Logger.error('[PreferenceModel]', `Failed to put value, Cause: ${err}`);
}
// 使用flush方法将preferences实例的数据存储到持久化文件,调用用户首选项实例的flush接口
await preference.flush();
}
// 获取数据,调用用户首选项实例的get接口
async getPreference() {
let screenBrightness = '';
if (preference === null) {
await this.getPreferencesFromStorage();
}
try {
screenBrightness = <string> await preference.get('screenBrightness', '');
} catch (err) {
Logger.error('[PreferenceModel]', `Failed to get value, Cause: ${err}`);
}
// 如果判断数据为空则提示用户先输入数据
if (screenBrightness === '') {
this.showToastMessage($r('app.string.data_is_null_msg'));
return;
}
this.showToastMessage($r('app.string.read_success_msg'));
return JSON.parse(screenBrightness);
}
// 校验用户输入是否为空
checkData(screenBrightness:ScreenBrightness) {
if (screenBrightness.brightSwitch === '' || screenBrightness.defaultValue === '') {
this.showToastMessage($r('app.string.fruit_input_null_msg'));
return true;
}
return false;
}
// 点击保存按钮保存数据
writeData(screenBrightness:ScreenBrightness) {
// Check whether the data is null.
let isDataNull = this.checkData(screenBrightness);
if (isDataNull) {
return;
}
// The data is inserted into the preferences database if it is not empty.
this.putPreference(screenBrightness);
this.showToastMessage($r('app.string.write_success_msg'));
}
// 消息弹框
showToastMessage(message: Resource) {
promptAction.showToast({
message: message,
duration: 3000
});
};
}
```
2. UI中主要包含两大部分:文本和输入框,按钮。将这两部分分别抽取为子组件,在主页中进行调用。具体代码如下:
文本和输入框子组件:
```ts
import ScreenBrightness from '../common/bean/Brightness';
@Component
export default struct TextItemComponent {
private textResource: Resource;
private placeholderResource: Resource;
private marginBottom: string;
private marginTop: string;
private textInputType: InputType;
private textFlag: number;
@Link screenBrightness: ScreenBrightness;
private textInputCallBack: (value: string) => void;
aboutToAppear() {
if (this.textFlag === 0) {
this.marginTop = '8%';
this.marginBottom = '4%';
this.textInputType = InputType.Normal;
} else {
this.marginBottom = '321vp';
this.textInputType = InputType.Number;
}
}
build() {
Column() {
// 文本
Text(this.textResource)
.fontSize(25)
.height('3.2%')
.width('100%')
.fontColor("#182431")
.letterSpacing('1.58')
.fontWeight(500)
.margin({
bottom: '2%',
left: '7%',
top: this.marginTop
})
// 输入框
TextInput({
placeholder: this.placeholderResource,
text: this.textFlag === 0 ? (this.screenBrightness.brightSwitch) : (this.screenBrightness.defaultValue)
})
.placeholderFont({ size: 20, weight: 500 })
.placeholderColor("#BDC1C4")
.caretColor(Color.Blue)
.type(this.textInputType)
.height('7%')
.width('93%')
.margin({ bottom: this.marginBottom })
.fontSize(20)
.fontColor("#182431")
.fontWeight(500)
.backgroundColor("#FFFFFF")
.onChange((value: string) => {
this.textInputCallBack(value);
})
}
}
}
```
按钮子组件:
```ts
import PreferenceModel from '../model/PreferenceModel';
import ButtonItemData from '../common/bean/ButtonItemData';
import ScreenBrightness from '../common/bean/Brightness';
@Component
export default struct ButtonComponent {
private buttonItemValues: Array<ButtonItemData> = this.getButtonItemValues();
@Link screenBrightness: ScreenBrightness;
build() {
Column() {
ForEach(this.buttonItemValues, (item) => {
Button(item.text, { type: ButtonType.Capsule, stateEffect: true })
.backgroundColor("#E8A027")
.width('87%')
.height('6%')
.fontWeight(500)
.fontSize(20)
.margin({ bottom: '24vp' })
.onClick(() => {
item.clickMethod();
})
}, item => JSON.stringify(item))
}
}
// 在foreach中渲染Button组件时传入不同按钮的参数
getButtonItemValues() {
let values: Array<ButtonItemData> = [
new ButtonItemData(
'保存数据',
() => {
// 调用保存方法
PreferenceModel.writeData(this.screenBrightness);
}
),
new ButtonItemData(
'读取数据',
() => {
// 调用读取方法
PreferenceModel.getPreference().then(resultData => {
this.screenBrightness = resultData;
console.info('dbdata is '+JSON.stringify(resultData))
});
}
),
new ButtonItemData(
'删除数据',
() => {
// 调用删除方法
PreferenceModel.deletePreferences();
// 数据删除后将相关内容置为空
this.screenBrightness.brightSwitch = '';
this.screenBrightness.defaultValue = ''
}
)
];
return values;
}
}
```
3. 构建首页UI。
在页面生命周期的aboutToAppear中调用自定义首选项类的getPreference方法获取到保存的数据,这样如果用户之前有保存数据的话,进入应用中就可以显示之前保存的数据。
具体代码如下:
```ts
import PreferenceModel from '../model/PreferenceModel';
import ButtonComponent from '../view/ButtonComponent';
import TextItemComponent from '../view/TextItemComponent';
import ScreenBrightness from '../common/bean/Brightness';
@Entry
@Component
struct Setting {
@State screenBrightness: ScreenBrightness = new ScreenBrightness('', '');
build() {
Column() {
// 亮度调节文本及文本框
TextItemComponent({
textResource: $r('app.string.brightness_text'),
placeholderResource: $r('app.string.brightness_placeholder'),
textFlag: 0,
screenBrightness: $screenBrightness,
textInputCallBack: (value) => {
this.screenBrightness.brightSwitch = value;
}
})
// 设定值文本及文本框
TextItemComponent({
textResource: $r('app.string.defaultValue_text'),
placeholderResource: $r('app.string.defaultValue_placeholder'),
textFlag: 1,
screenBrightness: $screenBrightness,
textInputCallBack: (value) => {
this.screenBrightness.defaultValue = value;
}
})
// 按钮
ButtonComponent({ screenBrightness: $screenBrightness })
}
.width('100%')
.height('100%')
.backgroundColor("#F1F3F5")
}
async aboutToAppear() {
await PreferenceModel.getPreferencesFromStorage();
// 获取到之前保存的数据,显示在输入框中
PreferenceModel.getPreference().then(resultData => {
this.screenBrightness = resultData;
});
}
}
```
## 完整代码
由于开发步骤中已经展示了大部分完整代码,此处补充前文中未呈现的两个数据类:
亮度数据类:
```ts
export default class ScreenBrightness {
// 亮度调节
brightSwitch: string;
// 设定值
defaultValue: string;
constructor(brightSwitch: string, defaultValue: string) {
this.brightSwitch = brightSwitch;
this.defaultValue = defaultValue;
}
}
```
按钮数据类:
```ts
export default class ButtonItemData {
// 按钮文本
text: string;
// 按钮点击事件触发的方法
clickMethod: () => void;
constructor(text: string, clickMethod: () => void) {
this.text = text;
this.clickMethod = clickMethod;
}
}
```
## 参考
- [@ohos.data.preferences (用户首选项)](../application-dev/reference/apis/js-apis-data-preferences.md)
- [通过用户首选项实现数据持久化](../application-dev/database/data-persistence-by-preferences.md)
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册