#星计划# 从前端角度学HarmonyOS基础篇 原创
一、ArkTS基础
1装饰器
1.1 @Component 装饰器
自定义组件
配合struct关键字
1.2 @Entry 装饰器
页面入口 页面首先呈现的@Entry装饰的组件,一个页面有且只有一个
1.3 @State装饰器
装饰的变量是组件内部的状态数据,当这些状态数据被修改时,将会调用所在组件的build方法进行UI刷新
1.4 @Link装饰器
装饰的变量可以和父组件的state变量形成双向数据绑定<br />Link变量不能在组件内部进行初始化<br />父组件的变量加上$ 表示传递的是引用 而不能用this。
1.5 @Builder装饰器
装饰的方法用于定义组件的声明式UI描述,在一个自定义组件内快速生成多个布局内容<br />来修饰一个函数,快速生成布局内容,从而可以避免重复的UI描述内容
1.6 @Prop装饰器
组件通信单向数据流,不需要要赋值
1.7 @Watch装饰器
@Link @Watch('onClickIndexChanged') clickIndex: number;
监听器,通过回调onClickIndexChanged 监听clickIndex 当clickIndex改变触发onClickIndexChanged方法
1.8 @Provide/@Consume装饰器
跨级双向绑定
@Provide('a') b: number = 0;
@Consume('a') c: number;
后代通过使用@Consume去获取父或上级@Provide提供的变量
1.8 @CustomDialog装饰器
修饰代码为自定义弹框 struct关键字 具体代码见组件管理
2.自定义组件
2.1生命周期
aboutToAppear() 创建<br />aboutToDisappear() 销毁
二、UIAbility
1.页面传参
import router from "@oho.router"
#传参
router.pushUrl({
url:"page/home"
params:{
id:1
}
})
#获取参数
router.getParams()?.["id"]
#返回
router.back()
#返回到指定页面
router.back({ url: 'pages/Index' });
2.生命周期
- Create状态,在UIAbility实例创建时触发,系统会调用onCreate回调。可以在onCreate回调中进行相关初始化操作。
例如用户打开电池管理应用,在应用加载过程中,在UI页面可见之前,可以在onCreate回调中读取当前系统的电量情况,用于后续的UI页面展示
- WindowStage用于管理窗口相关的内容,例如与界面相关的获焦/失焦、可见/不可见。
可以在onWindowStageCreate回调中,设置UI页面加载、设置WindowStage的事件订阅
在onWindowStageCreate(windowStage)中通过loadContent接口设置应用要加载的页面
例:正在打游戏的时候,有一个消息通知,游戏应用就从获焦切换到了失焦状态,消息应用切换到了获焦状态。对于消息应用,在onWindowStageCreate回调中,会触发获焦的事件回调,可以进行设置消息应用的背景颜色、高亮等操作。
...
onWindowStageCreate(windowStage: window.WindowStage) {
// 设置UI页面加载
...
windowStage.loadContent('pages/Index', (err, data) => {
...
});
}
...
3.Foreground和Background状态,分别在UIAbility切换至前台或者切换至后台时触发。<br />分别对应于onForeground回调和onBackground回调。<br />onForeground回调,在UIAbility的UI页面可见之前,即UIAbility切换至前台时触发。可以在onForeground回调中申请系统需要的资源,或者重新申请在onBackground中释放的资源。<br />onBackground回调,在UIAbility的UI页面完全不可见之后,即UIAbility切换至后台时候触发。可以在onBackground回调中释放UI页面不可见时无用的资源,或者在此回调中执行较为耗时的操作,例如状态保存等。
例如用户打开地图应用查看当前地理位置的时候,假设地图应用已获得用户的定位权限授权。在UI页面显示之前,可以在onForeground回调中打开定位功能,从而获取到当前的位置信息。
4.在UIAbility实例销毁之前,则会先进入onWindowStageDestroy回调,我们可以在该回调中释放UI页面资源。
例如在onWindowStageCreate中设置的获焦/失焦等WindowStage订阅事件
5.Destroy状态,在UIAbility销毁时触发。可以在onDestroy回调中进行系统资源的释放、数据的保存等操作
例如用户使用应用的程序退出功能,会调用UIAbilityContext的terminalSelf()方法,从而完成UIAbility销毁。或者用户使用最近任务列表关闭该UIAbility实例时,也会完成UIAbility的销毁。
3.UIAbility的启动模式
singleton(单实例模式)
当用户打开浏览器或者新闻等应用,并浏览访问相关内容后,回到桌面,再次打开该应用,显示的仍然是用户当前访问的界面。
multiton(多实例模式)
用户在使用分屏功能时,希望使用两个不同应用(例如备忘录应用和图库应用)之间进行分屏,也希望能使用同一个应用(例如备忘录应用自身)进行分屏。
例如微信和小程序单独分开 最近任务可以看到两个应用
<br /> specified(指定实例模式)
用户打开文档应用,从文档应用中打开一个文档内容,回到文档应用,继续打开同一个文档,希望打开的还是同一个文档内容;以及在文档应用中新建一个新的文档,每次新建文档,希望打开的都是一个新的空白文档内容
三、常用基础组件
使用资源引用类型
定义通用变量 entry/src/main/resources下的资源文件中
{
"string": [
{
"name": "login_text",
"value": "登录"
}
]
}
type代表资源类型(或资源的存放位置),可以取“color”、“float”、“string”、“plural”、“media”;name代表资源命名,由开发者定义资源时确定。
使用
$r('app.string.login_text')
1.Image
Image($r("app.media.icon"))
.width(100)
.height(100)
地址可以是网络图片 ,单需要在在module.json5文件中requestPermissions字段申明网络访问权限
{
"module" : {
"requestPermissions":[
{
"name": "ohos.permission.INTERNET"
}
]
}
}
2.Text
Text('HarmonyOS')
3.TextInput
TextInput({ placeholder: '请输入密码' })
.fontColor(Color.Blue)
.fontSize(20)
.placeholderColor(0x999999)
.placeholderFont({ size: 20, weight: FontWeight.Medium, family: 'cursive', style: FontStyle.Italic })
.type(InputType.Password) 密码框
- Normal:基本输入模式。支持输入数字、字母、下划线、空格、特殊字符
- Password:密码输入模式。
- Email:e-mail地址输入模式。
- Number:纯数字输入模式。
获取输入文本
TextInput({ placeholder: '请输入账号' })
.caretColor(Color.Blue)
.onChange((value: string) => {
this.text = value
})
4.Button
Button('登录', { type: ButtonType.Capsule, stateEffect: true })
第一个参数为按钮文字
按钮样式:
- Capsule:胶囊型按钮(圆角默认为高度的一半)。
- Circle:圆形按钮。
- Normal:普通按钮(默认不带圆角)。
点击事件为onClick
包含按钮图片:
Button({ type: ButtonType.Circle, stateEffect: true }) {
Image($r('app.media.icon_delete'))
.width(30)
.height(30)
}
.width(55)
.height(55)
.backgroundColor(0x317aff)
5.LoadingProgress
loading效果 全屏
LoadingProgress()
.color(Color.Blue)
.height(60)
.width(60)
6.Video
Video(value: {src?: string | Resource, currentProgressRate?: number | string |PlaybackSpeed, previewUri?: string |PixelMap | Resource, controller?: VideoController})
//使用本地文件案例
import mediaLibrary from '@ohos.multimedia.mediaLibrary';
async queryMediaVideo() {
let option = {
// 根据媒体类型检索
selections: mediaLibrary.FileKey.MEDIA_TYPE + '=?',
// 媒体类型为视频
selectionArgs: [mediaLibrary.MediaType.VIDEO.toString()]
};
let media = mediaLibrary.getMediaLibrary(getContext(this));
// 获取资源文件
const fetchFileResult = await media.getFileAssets(option);
// 以获取的第一个文件为例获取视频地址
let fileAsset = await fetchFileResult.getFirstObject();
this.source = fileAsset.uri
}
- src表示视频播放源的路径,可以支持本地视频路径和网络路径。网络地址需要在module.json5文件中requestPermissions字段申明网络访问权限(同图片),本地视频案例如上
- currentProgressRate表示视频播放倍速,其参数类型为number,取值支持0.75,1.0,1.25,1.75,2.0,默认值为1.0倍速
- previewUri表示视频未播放时的预览图片路径;
- controller表示视频控制器。
video属性
muted | 是否静音。默认值:false |
---|---|
autoPlay | 是否自动播放。默认值:false |
controls | 控制视频播放的控制栏是否显示。默认值:true,使用自定义控制器需要关闭 |
objectFit | 设置视频显示模式。默认值:Cover。六种模式Contain、Cover、Auto、Fill、ScaleDown、None |
loop | 是否单个视频循环播放。默认值:false |
回调事件
onStart(event:() => void) | 播放时触发该事件。 |
---|---|
onPause(event:() => void) | 暂停时触发该事件。 |
onFinish(event:() => void) | 播放结束时触发该事件。 |
onError(event:() => void) | 播放失败时触发该事件。 |
onPrepared(callback:(event?: { duration: number }) => void) | 视频准备完成时触发该事件,通过duration可以获取视频时长,单位为s。 |
onSeeking(callback:(event?: { time: number }) => void) | 操作进度条过程时上报时间信息,单位为s。 |
onSeeked(callback:(event?: { time: number }) => void) | 操作进度条完成后,上报播放时间信息,单位为s。 |
onUpdate(callback:(event?: { time: number }) => void) | 播放进度变化时触发该事件,单位为s,更新时间间隔为250ms。 |
onFullscreenChange(callback:(event?: { fullscreen: boolean }) => void) | 在全屏播放与非全屏播放状态之间切换时触发该事件 |
|
Video({ ... })
.onUpdate((event) => {
this.currentTime = event.time;
this.currentStringTime = changeSliderTime(this.currentTime); //更新事件
})
.onPrepared((event) => {
prepared.call(this, event); //准备事件
})
.onError(() => {
prompt.showToast({
duration: COMMON_NUM_DURATION, //播放失败事件
message: MESSAGE
});
...
})
自定义控制器
@Component
export struct VideoSlider {
...
build() {
Row(...) {
Image(...)
Text(...)
Slider(...)
Text(...)
}
...
}
}
自定义控制器容器内嵌套了视频播放时间Text组件、滑动器Slider组件以及视频总时长Text组件 3个横向排列的组件
两个Text组件显示的时长是由Slider组件的onChange(callback: (value: number, mode: SliderChangeMode) => void)回调事件来进行传递的,而Text组件的数值与视频播放进度数值value则是通过@Provide与 @Consume装饰器进行的数据联动
7.弹框
AlertDialog、ActionSheet、DatePickerDialog、TimePickerDialog、TextPickerDialog、自定义
警告弹窗
Button('点击显示弹窗')
.onClick(() => {
AlertDialog.show(
{
title: '删除联系人', // 标题
message: '是否需要删除所选联系人?', // 内容
autoCancel: false, // 点击遮障层时,是否关闭弹窗。
alignment: DialogAlignment.Bottom, // 弹窗在竖直方向的对齐方式
offset: { dx: 0, dy: -20 }, // 弹窗相对alignment位置的偏移量
primaryButton: {
value: '取消',
action: () => {
console.info('Callback when the first button is clicked');
}
},
secondaryButton: {
value: '删除',
fontColor: '#D94838',
action: () => {
console.info('Callback when the second button is clicked');
}
},
cancel: () => { // 点击遮障层关闭dialog时的回调
console.info('Closed callbacks');
}
}
)
})
//构建只包含一个操作按钮的确认弹窗,使用confirm响应操作按钮回调
AlertDialog.show(
{
title: '提示',
message: '提示信息',
autoCancel: true,
alignment: DialogAlignment.Bottom,
offset: { dx: 0, dy: -20 },
confirm: {
value: '确认',
action: () => {
console.info('Callback when confirm button is clicked');
}
},
cancel: () => {
console.info('Closed callbacks')
}
}
)
文本选择弹窗
@Entry
@Component
struct TextPickerDialogDemo {
@State select: number = 2;
private fruits: string[] = ['苹果', '橘子', '香蕉', '猕猴桃', '西瓜'];
build() {
Column() {
Button("TextPickerDialog")
.margin(20)
.onClick(() => {
TextPickerDialog.show({
range: this.fruits, // 设置文本选择器的选择范围
selected: this.select, // 设置初始选中项的索引值。
onAccept: (value: TextPickerResult) => { // 点击弹窗中的“确定”按钮时触发该回调。
// 设置select为按下确定按钮时候的选中项index,这样当弹窗再次弹出时显示选中的是上一次确定的选项
this.select = value.index;
console.info("TextPickerDialog:onAccept()" + JSON.stringify(value));
},
onCancel: () => { // 点击弹窗中的“取消”按钮时触发该回调。
console.info("TextPickerDialog:onCancel()");
},
onChange: (value: TextPickerResult) => { // 滑动弹窗中的选择器使当前选中项改变时触发该回调。
console.info("TextPickerDialog:onChange()" + JSON.stringify(value));
}
})
})
}
.width('100%')
}
}
日期选择弹窗
@Entry
@Component
struct DatePickerDialogDemo {
selectedDate: Date = new Date("2010-1-1")
build() {
Column() {
Button("DatePickerDialog")
.margin(20)
.onClick(() => {
DatePickerDialog.show({
start: new Date("1900-1-1"), // 设置选择器的起始日期
end: new Date("2023-12-31"), // 设置选择器的结束日期
selected: this.selectedDate, // 设置当前选中的日期
lunar: false,
onAccept: (value: DatePickerResult) => { // 点击弹窗中的“确定”按钮时触发该回调
// 通过Date的setFullYear方法设置按下确定按钮时的日期,这样当弹窗再次弹出时显示选中的是上一次确定的日期
this.selectedDate.setFullYear(value.year, value.month, value.day)
console.info("DatePickerDialog:onAccept()" + JSON.stringify(value))
},
onCancel: () => { // 点击弹窗中的“取消”按钮时触发该回调
console.info("DatePickerDialog:onCancel()")
},
onChange: (value: DatePickerResult) => { // 滑动弹窗中的滑动选择器使当前选中项改变时触发该回调
console.info("DatePickerDialog:onChange()" + JSON.stringify(value))
}
})
})
}
.width('100%')
}
}
自定义弹窗
使用 饰器@CustomDialog申明
定定义:资源管理对象manager获取数据,并将数据封装到hobbyBeans
@CustomDialog
export default struct CustomDialogWidget {
@State hobbyBeans: HobbyBean[] = [];
@Link hobbies: string;
private controller: CustomDialogController;
aboutToAppear() {...}
setHobbiesValue(hobbyBeans: HobbyBean[]) {
let hobbiesText: string = '';
hobbiesText = hobbyBeans.filter((isCheckItem: HobbyBean) =>
isCheckItem?.isChecked)
.map((checkedItem: HobbyBean) => {
return checkedItem.label;
}).join(',');
this.hobbies = hobbiesText;
}
build() {
Column() {
Text($r('app.string.text_title_hobbies'))...
List() {
ForEach(this.hobbyBeans, (itemHobby: HobbyBean) => {
ListItem() {
Row() {
Text(itemHobby.label)...
Toggle({ type: ToggleType.Checkbox, isOn: false })...
.onChange((isCheck) => {
itemHobby.isChecked = isCheck;
})
}
}
}, itemHobby => itemHobby.label)
}
Row() {
Button($r("app.string.cancel_button"))...
.onClick(() => {
this.controller.close();
})
Button($r("app.string.definite_button"))...
.onClick(() => {
this.setHobbiesValue(this.hobbyBeans);
this.controller.close();
})
}
}
}
}
使用:
在自定义弹窗的使用页面HomePage中先定义一个变量hobbies,使用装饰器@State修饰,和自定义弹窗中的@Link 装饰器修饰的变量进行双向绑定。然后我们使用alignment和offset设置弹窗的位置在屏幕底部,并且距离底部20vp。最后我们在自定义组件TextCommonWidget的点击事件中,调用customDialogController的open方法,用于显示弹窗。
@Entry
@Component
struct HomePage {
customDialogController: CustomDialogController = new CustomDialogController({
builder: CustomDialogWidget({
onConfirm: this.setHobbiesValue.bind(this),
}),
alignment: DialogAlignment.Bottom,
customStyle: true,
offset: { dx: 0,dy: -20 }
});
setHobbiesValue(hobbyArray: HobbyBean[]) {...}
build() {
...
TextCommonWidget({
...
title: $r("app.string.title_hobbies"),
content: $hobby,
onItemClick: () => {
this.customDialogController.open();
}
})
...
}
}
8.RefreshComponent
自定义下拉组件
RefreshComponent({
headerStyle: RefreshHeaderStyle.CLOUD, // 头部样式设置
itemLayout: (): void => this.ContentBody(), // 刷新部件样式
displayHeight: (
px2vp(this.deviceDisplay.height) - DimensionUtil.getVp($r('app.float.file_index_title_height'))),
onRefresh: () => { // 刷新回调方法
...
}
})
9.Web组件
借助Web组件我们就相当于在自己的应用程序里嵌入一个浏览器
只需要在Page目录下的ArkTS文件中创建一个Web组件,传入两个参数就可以了。其中src指定引用的网页路径,controller为组件的控制器,通过controller绑定Web组件,用于实现对Web组件的控制
同样需要申请网路权限 module.json5文件中申明网络访问权限:ohos.permission.INTERNET。
// xxx.ets
@Entry
@Component
struct WebComponent {
controller: WebController = new WebController();
build() {
Column() {
Web({ src: 'https://developer.harmonyos.com/', controller: this.controller })
}
}
}
加载本地网页
首先在main/resources/rawfile目录下创建一个HTML文件,然后通过$rawfile引用本地网页资源
// xxx.ets
@Entry
@Component
struct SecondPage {
controller: WebController = new WebController();
build() {
Column() {
Web({ src: $rawfile('index.html'), controller: this.controller })
}
}
}
属性
zoomAccess
zoomAccess用于设置是否支持手势进行缩放,默认允许执行缩放。Web组件默认支持手势进行缩放。
Web({ src:'www.example.com', controller:this.controller })
.zoomAccess(true)
zoom
zoom(factor: number)方法用于设置网站的缩放比例。其中factor表示缩放倍数
controller: WebController = new WebController();
factor: number = 1.5;
Button('zoom')
.onClick(() => {
this.controller.zoom(this.factor);
})
Web({ src: 'www.example.com', controller: this.controller })
textZoomAtio
textZoomAtio用于设置页面的文本缩放百分比,默认值为100,表示100%,以下示例代码将文本放大为原来的1.5倍
Web({ src:'www.example.com', controller:this.controller })
.textZoomAtio(150)
组件事件
onProgressChange可以监听网页的加载进度,onPageEnd在网页加载完成时触发该回调,且只在主frame触发,onConfirm则在网页触发confirm告警弹窗时触发回调
当onConfirm回调返回false时,触发默认弹窗。当回调返回true时,系统应用可以调用系统弹窗能力(包括确认和取消),并且需要根据用户的确认或取消操作调用JsResult通知Web组件。
Web({ src:$rawfile('index.html'), controller:this.controller })
.onConfirm((event) => {
AlertDialog.show({
title: 'title',
message: event.message,
confirm: {
value: 'onAlert',
action: () => {
event.result.handleConfirm();
}
},
cancel: () => {
event.result.handleCancel();
}
})
return true;
})
JavaScript交互
javaScriptAccess 调用js
如果您希望加载的网页在Web组件中运行JavaScript,则必须为您的Web组件启用JavaScript功能,默认情况下是允许JavaScript执行的
Web组件onPageEnd事件中添加runJavaScript方法。事件是网页加载完成时的回调,runJavaScript方法可以执行HTML中的JavaScript脚本
Web({ src:'https://www.example.com', controller:this.controller })
.javaScriptAccess(true)
例子:当页面加载完成时,触发onPageEnd事件,调用HTML文件中的test方法并将结果返回给Web组件
Web({ src: $rawfile('index.html'), controller: this.controller })
.javaScriptAccess(true)
.onPageEnd(e => {
this.controller.runJavaScript({
script: 'test()',
callback: (result: string)=> {
this.webResult = result;
}});
})
// index.html
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<body>
</body>
<script type="text/javascript">
function test() {
return "This value is from index.html"
}
</script>
</html>
js调用web组件
可以使用registerJavaScriptProxy将Web组件中的JavaScript对象注入daowindow对象中,这样网页中的JS就可以直接调用该对象了
要想registerJavaScriptProxy方法生效,须调用refresh方法
// xxx.ets
@Entry
@Component
struct WebComponent{
@State dataFromHtml: string = ''
controller: WebController = new WebController()
testObj = {
test: (data) => {
this.dataFromHtml = data;
return 'ArkUI Web Component';
},
toString: () => {
console.log('Web Component toString');
}
}
build() {
Column() {
Text(this.dataFromHtml).fontSize(20)
Row() {
Button('Register JavaScript To Window').onClick(() => {
this.controller.registerJavaScriptProxy({
object: this.testObj,
name: 'objName',
methodList: ['test', 'toString'],
});
this.controller.refresh();
})
}
Web({ src: $rawfile('index.html'), controller: this.controller })
.javaScriptAccess(true)
}
}
}
// index.html
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<body>
<button onclick="htmlTest()">调用Web组件里面的方法</button>
</body>
<script type="text/javascript">
function htmlTest() {
str = objName.test("param from Html");
}
</script>
</html>
其中object表示参与注册的对象,name表示注册对象的名称为objName,与window中调用的对象名一致;methodList表示参与注册的应用侧JavaScript对象的方法,包含test、toString两个方法。在HTML中使用的时候直接使用objName调用methodList里面对应的方法即可
web组件页面方法
@Entry
@Component
struct Page5 {
controller: WebController = new WebController();
build() {
Column() {
Row() {
Button("前进").onClick(() => {
this.controller.forward();
})
Button("后退").onClick(() => {
this.controller.backward();
})
Button("刷新").onClick(() => {
this.controller.refresh();
})
Button("停止").onClick(() => {
this.controller.stop();
})
Button("清除历史").onClick(() => {
this.controller.clearHistory();
})
}
.padding(12)
.backgroundColor(Color.Gray)
.width('100%')
Web({ src: 'https://developer.harmonyos.com/', controller: this.controller })
}
.height('100%')
}
}
使用accessBackward()来检查当前页面是否有后退来时记录,如果有则该方法返回 true。同样,您可以使用 accessForward()来检查是否存在前进历史记录
web组件页面调试
可以使用onConsole获取网页输出的调试日志信息
Web({ src: $rawfile('index.html'), controller: this.controller })
.onConsole((event) => {
console.log('getMessage:' + event.message.getMessage());
console.log('getMessageLevel:' + event.message.getMessageLevel());
return false;
})
10.Blank
空白填充组件
11.Checkbox
多选框组件
Checkbox({name:"checkbox1",group:"checkboxGroup"})
.select(true)
.selectedColor("#ffffff")
.onChange(()=>{
....
})
name:多选框名称
group:多选框群组名称
.select()是否选中
.selectedColor()选中颜色
onChange回调事件
12.CheckboxGroup
多选框群组
Checkbox({group:"checkboxGroup"}) //群组名称
.select(true)
.selectedColor("#ffffff")
.onChange(()=>{
....
})
13.DataPanel
图表面板:数据最大支持九个
value=[10,10,10]//数据最大支持九个
DataPanel({values:this.value,max:100,type:DataPanel[Type.Circle]}).width(200).height(200)
max:大于0表示数据最大值,小于0等于value数组之和.按比例显示
type:数据面板样式
14.Divider
分割器
四、页面容器布局组件
1.Column和Row
- Column表示沿垂直方向布局的容器。
- Row表示沿水平方向布局的容器。
Column
Column(value?:{space?: string | number})
Row
Row(value?:{space?: string | number})
#可选参数space,表示子组件在主轴方向上的间距。
justifyContent | 设置子组件在主轴方向上的对齐格式。 |
---|---|
alignItems | 设置子组件在交叉轴方向上的对齐格式。 |
justifyContent设置属性值:
- Start:元素在主轴方向首端对齐,第一个元素与行首对齐,同时后续的元素与前一个对齐。
- Center:元素在主轴方向中心对齐,第一个元素与行首的距离以及最后一个元素与行尾距离相同。
- End:元素在主轴方向尾部对齐,最后一个元素与行尾对齐,其他元素与后一个对齐
- SpaceBetween:元素在主轴方向均匀分配弹性元素,相邻元素之间距离相同。 第一个元素与行首对齐,最后一个元素与行尾对齐。
- SpaceAround:元素在主轴方向均匀分配弹性元素,相邻元素之间距离相同。 第一个元素到行首的距离和最后一个元素到行尾的距离是相邻元素之间距离的一半。
- SpaceEvenly:元素在主轴方向等间距布局,无论是相邻元素还是边界元素到容器的间距都一样。
alignItems设置属性值:
- Start:设置子组件在水平方向上按照起始端对齐。
- Center(默认值):设置子组件在水平方向上居中对齐。
- End:设置子组件在水平方向上按照末端对齐。
Row容器:VerticalAlign
- Top:设置子组件在垂直方向上居顶部对齐
- Center(默认值):设置子组件在竖直方向上居中对齐
- Bottom:设置子组件在竖直方向上居底部对齐。
2.List
List是很常用的滚动类容器组件,一般和子组件ListItem一起使用,List列表中的每一个列表项对应一个ListItem组件。
例
private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
build() {
Column() {
List({ space: 10 }) {
ForEach(this.arr, (item: number) => {
ListItem() {
Text(`${item}`)
.width('100%')
.height(100)
.fontSize(20)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.borderRadius(10)
.backgroundColor(0x007DFF)
}
}, item => item)
}
}
属性
divider
设置列表分割
- strokeWidth: 分割线的线宽。
- color: 分割线的颜色。
- startMargin:分割线距离列表侧边起始端的距离。
- endMargin: 分割线距离列表侧边结束端的距离。
listDirection
设置List排列方向
- Vertical(默认值):子组件ListItem在List容器组件中呈纵向排列
- Horizontal:子组件ListItem在List容器组件中呈横向排列
事件
List列表滚动事件监听:
- onScroll:列表滑动时触发,返回值scrollOffset为滑动偏移量,scrollState为当前滑动状态。
- onScrollIndex:列表滑动时触发,返回值分别为滑动起始位置索引值与滑动结束位置索引值。
- onReachStart:列表到达起始位置时触发。
- onReachEnd:列表到底末尾位置时触发。
- onScrollStop:列表滑动停止时触发。
List({ space: 10 }) {
ForEach(this.arr, (item) => {
ListItem() {
Text(`${item}`)
...
}
}, item => item)
}
.onScrollIndex((firstIndex: number, lastIndex: number) => {
console.info('first' + firstIndex)
console.info('last' + lastIndex)
})
.onScroll((scrollOffset: number, scrollState: ScrollState) => {
console.info('scrollOffset' + scrollOffset)
console.info('scrollState' + scrollState)
})
.onReachStart(() => {
console.info('onReachStart')
})
.onReachEnd(() => {
console.info('onReachEnd')
})
.onScrollStop(() => {
console.info('onScrollStop')
})
3.Grid
private arr: string[] = new Array(16).fill('').map((_, index) => `item ${index}`);
build() {
Column() {
Grid() {
ForEach(this.arr, (item: string) => {
GridItem() {
Text(item)
.height(100)
}
}, item => item)
}.columnsTemplate('1fr 1fr 1fr 1fr') #需要滚动
#设置rowsTemplate和columnsTemplate中的一个即可
将示例代码中GridItem的高度设置为固定值,例如100;仅设置columnsTemplate属性,不设置rowsTemplate属性,就可以实现Grid列表的滚动
Grid像List一样也可以使用onScrollIndex来监听列表的滚动。
4.Tabs
配合TabsController
@Entry
@Component
struct TabsExample {
@State currentIndex: number = 0;
private tabsController: TabsController = new TabsController();
@Builder TabBuilder(title: string, targetIndex: number, selectedImg: Resource, normalImg: Resource) {
Column() {
Image(this.currentIndex === targetIndex ? selectedImg : normalImg)
.size({ width: 25, height: 25 })
Text(title)
.fontColor(this.currentIndex === targetIndex ? '#1698CE' : '#6B6B6B')
}
.width('100%')
.height(50)
.justifyContent(FlexAlign.Center)
.onClick(() => {
this.currentIndex = targetIndex;
this.tabsController.changeIndex(this.currentIndex);
})
}
build() {
Tabs({ barPosition: BarPosition.End, controller: this.tabsController }) {
TabContent() {
Column().width('100%').height('100%').backgroundColor('#00CB87')
}
.tabBar(this.TabBuilder('首页', 0, $r('app.media.home_selected'), $r('app.media.home_normal')))
TabContent() {
Column().width('100%').height('100%').backgroundColor('#007DFF')
}
.tabBar(this.TabBuilder('我的', 1, $r('app.media.mine_selected'), $r('app.media.mine_normal')))
}
.barWidth('100%')
.barHeight(50)
.onChange((index: number) => {
this.currentIndex = index;
})
}
}
Tabs组件中包含4个子组件TabContent,通过TabContent的tabBar属性设置TabBar的显示内容。使用通用属性width和height设置了Tabs组件的宽高,使用barWidth和barHeight设置了TabBar的宽度和高度
- TabContent组件不支持设置通用宽度属性,其宽度默认撑满Tabs父组件。
- TabContent组件不支持设置通用高度属性,其高度由Tabs父组件高度与TabBar组件高度决定。
属性
BarMode
abs的布局模式有Fixed(默认)和Scrollable两种 Scrollable,可以实现页签的滚动
Tabs(....) .barMode(BarMode.Scrollable)
BarPosition
barPosition的值可以设置为BarPosition.Start(默认值)和BarPosition.End
- BarPosition.Start vertical属性方法设置为false(默认值)时,页签位于容器顶部。 vertical属性方法设置为true时,页签位于容器左侧
- BarPosition.End vertical属性方法设置为false时,页签位于容器底部。vertical属性方法设置为true时,页签位于容器右侧。
五、请求
进行网络请求前,您需要在module.json5文件中申明网络访问权限。 requestPermissions 里ohos.permission.INTERNET
//1.导入http模块
import http from '@ohos.net.http';
//2.创建httpRequest对象 面包括常用的一些网络请求方法,比如request、destroy、on('headerReceive')等
let httpRequest = http.createHttp();
//3.订阅http响应头,此接口会比request请求先返回,可以根据业务需要订阅此消息
httpRequest.on('headersReceive', (header) => {
console.info('header: ' + JSON.stringify(header));
})
//4.发起http请求
let url = "https://EXAMPLE_URL";
let promise = httpRequest.request(
// 请求url地址
url,
{
// 请求方式
method: http.RequestMethod.POST,
// 请求的额外数据。
extraData: {
"param1": "value1",
"param2": "value2",
},
// 可选,默认为60s
connectTimeout: 60000,
// 可选,默认为60s
readTimeout: 60000,
// 开发者根据自身业务需要添加header字段
header: {
'Content-Type': 'application/json'
}
});
//5.处理响应结果
promise.then((data) => {
if (data.responseCode === http.ResponseCode.OK) {
console.info('Result:' + data.result);
console.info('code:' + data.responseCode);
}
}).catch((err) => {
console.info('error:' + JSON.stringify(err));
});
get参数可以直接拼接 post 需要extraData
destroy
中断网络请求
httpRequest.destroy();
on
订阅HTTP Response Header 事件
httpRequest.on('headersReceive', (header) => {
console.info('header: ' + JSON.stringify(header));
});
off
取消订阅HTTP Response Header 事件
httpRequest.off('headersReceive');
六、首选项Preferences
1、以Key-Value形式存储数据,Key是不重复的关键字,value可以为空
2、非关系型数据库
建议存储数据不超过一万条,key长度不超过80,value长度不超过8192
常用接口有:保存数据(put)、获取数据(get)、是否包含指定的key(has)、删除数据(delete)、数据持久化(flush)
使用:
导入@ohos.data.preferences模块,同时定义两个常量PREFERENCES_NAME和KEY_APP_FONT_SIZE。(注:把常用接口封装在PreferencesUtil工具类里面,为了方便后面代码直接调用)
import dataPreferences from '@ohos.data.preferences';
...
const PREFERENCES_NAME = 'myPreferences'; // 数据库表名字
const KEY_APP_FONT_SIZE = 'appFontSize'; // 表中存取的关键字
需要在entryAbility的onCreate方法获取首选项实例,该实力便后续能进行保存、读取、删除等操作,
获取实例需要上下文context和文件名字PREFERENCES_NAME
// entryAbility.ets
//初始化
onCreate(want, launchParam) {
globalThis.abilityWant = want;
// 创建首选项
PreferencesUtil.createFontPreferences(this.context);
...
}
// PreferencesUtil.ets 工具类
createFontPreferences(context) {
globalThis.getFontPreferences = (() => {
// 获取首选项实例
let preferences: Promise<dataPreferences.Preferences> = dataPreferences.getPreferences(context, PREFERENCES_NAME);
return preferences;
});
}
保存数据(put)
在entryAbility的onCreate方法,调用PreferencesUtil.saveDefaultFontSize保存默认数据,先用has方法判断当前key是否有存在,如果没有就通过put方法把用户数据保存起来,该方法通过key-value键值对方式保存,常量KEY_APP_FONT_SIZE作为key,用户数据fontSize作为value,再通过flush方法把数据保存到文件
onCreate(want, launchParam) {
globalThis.abilityWant = want;
...
// 设置字体默认大小
PreferencesUtil.saveDefaultFontSize(Constants.SET_SIZE_STANDARD);
}
// PreferencesUtil.ets 工具类
saveDefaultFontSize(fontSize: number) {
globalThis.getFontPreferences().then((preferences) => {
// 判断保存的key是否存在
preferences.has(KEY_APP_FONT_SIZE).then(async (isExist) => {
if (!isExist) {
// 保存数据
await preferences.put(KEY_APP_FONT_SIZE, fontSize);
preferences.flush();
}
})
}
获取数据(get)
在HomePage的onPageShow方法,调用PreferencesUtil.getChangeFontSize方法获取用户数据,调用get方法获取,该方法通过key-value键值对方式读取,常量KEY_APP_FONT_SIZE作为key,默认数据fontSize作为value,把的到的结果赋值给变量fontSize,通过return方式把值返回去
// HomePage.ets
onPageShow() {
PreferencesUtil.getChangeFontSize().then((value) => {
this.changeFontSize = value;
});
}
// PreferencesUtil.ets 工具类
async getChangeFontSize() {
let fontSize: number = 0;
const preferences = await globalThis.getFontPreferences();
fontSize = await preferences.get(KEY_APP_FONT_SIZE, fontSize);
return fontSize;
}
是否包含指定的key(has)
preferences.has(KEY_APP_FONT_SIZE).then(async (isExist) => {
Logger.info(TAG, 'preferences has changeFontSize is ' + isExist);
}));
数据持久化(flush)
// PreferencesUtil.ets 工具类
saveChangeFontSize(fontSize: number) {
globalThis.getFontPreferences().then(async (preferences) => {
// 保存数据
await preferences.put(KEY_APP_FONT_SIZE, fontSize);
// 数据持久化
preferences.flush();
})
}
删除数据(delete)
// PreferencesUtil.ets 工具类
async deleteChangeFontSize() {
const preferences: dataPreferences.Preferences = await globalThis.getFontPreferences();
// 删除数据
let deleteValue = preferences.delete(KEY_APP_FONT_SIZE);
deleteValue.then(() => {
Logger.info(TAG, 'Succeeded in deleting the key appFontSize.');
});
}
七、第三方库使用
使用ohpm等同于npm 进行安装时,并会在oh-package.json5中自动添加依赖
//安装
ohpm install @ohos/lottie
//删除
ohpm uninstall @ohos/lottie
第三方库使用 以lottie为例
import lottie from '@ohos/lottie'
lottie.xxx
八、样式
动画animation
产生属性动画的属性须在animation之前声明,其后声明的将不会产生属性动画
目前支持的属性包括width、height、position、opacity、backgroundColor、scale、rotate、translate等
Image($r('app.media.image1'))
.animation({
duration: 1000,
tempo: 1.0,
delay: 0,
curve: Curve.Linear,
playMode: PlayMode.Normal,
iterations: 1
})
duration | 动画时长,单位为毫秒,默认时长为1000毫秒 |
---|---|
tempo | 动画的播放速度,值越大动画播放越快,值越小播放越慢,为0时无动画效果 |
curve | 动画变化曲线,默认曲线为线性,默认为Curve.Linear |
delay | 延时播放时间,单位为毫秒,默认不延时播放。 |
iterations | 播放次数,默认一次,设置为-1时表示无限次播放。 |
playMode | 设置动画播放模式,默认播放完成后重头开始播放 ,默认为PlayMode.Normal |
onFinish | 动画播放结束时回调该函数 iterations为-1 则不会触发 |
curve枚举: Linear从头到尾的速度都是相同的、Ease低速开始然后加快,在结束前变慢、EaseInOut表示动画以低速开始和结束、FastOutSlowIn标准曲线等等
playMode值:Normal正常播放、Reverse反向播放、Alternate动画在奇数次正向播放,在偶数次反向播放、AlternateReverse动画在奇数次反向播放,在偶数次正向播放
常用css属性
fontColor | 设置文本颜色 |
---|---|
fontSize | 设置文本尺寸,Length为number类型时,使用fp单位。 |
fontStyle | 设置文本的字体样式。默认值:FontStyle.Normal。 |
fontWeight | 设置文本的字体粗细 |
fontFamily | 设置文本的字体列表。使用多个字体,使用“,”进行分割,优先级按顺序生效 |
textAlign | 文字对其方式 |
backgroundColor | 北京颜色 |
maxLines和textOverflow | maxLines用于设置文本显示最大行数。textOverflow设置为Ellipsis ,它将显示不下的文本用 “…” 表示 |
decoration | 文本装饰线样式及其颜色例如decoration({ type: TextDecorationType.Underline, color: Color.Black }) |