HarmonyOS学习
一,DevEoc Studio基本内容学习
项目工程目录
entry 默认的项目入口模块
ets 界面相关文件(目前都放入pages文件内即可)
resource资源文件,配置文件
index.est默认文件
’ @ ‘开头的一般为装饰器,修饰功能,来约定后面代码的功能
Entry项目入口
@Component 约定下方代码为组件
(鸿蒙中,界面中能看到的都是组件)
@State约定后面的代码为状态,数据变视图,自动更新(数据驱动视图)
bulid()构建界面,文字等等
系统组件:RelativeContainer Text
@Entry
@Component
struct Index {@State message: string = 'Hello HM';build() {RelativeContainer() {Text(this.message).id('HelloWorld').fontSize($r('app.float.page_text_font_size')).fontWeight(FontWeight.Bold).alignRules({center: { anchor: '__container__', align: VerticalAlign.Center },middle: { anchor: '__container__', align: HorizontalAlign.Center }}).onClick(() => {this.message = 'Welcome';})}.height('100%').width('100%')}
}
二,ArkTs学习
1.变量和类型
使用变量存储不同类型的数据:状态信息(布尔类型boolean),文字信息(字符串类型string),数字信息(数字类型number)
any不确定类型(只能在TS中使用,不能在ArkTS中使用)
变量:存储数据的容器
存储方式:【 let 变量名:数据类型 = 值 】
*在日志中输出小括号中的内容
console.log()
测试:在日志中查看输出信息
日志并不会自动清空,右键清空
//注释:crtl+/
//声明变量,保存数据 string字符串类型
let title:string='创意橘子花瓶'
//日志输出
console.log('商品标题是',title)let count:number=1
console.log('购买数量',count )let isSelect:boolean=true
console.log('订单选中了吗?',isSelect)
2.数组
数组:一次性保存多个同类型数据
数组也是容器,用来存储多个数据
数组:[数据1,数据2,......]
表示方法: let 数组名 : 类型[] = [数据1,数据2,数据3,.......]
找到对应的数据:数组名[索引] (索引0,1,2,...)
let titles:string[]=['创意','橘子','花瓶']
console.log('数组是',titles)
console.log('产品1',titles[0])
3.对象
对象:可以一次性存多个不同类型的数据
*数组存的是相同类型的数据,对象存的是不同类型的数据
***使用接口来约定对象的结构和类型
【用接口来定义对象中变量的类型,(接口中有什么是哪种类型,对象中也要有对应的内容)】
定义接口【interface 接口名{}】
定义对象【let 对象名:接口名={}】
//定义接口->约定对象的数据类型(接口名Goods)
interface Goods{title:stringprice:number
}//定义对象【 属性名:属性值->键值对->键值对之间用逗号隔开 】(继承接口,要和接口的数据相对应)
let vase:Goods={title:'创意句子花瓶',price:12.99
}
//查找数据 对象名.属性名
console.log('商品标题是',vase.title)
console.log('商品价格是',vase.price)
console.log('对象是',vase)//得到[object Object],隐藏数据的内容
练习
interface People{name:stringage:numberheight:numberlisten:boolean
}let ren:People={name:'王铁锤',age:20,height:180,listen:true
}
console.log('人名',ren.name)
console.log('年龄',ren.age)
console.log('身高',ren.height)
console.log('成年没',ren.listen)
4.函数
使用函数封装代码,提升代码复用性(一次定义,多次使用)
*定义函数
function calc(){ function 函数名(参数1:类型,参数2:类型,...){
return 返回值(返回到函数调用的位置)
} }
*调用函数
calc() 函数名()
例子:计算圆的周长
//计算任意半径圆的周长 2*3.14*半径
function calc(r:number){console.log('半径为',r)return 2*3.14*r;
}//真实数据->实参
let c1:number=calc(10)
console.log('圆的周长',c1)let c:number=calc(100)
console.log('圆的周长',c)
没有参数没有返回值
//没有参数没有返回值的函数
function printInfo(){console.log('函数里面的输出语句')
}
printInfo();
定义函数->function 函数名(参数列表){} 形参
调用函数->函数名(数据列表) 实参
5.箭头函数
使用箭头函数封装代码,提升代码复用性
表示形式: ( ) =>{
}
可以将箭头函数存到一个函数名中
*定义函数
(函数名sum)
let sum = (num1: number,num2:number)=>{
return num1+num2
}
*调用函数
sum(1,2)
//计算任意两个数的和
let sum=(num1:number,num2:number)=>{console.log('参数的数据是',num1,num2)return num1+num2
}
console.log('箭头函数的返回值是',sum(1,2))
console.log('箭头函数的返回值是',sum(10,20))
练习:计算圆的周长
let cun=(r:number)=>{return 2*3.14*r
}
console.log('圆的周长是',cun(2))
三,ArkUI
ArkUI(方舟开发框架):构建鸿蒙应用界面的框架
1.组件基础
组件:界面构建与显示的最小单位
*掌握组件写法,使用组件布局界面
**容器组件:布局
写法:组件名(){}
Colume(){} (内容竖着排)
Row(){} (内容横着排)
**内容组件:内容
写法:组件名()
Text('内容')要求内容都是字符串类型的
*****注意:先布局,再内容 (在bulid()中写代码)
Column换行排列
Row横向排列
@Entry
@Component
struct Index {build() {// Column(){// Text('大壮')// Text('大壮')// Text('大壮')// }Row(){Text('大壮')Text('大壮')Text('大壮')}}
}
***build唯一的容器组件:用嵌套来解决
2.通用属性
使用属性美化组件
写法: 组件
.属性(值)
属性名 | 作用 | 属性值 |
width | 宽度 | 数值(默认单位vp) |
height | 高度 | 数值(默认单位vp) |
backgroundColor | 背景色 | 色值(内置颜色或十六进制色值) |
@Entry
@Component
struct Index {//build 里面要有唯一的容器和组件build() {Column(){Text('大锤')//给Text组件添加宽高背景色//Color E->Enum 枚举.backgroundColor(Color.Blue).width(100).height(50)Row(){}//满屏尺寸为360vp或者100%//.width(360).width('100%').height(100).backgroundColor('#ff6600')}}
}
3,文本属性
属性名 | 作用 | 属性值 |
fontSize | 字体大小 | 数值(默认单位fp) |
fontColor | 文字颜色 | 色值(内置颜色或十六进制颜色) |
fontWeight | 字体粗细 | 100~900 |
@Entry
@Component
struct Index {//build 里面要有唯一的容器和组件build() {Column(){Text('大锤')//this.自定义构建函数名(数据列表1)//this.自定义构建函数名(数据列表2).fontSize(30).fontColor(Color.Blue).fontWeight(800)}}
}
练习:新闻列表
@Entry
@Component
struct Index {//build 里面要有唯一的容器和组件build() {Column(){Text('在千年').fontSize(18).width(320)Text('新华社').fontSize(12).fontColor('#999999').width(320)Text('扩大开发对象').fontSize(18).width(320)Text('央视新闻').fontSize(12).fontColor('#999999').width(320)}}
}
4,图像组件
使用图像组件Image为界面添加图像资源
Image(图像资源路径)
支持本地图和网络图
路径写法:本地图 Image($r('app.media.xx'))
网络图 Image('https:xxx')
@Entry
@Component
struct Index {//build 里面要有唯一的容器和组件build() {Column(){//添加本地图片Image($r('app.media.startIcon')).width(200)//添加网络图片Image('https://p5.ssl.qhimgs1.com/sdr/400__/t013c8c9997c4ffb6af.jpg').width(200)}}
}
5,内外边距
使用内,外边距调整组件及内容的位置
内边距padding 外边距margin
*希望内容和组件之间有间距用padding
*希望两个组件之间有间距用margin
***四个方向间距相同 写法:
组件
.padding(数值)
.margin(数值)
***四个方向间距不同 写法:
组件
.padding({top:10,botton:20,left:30,right:40})
.margin({top:10,botton:20,left:30,right:40})
@Entry
@Component
struct Index {//build 里面要有唯一的容器和组件build() {Column(){Button('登录').width('100%').margin({bottom:20})Button('注册').width('100%').backgroundColor(Color.Green)}.backgroundColor('#DDDDDD').padding(10).padding({left:10,top:20,right:30,bottom:30})}
}
内边距:拉开内容与组件边缘的距离
外边距:拉开两个组件的距离
单值:四个方向间距相同
对象:四个方向间距不同
6,边框属性border
使用border属性为组件添加边框效果:设置边框,圆角,粗细,等等
写法: 组件
.border({
width:粗细
color:颜色
style:线条样式
radius:圆角
})
@Entry
@Component
struct Index {//build 里面要有唯一的容器和组件build() {Column(){Text('+状态').width(100).height(60).backgroundColor(Color.Brown)//文本水平居中.textAlign(TextAlign.Center).border({width:3,color:Color.Blue,style:BorderStyle.Dotted,radius:10})}.padding(20)}
}
四,界面布局
1.歌曲列表
使用组件及属性方法布局歌曲列表
***先整体,再布局
***先布局,再内容,后美化
******List容器组件,里面加ListItem
写法:List(){
ListItem(){...}
ListItem(){...}
}
******scrollBar滚动条 BarState滚动条状态
设置不显示滚动条 .scrollBar(BarState.Off)
******扩充组件的安全区expandSafeArea 扩充到顶部SafeAreaEdge.TOP,底部SafeAreEdge.BOTTOM
组件(){}
.expandSafeArea([SafeAreaType.SYSTEM],[SafeAreaEdge.TOP,SafeAreaEdge.BOTTOM])
******.layoutWeight(数字) 将外层组件剩余尺寸分成指定份数,当前组件占用对应的份数
******图片.svg(支持用代码,用属性改变图片颜色) 用 .fillColor('') 改变图片颜色
import { EditableLeftIconType } from '@kit.ArkUI'@Entry
@Component
struct Index {build() {Column(){Text('猜你喜欢').fontColor('#fff').width('100%').margin({bottom:10})//容器组件List,支持滑动,加ListItemList(){ListItem(){Row(){//图Image($r('app.media.1')).width(80).height(80).border({radius:8}).margin({right:5,left:5})//字Column(){Text('直到世界镜头').fontColor('#F3F3F3').width('100%').fontWeight(700).margin({bottom:15,left:10})Row(){Text('VIP').fontColor('#9A8E28').border({radius:8,color:'#9A8E28',width:1}).padding({left:5,right:5,top:3,bottom:3}).margin({right:8,left:8}).fontSize(10)Text('凤凰传奇').fontColor('#696969').fontSize(12)}.width('100%')}.layoutWeight(1)//占用剩余的所有空间//图标//*图片.svg(支持用代码,用属性改变图片颜色)用.fillColor('')Image($r('app.media.4')).width(20).margin({right:5})}.width('100%').height(80)//.backgroundColor(Color.Pink).margin({bottom:10})}ListItem(){Row(){//图Image($r('app.media.1')).width(80).height(80).border({radius:8}).margin({right:5,left:5})//字Column(){Text('直到世界镜头').fontColor('#F3F3F3').width('100%').fontWeight(700).margin({bottom:15,left:10})Row(){Text('VIP').fontColor('#9A8E28').border({radius:8,color:'#9A8E28',width:1}).padding({left:5,right:5,top:3,bottom:3}).margin({right:8,left:8}).fontSize(10)Text('凤凰传奇').fontColor('#696969').fontSize(12)}.width('100%')}.layoutWeight(1)//占用剩余的所有空间//图标//*图片.svg(支持用代码,用属性改变图片颜色)用.fillColor('')Image($r('app.media.4')).width(20).margin({right:5})}.width('100%').height(80)//.backgroundColor(Color.Pink).margin({bottom:10})}}//折叠滚动条: 滚动条scrollBar 滚动条状态BarState 关闭Off.scrollBar(BarState.Off)}.width('100%').height('100%').backgroundColor('#131313').padding({left:10,right:10})//扩充组件的安全区,扩充到顶部SafeAreaEdge.TOP,底部SafeAreEdge.BOTTOM.expandSafeArea([SafeAreaType.SYSTEM],[SafeAreaEdge.TOP,SafeAreaEdge.BOTTOM])}
}
2,if分支语句
根据逻辑条件结果,执行不同语句
if(逻辑条件){
条件成立执行的代码
}else{
条件不成立执行的代码
}
*if成立时
let age:number=20
if(age>=18){console.log('成年了')
}@Entry
@Component
struct Index {build() {Column() {}}
}
*if不成立,执行else
let age:number=10
if(age>=18){console.log('成年了')
}else{console.log('未成年')
}@Entry
@Component
struct Index {build() {Column() {}}
}
根据逻辑条件结果,执行不同语句
if(条件1){
条件1成立执行的代码
}else if(条件2){
条件2成立执行的代码
}else{
以上条件都不成立执行的代码
}
let score:number=90
if(score>=80){console.log('A')
}else if (score>=70){console.log('B')
}else if(score>=60){console.log('C')
}else {console.log('D')
}
3.条件表达式
根据逻辑条件结果,执行不同的表达式,得到不同结果
写法: 条件?条件成立的表达式:条件不成立的表达式
let num1:number=10
let num2:number=20
num1>num2?console.log('num1大'):console.log('num2大')
4.条件渲染
根据逻辑条件结果,渲染不同的UI内容
写法:
if(条件1){
组件1
}else if(条件2){
组件2
}else{
组件 else
}
*** “ === ”严格等号,判断数值+类型
let num1:number=1@Entry
@Component
struct Index {build() {Column() {if(num1==1){Text('文本1')}else if(num1==2){Text('文本2')}else{Text('文本else')}}}
}
五,ArkTS核心
1.循环渲染
根据数组数据重复渲染UI内容
写法: ForEach(数组名字,箭头函数)
ForEach(数组,(item:类型,index:number)=>{
组件
})
*item数组中的数据项 index索引
let names:string[]=['Tom','Kit','Dog']@Entry
@Component
struct Index {build() {Column() {ForEach(names,(item:string,index:number)=>{//字符串之间的‘+’,表示拼接Text(item+index)})}.padding(10)}
}
2.状态管理(V2)
应用的运行时的状态是参数,当参数改变时,UI渲染刷新
状态变量:使用装饰器装饰,状态变量数据改变会引起UI的渲染刷新
//V2状态管理
@ComponentV2
struct Index{
@Local num:number=1
......
}
*注意:
(1).状态必须设置数据类型
(2).状态必须设置初始值
//.onClick点击事件
组件
.onClick(()=>{
this.num++
this.num--
})
@Entry
//进入V2状态
@ComponentV2
struct Index {//num状态@Local num:number=0build() {Column() {Row(){Text('-').width(40).height(40).textAlign(TextAlign.Center).border({width:1,radius:{topLeft:3,bottomLeft:3},color:'#999'})//添加点击事件,修改状态.onClick(()=>{if(this.num>1){this.num--}})//状态设置进来,将num的类型转换为stringText(this.num.toString()).width(40).height(40).textAlign(TextAlign.Center).border({width:{top:1,bottom:1},color:'#999'})Text('+').width(40).height(40).textAlign(TextAlign.Center).border({width:1,radius:{topRight:3,bottomRight:3},color:'#999'})//添加点击事件,修改状态.onClick(()=>{this.num++})}.padding(20)}}
}
3.@Builder自定义构建函数
使用@Builder装饰的函数也称为“自定义构建函数”
@Builder装饰的函数作用:封装UI元素,提升复用性
*定义方法:
@Builder
自定义构建函数名(参数列表){
要复用的组件结构
}
*调用方法
this.自定义构建函数名(数据列表1)
this.自定义构建函数名(数据列表2)
*自定义构建函数可以写在组件的里面
@Entry
@Component
struct Index {//封装自定义构建函数 传入参数@BuildertitleBuilder(title:string){Row(){Text(title).fontColor('#fff').fontWeight(700).layoutWeight(1)Image($r('app.media.1')).width(22)}.width('100%').height(50)}build() {Column() {this.titleBuilder('每日推荐')this.titleBuilder('推荐歌单')}.width('100%').height('100%').expandSafeArea([SafeAreaType.SYSTEM],[SafeAreaEdge.TOP,SafeAreaEdge.BOTTOM]).backgroundColor('#131313').padding({left:10,right:10})}
}
六,歌单交互效果
1. ForEach循环渲染歌单
数组里面包对象,可以叫做对象数组
interface Music{image:stringname:stringauthor:string
}@Entry
@Component
struct Index {songs:Music[]=[{image:'https://img2.baidu.com/it/u=2614416695,3021245428&fm=253&fmt=auto&app=138&f=JPEG?w=504&h=500',name:'美美美',author:'xiao田'},{image:'https://img0.baidu.com/it/u=1717687967,3764228590&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=800',name:'美美美',author:'xiao田'},{image:'https://img2.baidu.com/it/u=579662994,16903855&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=800',name:'美美美',author:'xiao田'},{image:'https://img0.baidu.com/it/u=2960273897,2797347908&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=800',name:'美美美',author:'xiao田'},{image:'https://img1.baidu.com/it/u=3259094038,2675463443&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',name:'美美美',author:'xiao田'},{image:'https://img1.baidu.com/it/u=3745915620,3856927535&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',name:'美美美',author:'xiao田'},{image:'https://img2.baidu.com/it/u=182231357,1062845046&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',name:'美美美',author:'xiao田'},{image:'https://img1.baidu.com/it/u=2431701095,4189347457&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',name:'美美美',author:'xiao田'},{image:'https://img2.baidu.com/it/u=2894005634,1549621335&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',name:'美美美',author:'xiao田'},{image:'https://img2.baidu.com/it/u=2578316366,3430436350&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',name:'美美美',author:'xiao田'}]build() {Column() {Text('猜你喜欢').fontColor('#fff').width('100%').margin({bottom:10})List(){ForEach(this.songs,(item:Music,index:number)=>{ListItem(){Row(){//tuImage(item.image).width(80).border({radius:5}).margin({right:5,top:10,bottom:10})//ziColumn(){Text(item.name).fontColor('#fff').fontSize('14').margin({left:20,bottom:10}).width('100%')Row(){Text('VIP').fontColor('#fff').fontSize(12).margin(10).border({radius:8,width:1,color:'#fff'})Text(item.author).fontColor('#fff').fontSize(12)}.width('100%')}.layoutWeight(1)//fuImage($r('app.media.4')).width(10).margin(5)}}})}.scrollBar(BarState.Off)}.padding(20).width('100%').height('100%').backgroundColor('#131313').expandSafeArea([SafeAreaType.SYSTEM],[SafeAreaEdge.TOP,SafeAreaEdge.BOTTOM])}
}
2.播放状态
层叠组件Stcak()
interface Music{image:stringname:stringauthor:string
}@Entry
@ComponentV2
struct Index {@Local playIndex:number=-1songs:Music[]=[{image:'https://img2.baidu.com/it/u=2614416695,3021245428&fm=253&fmt=auto&app=138&f=JPEG?w=504&h=500',name:'美美美',author:'xiao田'},{image:'https://img0.baidu.com/it/u=1717687967,3764228590&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=800',name:'美美美',author:'xiao田'},{image:'https://img2.baidu.com/it/u=579662994,16903855&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=800',name:'美美美',author:'xiao田'},{image:'https://img0.baidu.com/it/u=2960273897,2797347908&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=800',name:'美美美',author:'xiao田'},{image:'https://img1.baidu.com/it/u=3259094038,2675463443&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',name:'美美美',author:'xiao田'},{image:'https://img1.baidu.com/it/u=3745915620,3856927535&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',name:'美美美',author:'xiao田'},{image:'https://img2.baidu.com/it/u=182231357,1062845046&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',name:'美美美',author:'xiao田'},{image:'https://img1.baidu.com/it/u=2431701095,4189347457&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',name:'美美美',author:'xiao田'},{image:'https://img2.baidu.com/it/u=2894005634,1549621335&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',name:'美美美',author:'xiao田'},{image:'https://img2.baidu.com/it/u=2578316366,3430436350&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',name:'美美美',author:'xiao田'}]build() {Column() {Text('猜你喜欢').fontColor('#fff').width('100%').margin({bottom:10})List(){ForEach(this.songs,(item:Music,index:number)=>{ListItem(){Row(){//tuStack(){Image(item.image).width(80).border({radius:5}).margin({right:5,top:10,bottom:10})if(this.playIndex===index){Image($r('app.media.1')).width(10)}}//ziColumn(){Text(item.name).fontColor('#fff').fontSize('14').margin({left:20,bottom:10}).width('100%')Row(){Text('VIP').fontColor('#fff').fontSize(12).margin(10).border({radius:8,width:1,color:'#fff'})Text(item.author).fontColor('#fff').fontSize(12)}.width('100%')}.layoutWeight(1)//fuImage($r('app.media.4')).width(10).margin(5)}.onClick(()=>{this.playIndex=index})}})}.scrollBar(BarState.Off)}.padding(20).width('100%').height('100%').backgroundColor('#131313').expandSafeArea([SafeAreaType.SYSTEM],[SafeAreaEdge.TOP,SafeAreaEdge.BOTTOM])}
}
循环渲染数据的思路:
数组数据------>ForEach------>替换数据
控制播放状态的思路:
播放状态组件(层叠)--->状态变量@Local播放索引--->条件渲染,播放状态组件--->点击事件修改状态变量
层叠布局组件:
Stack容器组件
依据:【全网首套鸿蒙5.0零基础入门到项目实战开发全套视频教程,原生鸿蒙正式版项目实战从ArkTS+AI到V2应用状态管理,鸿蒙API16应用开发全掌握】https://www.bilibili.com/video/BV1gSZvYzEdZ?p=25&vd_source=9e0031c99b0b852d596960307c0f094d