鸿蒙系统之ArkTs布局组件
一. Stack叠加布局
Stack介绍
堆叠容器,子组件按照顺序依次入栈,后一个子组件覆盖前一个子组件
Column(){
Stack({alignContent:Alignment.TopEnd}){
//Stack 叠加布局
Row(){
Text('第一个')
}.width('100%').backgroundColor('#ccc').height(100)
Row(){
Text('第二个')
}.width('50%').backgroundColor('blue').height(100)
}.height(200).width('100%').border({width:1,color:'red'})
}
.height('100%')
.width('100%')
运行结果:
Stack的用法
@State arr:number[]=[1,2,3,4,5,6,7]
@State addFlag:boolean=false //默认不显示
Stack(){
Column(){
List(){
ForEach(this.arr,(a:number,index)=>{
ListItem(){
Row(){}.width('100%').height(100)
.backgroundColor(index%2==0?'#aaa':'#ccc')
}
})
}.width('90%')
.height('80%')
Button('添加')
.onClick(()=>{
this.addFlag=true
})
}
.height('100%')
.width('100%')
if(this.addFlag){
Column(){
Text('添加页面')
Button('提交')
.onClick(()=>{
this.addFlag=false
})
}
.height('100%')
.width('100%')
.backgroundColor('#fff')
}
}
.height('100%')
.width('100%')
}
运行结果:
通过Stack布局就可以实现在同一页面进行内容展示
二. 通过Stack实现 ‘闲鱼’ 手机模块的展示
2.1效果展示
2.2. 代码展示与讲解
第一步:先把手机的属性与方法声明出来
export class Phone{
//手机图片,配送方式,标题
// 手机品牌,功能,价格 预购
// 用户头像 ,用户昵称,芝麻信用分
private _pImg: string
public set pImg(value: string) {
this._pImg = value
}
public get pImg(): string {
return this._pImg
}
private _psfs: string
public set psfs(value: string) {
this._psfs = value
}
public get psfs(): string {
return this._psfs
}
private _titles: string
public set titles(value: string) {
this._titles = value
}
public get titles(): string {
return this._titles
}
private _brand: string
public set brand(value: string) {
this._brand = value
}
public get brand(): string {
return this._brand
}
private _pow: string
public set pow(value: string) {
this._pow = value
}
public get pow(): string {
return this._pow
}
private _price: number
public set price(value: number) {
this._price = value
}
public get price(): number {
return this._price
}
constructor(pImg: string, psfs: string, titles: string, brand: string, pow: string, price: number, yg: number,
userImg: string, username: string, zmNumber: number) {
this._pImg = pImg
this._psfs = psfs
this._titles = titles
this._brand = brand
this._pow = pow
this._price = price
this._yg = yg
this._userImg = userImg
this._username = username
this._zmNumber = zmNumber
}
private _yg: number
public set yg(value: number) {
this._yg = value
}
public get yg(): number {
return this._yg
}
private _userImg: string
public set userImg(value: string) {
this._userImg = value
}
public get userImg(): string {
return this._userImg
}
private _username: string
public set username(value: string) {
this._username = value
}
public get username(): string {
return this._username
}
private _zmNumber: number
public set zmNumber(value: number) {
this._zmNumber = value
}
public get zmNumber(): number {
return this._zmNumber
}
}
第二步:创建数组并实例化数据 这里用的都是网络图片
@State message: string = '';
@State phoneList:Phone[]=[]
@State isMai:boolean=false //默认不显示卖出页面
aboutToAppear(): void {
this.phoneList.push(new Phone('https://ts4.cn.mm.bing.net/th?id=OIP-C.HYSpio0UbDgI723YrAxr7AHaHa&w=250&h=250&c=8&rs=1&qlt=90&o=6&dpr=1.3&pid=3.1&rm=2','包邮','二手苹果','苹果','无拆无修',1980,3,'https://ts4.cn.mm.bing.net/th?id=OIP-C.HYSpio0UbDgI723YrAxr7AHaHa&w=250&h=250&c=8&rs=1&qlt=90&o=6&dpr=1.3&pid=3.1&rm=2','张三',180))
this.phoneList.push(new Phone('https://ts2.cn.mm.bing.net/th?id=OIP-C.LMoltz5GsTfaDcJQe7QNHQHaIa&w=234&h=266&c=8&rs=1&qlt=90&o=6&dpr=1.3&pid=3.1&rm=2','自提','九成新华为','华为','无功正常',2980,31,'https://tse2-mm.cn.bing.net/th/id/OIP-C.fNF8owgmIwYhU9KINmt2dAAAAA?w=216&h=216&c=7&r=0&o=5&dpr=1.3&pid=1.7','阿斯顿',580))
this.phoneList.push(new Phone('https://ts4.cn.mm.bing.net/th?id=OIP-C.HYSpio0UbDgI723YrAxr7AHaHa&w=250&h=250&c=8&rs=1&qlt=90&o=6&dpr=1.3&pid=3.1&rm=2','包邮','九成新小米','小米','无拆无修',980,5,'https://tse3-mm.cn.bing.net/th/id/OIP-C.LYRZ_nETF4W4VchbeGIP5gAAAA?rs=1&pid=ImgDetMain','格瑞特',380))
this.phoneList.push(new Phone('https://ts2.cn.mm.bing.net/th?id=OIP-C.LMoltz5GsTfaDcJQe7QNHQHaIa&w=234&h=266&c=8&rs=1&qlt=90&o=6&dpr=1.3&pid=3.1&rm=2','自提','九成新华为','华为','无功正常',2980,31,'https://tse2-mm.cn.bing.net/th/id/OIP-C.fNF8owgmIwYhU9KINmt2dAAAAA?w=216&h=216&c=7&r=0&o=5&dpr=1.3&pid=1.7','阿斯顿',580))
this.phoneList.push(new Phone('https://ts2.cn.mm.bing.net/th?id=OIP-C.LMoltz5GsTfaDcJQe7QNHQHaIa&w=234&h=266&c=8&rs=1&qlt=90&o=6&dpr=1.3&pid=3.1&rm=2','自提','九成新华为','华为','无功正常',2980,31,'https://tse2-mm.cn.bing.net/th/id/OIP-C.fNF8owgmIwYhU9KINmt2dAAAAA?w=216&h=216&c=7&r=0&o=5&dpr=1.3&pid=1.7','阿斯顿',580))
this.phoneList.push(new Phone('https://ts4.cn.mm.bing.net/th?id=OIP-C.HYSpio0UbDgI723YrAxr7AHaHa&w=250&h=250&c=8&rs=1&qlt=90&o=6&dpr=1.3&pid=3.1&rm=2','包邮','二手苹果','苹果','无拆无修',1980,3,'https://ts4.cn.mm.bing.net/th?id=OIP-C.HYSpio0UbDgI723YrAxr7AHaHa&w=250&h=250&c=8&rs=1&qlt=90&o=6&dpr=1.3&pid=3.1&rm=2','张三',180))
this.phoneList.push(new Phone('https://ts4.cn.mm.bing.net/th?id=OIP-C.HYSpio0UbDgI723YrAxr7AHaHa&w=250&h=250&c=8&rs=1&qlt=90&o=6&dpr=1.3&pid=3.1&rm=2','包邮','二手苹果','苹果','无拆无修',1980,3,'https://ts4.cn.mm.bing.net/th?id=OIP-C.HYSpio0UbDgI723YrAxr7AHaHa&w=250&h=250&c=8&rs=1&qlt=90&o=6&dpr=1.3&pid=3.1&rm=2','张三',180))
this.phoneList.push(new Phone('https://ts4.cn.mm.bing.net/th?id=OIP-C.HYSpio0UbDgI723YrAxr7AHaHa&w=250&h=250&c=8&rs=1&qlt=90&o=6&dpr=1.3&pid=3.1&rm=2','包邮','二手苹果','苹果','无拆无修',1980,3,'https://ts4.cn.mm.bing.net/th?id=OIP-C.HYSpio0UbDgI723YrAxr7AHaHa&w=250&h=250&c=8&rs=1&qlt=90&o=6&dpr=1.3&pid=3.1&rm=2','张三',180))
}
第三步:遍历数据并显示到页面中
这里有个bug,就是只能显示双数,看有哪个小伙伴可以解决一下。我们继续讲解我们用column是竖着排列,我们想要实现两行数据,该怎么实现呢?
我们这是就用到Stack布局了,我们首先在Row布局里面写两个Column布局结构为这样:
这样写的目的是让第二个Column把上面的Column给覆盖住,宽度我们给给45%是让两边留点位置,但是这样写就会出现重复内容,这时我们就需要考虑下标单数在右面还是下标双数在右面,
下标我们知道从0开始,偶数便在左边,我们就在第一个Column中写左边的内容
内容如下:
Column() {
Image(this.phoneList[index].pImg)
.aspectRatio(3 / 4)
.borderRadius(10)
Row(){
if(this.phoneList[index].psfs=='包邮'){
Stack({alignContent:Alignment.Bottom}){
Row().backgroundColor(Color.Yellow).height(7).width(30)
Text('包邮').fontWeight(700)
}.width(40).height(20)
}
Text(this.phoneList[index].titles)
}.width('100%').margin({top:5})
Row(){
Text(this.phoneList[index].brand).fontColor('#ccc').fontSize(14)
Text('|').fontColor('#ccc').margin({left:5,right:5})
Text(this.phoneList[index].pow).fontColor('#ccc').fontSize(14)
}.width('100%').margin({top:5})
Row(){
Text('¥')
.fontSize(10)
.fontColor('#E73A3F')
.alignSelf(ItemAlign.End)
Text(`${this.phoneList[index].price}`)
.fontSize(16)
.fontColor('#E73A3F')
Text(this.phoneList[index].yg>0?`${this.phoneList[index].yg}人想要`:'')
.margin({left :5})
.fontColor('#ccc')
.fontSize(14)
}.width('100%').margin({top:5})
Row(){
Image(this.phoneList[index].userImg)
.height(25)
.width(25)
.borderRadius(10)
Text(this.phoneList[index].username)
.fontColor('#ccc')
.fontSize(16)
.margin({left :5})
}.width('100%').margin({top:5})
}.width('45%')
第二个Column就需要写上我们右边所展示的内容,让下标加1即可
Column() {
Image(this.phoneList[index+1].pImg)
.aspectRatio(3 / 4)
.borderRadius(10)
Row(){
if(this.phoneList[index+1].psfs=='包邮'){
Stack({alignContent:Alignment.Bottom}){
Row().backgroundColor(Color.Yellow).height(7).width(30)
Text('包邮').fontWeight(700)
}.width(40).height(20)
}
Text(this.phoneList[index+1].titles)
}.width('100%').margin({top:5})
Row(){
Text(this.phoneList[index+1].brand).fontColor('#ccc').fontSize(14)
Text('|').fontColor('#ccc').margin({left:5,right:5})
Text(this.phoneList[index+1].pow).fontColor('#ccc').fontSize(14)
}.width('100%').margin({top:5})
Row(){
Text('¥')
.fontSize(10)
.fontColor('#E73A3F')
.alignSelf(ItemAlign.End)
Text(`${this.phoneList[index+1].price}`)
.fontSize(16)
.fontColor('#E73A3F')
Text(this.phoneList[index+1].yg>0?`${this.phoneList[index+1].yg}人想要`:'')
.margin({left :5})
.fontColor('#ccc')
.fontSize(14)
}.width('100%').margin({top:5})
Row(){
Image(this.phoneList[index+1].userImg)
.height(25)
.width(25)
.borderRadius(10)
Text(this.phoneList[index+1].username)
.fontColor('#ccc')
.fontSize(16)
.margin({left :5})
}.width('100%').margin({top:5})
}.width('45%')
但是这样就会出现页面重复的现象,我们就需要做个判断,让下标被2整除显示,这样就避免重复
完整代码 如下:
Column(){
List(){
ForEach(this.phoneList,(phone:Phone,index)=>{
ListItem() {
if (index % 2 == 0) {
Row() {
Column() {
Image(this.phoneList[index].pImg)
.aspectRatio(3 / 4)
.borderRadius(10)
Row(){
if(this.phoneList[index].psfs=='包邮'){
Stack({alignContent:Alignment.Bottom}){
Row().backgroundColor(Color.Yellow).height(7).width(30)
Text('包邮').fontWeight(700)
}.width(40).height(20)
}
Text(this.phoneList[index].titles)
}.width('100%').margin({top:5})
Row(){
Text(this.phoneList[index].brand).fontColor('#ccc').fontSize(14)
Text('|').fontColor('#ccc').margin({left:5,right:5})
Text(this.phoneList[index].pow).fontColor('#ccc').fontSize(14)
}.width('100%').margin({top:5})
Row(){
Text('¥')
.fontSize(10)
.fontColor('#E73A3F')
.alignSelf(ItemAlign.End)
Text(`${this.phoneList[index].price}`)
.fontSize(16)
.fontColor('#E73A3F')
Text(this.phoneList[index].yg>0?`${this.phoneList[index].yg}人想要`:'')
.margin({left :5})
.fontColor('#ccc')
.fontSize(14)
}.width('100%').margin({top:5})
Row(){
Image(this.phoneList[index].userImg)
.height(25)
.width(25)
.borderRadius(10)
Text(this.phoneList[index].username)
.fontColor('#ccc')
.fontSize(16)
.margin({left :5})
}.width('100%').margin({top:5})
}.width('45%')
Column() {
Image(this.phoneList[index+1].pImg)
.aspectRatio(3 / 4)
.borderRadius(10)
Row(){
if(this.phoneList[index+1].psfs=='包邮'){
Stack({alignContent:Alignment.Bottom}){
Row().backgroundColor(Color.Yellow).height(7).width(30)
Text('包邮').fontWeight(700)
}.width(40).height(20)
}
Text(this.phoneList[index+1].titles)
}.width('100%').margin({top:5})
Row(){
Text(this.phoneList[index+1].brand).fontColor('#ccc').fontSize(14)
Text('|').fontColor('#ccc').margin({left:5,right:5})
Text(this.phoneList[index+1].pow).fontColor('#ccc').fontSize(14)
}.width('100%').margin({top:5})
Row(){
Text('¥')
.fontSize(10)
.fontColor('#E73A3F')
.alignSelf(ItemAlign.End)
Text(`${this.phoneList[index+1].price}`)
.fontSize(16)
.fontColor('#E73A3F')
Text(this.phoneList[index+1].yg>0?`${this.phoneList[index+1].yg}人想要`:'')
.margin({left :5})
.fontColor('#ccc')
.fontSize(14)
}.width('100%').margin({top:5})
Row(){
Image(this.phoneList[index+1].userImg)
.height(25)
.width(25)
.borderRadius(10)
Text(this.phoneList[index+1].username)
.fontColor('#ccc')
.fontSize(16)
.margin({left :5})
}.width('100%').margin({top:5})
}.width('45%')
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
.margin({bottom:10})
}
}
})
}
.height('100%')
.width('98%')
}
.height('100%')
.width('100%')
第四步:写底部信息栏
这是我们需要考虑登录这一部分还有信息栏一部分,我们先写信息栏
信息栏有一需要注意的地方,那就是卖闲置它是通过Stack布局给叠加上去
这里有个知识点引用字体图标, 写在Text组件中就可以
Stack({alignContent:Alignment.Bottom}){
Row(){
Column({space:5}){
Text(){
SymbolSpan($r('sys.symbol.house'))
.fontSize(20)
}
Text('闲鱼').fontSize(10)
}
Column({space:5}){
Text(){
SymbolSpan($r('sys.symbol.smallcircle_filled_circle'))
.fontSize(20)
}
Text('北京').fontSize(10)
}
Text()
Text()
Column({space:5}){
Text(){
SymbolSpan($r('sys.symbol.ellipsis_message'))
.fontSize(20)
}
Text('消息').fontSize(10)
}
Column({space:5}){
Text(){
SymbolSpan($r('sys.symbol.person_crop_circle_fill_1'))
.fontSize(20)
}
Text('我的').fontSize(10)
}
}.width('100%').height(50).backgroundColor('#fff')
.justifyContent(FlexAlign.SpaceAround)
Row(){
Row(){
Text('卖').fontSize(30).fontWeight(700).fontStyle(FontStyle.Italic)
Text('闲置').width(10).fontSize(10).fontStyle(FontStyle.Italic)
}
.width(60)
.height(60)
.borderRadius(60)
.backgroundColor('#fde60c')
.justifyContent(FlexAlign.Center)
}.width(70).height(70).backgroundColor('#fff').borderRadius(50)
.justifyContent(FlexAlign.Center)
}.width('100%').height(100)
.onClick(()=>this.isMai=true)
if(this.isMai){
Column(){
Button('返回')
.onClick(()=>this.isMai=false)
}
.height('100%')
.width('100%')
.backgroundColor('#fff')
}
写完信息栏此时我们就要开始写上面那一部分,还是利用Stack实现叠加上去
Stack({alignContent:Alignment.Top}){
Row(){
Row(){
Row(){
Image($rawfile('a.jpg')).width(40).height(40).borderRadius(20)
}.justifyContent(FlexAlign.Center)
}.width('18%').height(60).justifyContent(FlexAlign.Center)
Row(){
Column({space:5}){
Text('欢迎来到闲鱼').fontColor('#fff').width('100%').fontSize(16)
Text('赶快登录打开新世界吧').fontColor('#999').fontSize(12).width('100%')
}
}.width('50%').height(60)
Row(){
Row(){
Text('马上登录').fontWeight(600).onClick(()=>{
router.pushUrl({
url:'pages/LoginPage'
})
})
}.width(90).height(25).backgroundColor(Color.Yellow).justifyContent(FlexAlign.Center).borderRadius(15)
}.width('28%').height(60).justifyContent(FlexAlign.Start)
}.justifyContent(FlexAlign.SpaceAround)
}.width('95%').height(65).backgroundColor('rgba(0,0,0,0.8)').borderRadius(10)
.margin({bottom:80})
完整代码如下
Stack({alignContent:Alignment.Bottom}){
Stack({alignContent:Alignment.Top}){
Row(){
Row(){
Row(){
Image($rawfile('a.jpg')).width(40).height(40).borderRadius(20)
}.justifyContent(FlexAlign.Center)
}.width('18%').height(60).justifyContent(FlexAlign.Center)
Row(){
Column({space:5}){
Text('欢迎来到闲鱼').fontColor('#fff').width('100%').fontSize(16)
Text('赶快登录打开新世界吧').fontColor('#999').fontSize(12).width('100%')
}
}.width('50%').height(60)
Row(){
Row(){
Text('马上登录').fontWeight(600).onClick(()=>{
router.pushUrl({
url:'pages/LoginPage'
})
})
}.width(90).height(25).backgroundColor(Color.Yellow).justifyContent(FlexAlign.Center).borderRadius(15)
}.width('28%').height(60).justifyContent(FlexAlign.Start)
}.justifyContent(FlexAlign.SpaceAround)
}.width('95%').height(65).backgroundColor('rgba(0,0,0,0.8)').borderRadius(10)
.margin({bottom:80})
Row(){
Column({space:5}){
Text(){
SymbolSpan($r('sys.symbol.house'))
.fontSize(20)
}
Text('闲鱼').fontSize(10)
}
Column({space:5}){
Text(){
SymbolSpan($r('sys.symbol.smallcircle_filled_circle'))
.fontSize(20)
}
Text('北京').fontSize(10)
}
Text()
Text()
Column({space:5}){
Text(){
SymbolSpan($r('sys.symbol.ellipsis_message'))
.fontSize(20)
}
Text('消息').fontSize(10)
}
Column({space:5}){
Text(){
SymbolSpan($r('sys.symbol.person_crop_circle_fill_1'))
.fontSize(20)
}
Text('我的').fontSize(10)
}
}.width('100%').height(50).backgroundColor('#fff')
.justifyContent(FlexAlign.SpaceAround)
Row(){
Row(){
Text('卖').fontSize(30).fontWeight(700).fontStyle(FontStyle.Italic)
Text('闲置').width(10).fontSize(10).fontStyle(FontStyle.Italic)
}
.width(60)
.height(60)
.borderRadius(60)
.backgroundColor('#fde60c')
.justifyContent(FlexAlign.Center)
}.width(70).height(70).backgroundColor('#fff').borderRadius(50)
.justifyContent(FlexAlign.Center)
}.width('100%').height(100)
.onClick(()=>this.isMai=true)
if(this.isMai){
Column(){
Button('返回')
.onClick(()=>this.isMai=false)
}
.height('100%')
.width('100%')
.backgroundColor('#fff')
}
最后一步写头部导航栏
代码如下
Stack({alignContent:Alignment.Top}){
Column(){
Row(){
Stack({alignContent:Alignment.Bottom}){
Image($rawfile('a.jpg')).width(50).height(50).borderRadius(50)
Text('签到').width(50).height(20).backgroundColor(Color.Orange).textAlign(TextAlign.Center).borderRadius(10)
}.width(30)
Row(){
Text(){
SymbolSpan($r('sys.symbol.line_viewfinder'))
}.fontSize(20)
TextInput({placeholder:'西瓜'}).borderRadius(0).backgroundColor('#fff').width('40%')
Text()
Text()
Text()
Text()
Text(){
SymbolSpan($r('sys.symbol.camera'))
}.fontSize(25)
Text(){
SymbolSpan($r('sys.symbol.magnifyingglass'))
}
.fontSize(20)
.width(55)
.height(40)
.backgroundColor(Color.Black)
.borderRadius(20)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
}
.width(270)
.height(50)
.backgroundColor('#fff')
.borderRadius(25)
.border({width:2,color:Color.Black})
.justifyContent(FlexAlign.SpaceAround)
}
.width('100%')
.height('50%')
.justifyContent(FlexAlign.SpaceAround)
.margin({top:10})
Row(){
Text('谷圈')
Text('二次元')
Text('手机党')
Text('骑行')
Text('恋与深空')
Text(){
SymbolSpan($r('sys.symbol.chevron_down'))
}
}
.width('100%')
.height('50%')
.justifyContent(FlexAlign.SpaceAround)
.alignItems(VerticalAlign.Bottom)
}
.width('95%')
.height(110)
}
.width('100%')
.height(130)
.backgroundColor('#fff')
.margin({bottom:625})
最后页面效果: