一、Tabs实现页面切换
项目整体效果如下:
修改Index.ets,实现选项卡切换页面,内容如下:
import { NoteBookComponent } from '../components/NoteBookComponent'
import { FoundComponent } from '../components/FoundComponent'
import { MeComponent } from '../components/MeComponent'
import { WeChatComponent } from '../components/WeChatComponent'
@Entry
@Component
struct Index {
//初始化值,作为页面索引使用
@State currentIndex:number = 0
private tabsController:TabsController = new TabsController()
//自定义组件,设置tabs显示效果
@Builder BottomBar(title:string, targetIndex:number, normalImg:Resource, selectedImg:Resource){
Column(){
Image(this.currentIndex == targetIndex? selectedImg:normalImg)
.width(28)
.height(28)
Text(title)
.padding({top:3})
.fontColor(this.currentIndex == targetIndex ? "#00EE76" : "#6b6b6b")
}.onClick(()=>{ //点击整个列出现变化
this.currentIndex = targetIndex
/**
* 用来调用TabsController实例的changeIndex方法,目的是更新选项卡的索引。
* 在这段代码中,this.controller是一个TabsController实例,通过调用changeIndex方法并传入this.index作为参数,
* 可以实现在用户点击选项卡时更新选项卡的索引位置,从而实现选项卡内容的切换。
*/
this.tabsController.changeIndex(this.currentIndex) // 调用控制器的changeIndex方法,更新选项卡的索引
})
}
build() {
Column(){
Tabs({
barPosition:BarPosition.End, //设置Tabs的页签位置。默认值:BarPosition.Start
controller:this.tabsController,//设置Tabs控制器。
index:this.currentIndex} //设置初始页签索引。默认值:0
){
TabContent(){
//页面组件
WeChatComponent()
}.tabBar(this.BottomBar("微信",0,$r("app.media.icon_wechat_normal"),$r("app.media.icon_wechat_selected")))
TabContent(){
//页面组件
NoteBookComponent()
}.tabBar(this.BottomBar("通讯录",1,$r("app.media.icon_book_normal"),$r("app.media.icon_book_selected"),))
TabContent(){
//页面组件
FoundComponent()
}.tabBar(this.BottomBar("发现",2,$r("app.media.icon_found_normal"),$r("app.media.icon_found_selected")))
TabContent(){
//页面组件
MeComponent()
}.tabBar(this.BottomBar("我",3,$r("app.media.icon_me_normal"),$r("app.media.icon_me_selected")))
}
.vertical(false) //vertical:设置 Tab 是否为左右排列,默认为 false ,表示上下排列
}
.width("100%")
.height('100%')
}
}
二、实现微信消息页面
微信联系人消息页面分析,剖析如下:
2.1.实现头部组件
头部组件构成如下:
在components包下创建HeadComponent.ets,在里面定义组件,后期其他页面也是需要使用,代码如下:
@Component
export struct HeadComponent {
img:Resource //图标
textInfo:string//文字说明
build() {
Row(){
Row(){
//文字
Text(this.textInfo)
.fontSize(25)
.fontWeight(FontWeight.Bold)
}
.width("90%")
.justifyContent(FlexAlign.Center)
Row(){
//添加按钮
Image(this.img)
.size({width:20, height:20})
}
.width("10%")
}
.size({width:"100%"})
.padding({top:15, bottom:15})
}
}
2.2.实现搜索组件
搜索组件构成如下:
在components包下创建SearchComponent.ets,在里面定义组件,后期其他页面也是需要使用,代码如下:
@Component
export struct SearchComponent {
//图标
img:Resource
//文字
textInfo:string
build() {
Row(){
//图标设置样式大小
Image(this.img)
.width(25)
.height(25)
.margin({right:15})
Text(this.textInfo)
}
.justifyContent(FlexAlign.Center)
.borderRadius(10)
.backgroundColor(Color.White)
.width("90%")
.height(30)
}
}
2.3.准备用户或者群聊数据
在ets目录创建子包model包。新建FInderData.ets,内容如下:
//好友类
export class Friends{
avatar: Resource|Resource[]
nickName:string
chatInfo:string
constructor(avatar:Resource|Resource[],nickName:string, chatInfo:string) {
this.avatar = avatar
this.nickName = nickName
this.chatInfo = chatInfo
}
}
//准备数据
export let iconList1:Friends[] = [
new Friends([
$r("app.media.icon_head01"),
$r("app.media.icon_head02"),
$r("app.media.icon_head03"),
$r("app.media.icon_head04"),
$r("app.media.icon_head05"),
$r("app.media.icon_head06"),
$r("app.media.icon_head07"),
$r("app.media.icon_head08"),
$r("app.media.icon_head09"),
],"鸿蒙开发交流群","今天学习鸿蒙开发,你来不来!!!"),
new Friends($r("app.media.icon_head01"),"小兔兔","今天学习鸿蒙开发,你来不来!!!"),
new Friends($r("app.media.icon_head02"),"低沉旳呢喃","一怒之下将朋友删除"),
new Friends($r("app.media.icon_head03"),"果子小公公","今天学习鸿蒙开发,你来不来!!!"),
new Friends($r("app.media.icon_head04"),"传说里的你","This is the setting of textOverflow to Clip text content This is the setting of textOverflow to None text content. This is the setting of textOverflow to Clip text content This is the setting of textOverflow to None text content."),
new Friends($r("app.media.icon_head05"),"张三你好","旧的不去新的不来,人这一生分离太多"),
new Friends($r("app.media.icon_head06"),"桃洛憬","快乐活着,一切皆有可能,新年快乐!"),
new Friends($r("app.media.icon_head07"),"一追再追","但有可能会因为连败影响到球员的心态和情绪"),
new Friends([
$r("app.media.icon_head11"),
$r("app.media.icon_head12"),
$r("app.media.icon_head13"),
$r("app.media.icon_head14"),
$r("app.media.icon_head15"),
$r("app.media.icon_head16"),
$r("app.media.icon_head17"),
$r("app.media.icon_head18"),
$r("app.media.icon_head19"),
],"致一科技项目群","今天下午项目评审,请各位按时参加"),
new Friends($r("app.media.icon_head08"),"清梦一场","1-2输球的结果,也是国足时隔39年再一次输给中国香港队,"),
new Friends($r("app.media.icon_head09"),"紫涩微凉","在昨晚进行的封闭热身赛中,国足1-2不敌中国香港队"),
new Friends($r("app.media.icon_head10"),"哥帅但不是蟋蟀","在纳兹莫加医院,口腔科医生盛磊给患者看病。"),
new Friends($r("app.media.icon_head11"),"诗酒乔木","微信删除的聊天记录怎么恢复?"),
new Friends($r("app.media.icon_head12"),"空白的昵称","今天学习鸿蒙开发,你来不来!!!"),
new Friends($r("app.media.icon_head13"),"快乐的天使","一怒之下将朋友删除"),
new Friends($r("app.media.icon_head14"),"流行的趋势","今天学习鸿蒙开发,你来不来!!!"),
new Friends($r("app.media.icon_head15"),"萌萌哒","新年快乐!花样倒计时伴随0点钟响全国各地喜迎2024"),
new Friends($r("app.media.icon_head16"),"勇往直前","旧的不去新的不来,人这一生分离太多"),
new Friends($r("app.media.icon_head17"),"唯美主义","快乐活着,一切皆有可能,新年快乐!"),
new Friends($r("app.media.icon_head18"),"战斗的勇气","一怒之下将朋友删除"),
new Friends($r("app.media.icon_head19"),"瞳孔中的我","今天学习鸿蒙开发,你来不来!!!"),
new Friends($r("app.media.icon_head20"),"贰玥眼号","新年快乐!花样倒计时伴随0点钟响全国各地喜迎2024"),
new Friends($r("app.media.icon_head21"),"寒冷渗进的温暖","旧的不去新的不来,人这一生分离太多"),
new Friends($r("app.media.icon_head22"),"桃洛憬","快乐活着,一切皆有可能,新年快乐!"),
new Friends($r("app.media.icon_head23"),"甜甜圈小贩","快乐活着,一切皆有可能,新年快乐!")
]
2.4.实现用户或者群组件
实现用户或者群组件,拆解构成如下:
在WeChat目录下创建WeChatItem.ets,实现组件,如下:
import { Friends } from '../../model/FInderData'
@Component
export struct WeChatItem {
friend:Friends
build() {
//信息列表
Row(){
//如果avatar是一个数组,则表示是群聊
if (Array.isArray(this.friend.avatar)){
//如果是数组,则是群聊头像,采用网格布局
Grid(){
ForEach(this.friend.avatar, (img, index)=>{
GridItem(){
Image(img) //网格布局群聊头像
}
})
}
.width(50)
.height(50)
.margin({left:30, right:10})
.align(Alignment.Start) //Alignment.Start起始端纵向居中。设置元素内容在元素绘制区域内的对齐方式。默认值:Alignment.Center横向和纵向居中。
.rowsTemplate("1fr 1fr 1fr") //三行
.columnsTemplate("1fr 1fr 1fr")//三列布局
.borderRadius(4) //全局半径
}else {
//如果是单个图片,则是个人好友
Image(this.friend.avatar) //头像
.width(50)
.height(50)
.margin({left:30,right:10})
.borderRadius(4)
}
Column(){
Text(this.friend.nickName).fontColor("#1C1C1C").fontSize(18) //昵称
//聊天记录
Text(this.friend.chatInfo)
.fontColor("#B4CDCD")
.maxLines(1) //和textOverflow配合使用,超过一行则截断,
.textOverflow({overflow:TextOverflow.Ellipsis}) //超过一行显示显示省略号
}
.alignItems(HorizontalAlign.Start)
.width(240)
}
.width("100%")
.height(60)
.backgroundColor("#F5FFFA")
}
}
2.5.实现用户或者群聊天组件列表
实现用户或者群组件,拆解构成如下:
在WeChat目录下创建WeChatListItem.ets,实现聊天组件,如下:
import { Friends, iconList1 } from '../../model/FInderData'
import { WeChatItem } from './WeChatItem'
@Component
export struct WeChatListItem {
build() {
List({space:2}){
//循环产生用户列表
ForEach(iconList1, (item:Friends, index)=>{
ListItem(){
//信息列表
/*Row(){
//如果avatar是一个数组,则表示是群聊
if (Array.isArray(item.avatar)){
//如果是数组,则是群聊头像,采用网格布局
Grid(){
ForEach(item.avatar, (img, index)=>{
GridItem(){
Image(img) //网格布局群聊头像
}
})
}
.width(50)
.height(50)
.margin({left:30, right:10})
.align(Alignment.Start) //Alignment.Start起始端纵向居中。设置元素内容在元素绘制区域内的对齐方式。默认值:Alignment.Center横向和纵向居中。
.rowsTemplate("1fr 1fr 1fr") //三行
.columnsTemplate("1fr 1fr 1fr")//三列布局
.borderRadius(4) //全局半径
}else {
//如果是单个图片,则是个人好友
Image(item.avatar) //头像
.width(50)
.height(50)
.margin({left:30,right:10})
.borderRadius(4)
}
Column(){
Text(item.nickName).fontColor("#1C1C1C").fontSize(18) //昵称
//聊天记录
Text(item.chatInfo)
.fontColor("#B4CDCD")
.maxLines(1) //和textOverflow配合使用,超过一行则截断,
.textOverflow({overflow:TextOverflow.Ellipsis}) //超过一行显示显示省略号
}
.alignItems(HorizontalAlign.Start)
.width(240)
}
.width("100%")
.height(60)
.backgroundColor("#F5FFFA")*/
WeChatItem({friend:item})
}
})
}
.height("100%")
.width("100%")
}
}
2.6.创建主页
在components包下创建 WeChatComponent.ets,由上面定义的子组件构成整个聊天信息页面,分别由:
- 头部组件
- 搜索框
- 电脑登陆提示
- 好友和群聊列表
内容如下:
import { HeadComponent } from './HeadComponent'
import { LoginPromptComponent } from './WeChat/LoginPromptComponent'
import { SearchComponent } from './SearchComponent'
import { WeChatItem } from './WeChat/WeChatItem'
@Component
export struct WeChatComponent {
build() {
Column(){
//首行
HeadComponent({textInfo:"微信", img:$r("app.media.icon_add")})
//搜索框
SearchComponent({img:$r("app.media.icon_search"), textInfo:"搜索"})
//电脑登陆提示信息
LoginPromptComponent()
//好友和群聊列表
WeChatItem()
}
.size({width:"100%", height:"100%"})
.backgroundColor("#F5F5F5")
}
}
2.7.预览
在这里代码创建完成后在主页Index.ets下调用WeChatComponent ,然后预览如下:
三、实现通讯录页面
页面分解图如下:
3.1.准备数据
在model包下创建NoteBookData.ets文件,用于准备后面的数据,内容如下:
export interface INoteBookItem{
icon:Resource
title:string
bgColor: string
}
//准备数据
export let NoteBookDataList:INoteBookItem[] = [
{
icon:$r("app.media.icon_new_friends"),
title:"新的朋友",
bgColor:"#9FB6CD"
},
{
icon:$r("app.media.icon_public_account"),
title:"仅聊天的朋友",
bgColor:"#9FB6CD"
},
{
icon:$r("app.media.icon_group_chat"),
title:"群聊",
bgColor:"#9FB6CD"
},
{
icon:$r("app.media.icon_tag"),
title:"标签",
bgColor:"#9FB6CD"
}
]
3.2.定义布局方式
页面布局分析拆解如下:
这里是对新的朋友、仅聊天的朋友、群聊和标签进行布局,在 components包下创建子包NoteBook,然后创建 NoteBookListComponent.ets,循内容如下:
import { INoteBookItem, NoteBookDataList } from '../../model/NoteBookData'
@Component
export struct NoteBookListComponent {
build() {
Column(){
List({space:10}){
ForEach(NoteBookDataList,(item:INoteBookItem, index)=>{
ListItem(){
//循环产生新朋友、群聊、仅聊天
Row(){
//加载图片
Image(item.icon).width(25).height(25)
//文字描述
Text(item.title)
.fontSize(20)
.margin({left:10})
}
.padding({left:20})
.width("95%")
.justifyContent(FlexAlign.Start)
.backgroundColor(Color.White)
}
})
}.divider({ strokeWidth: 1, color: "#F5F5F5" }) //分割线
}
.width("100%")
.height("100%")
.alignItems(HorizontalAlign.Center) //水平居中
.justifyContent(FlexAlign.Center) //垂直居中
.backgroundColor("#F5F5F5") //整个列表背景颜色
}
}
3.3.创建通讯录页面
根据上面定义的组件内容,在components包下创建通讯录页面NoteBookComponent.ets,如下
import { HeadComponent } from './HeadComponent'
import { NoteBookListComponent } from './NoteBook/NoteBookListComponent';
import { SearchComponent } from './SearchComponent'
//定义字母数字
let uppercaseLetters: string[] = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
//定义接口
interface PersonInterface{
name:string
}
//定义按照首字母分组,一个组A下有多个用户
interface ContractPersonInterface{
char:string,
personItem:PersonInterface[] //一个字母开头会有多个用户
}
@Component
export struct NoteBookComponent {
//准备用户列表
@State personList: ContractPersonInterface[] = [
{char:"A", personItem:[{"name":"阿大"},{"name":"阿二"},{"name":"阿三"},{"name":"奥特曼"},{"name":"奥特蛋"},{"name":"阿二"},{"name":"阿三"},{"name":"奥特曼"},]},
{char:"B", personItem:[{"name":"宝贝"},{"name":"宝宝"},{"name":"宝儿"},{"name":"宝贝儿"},{"name":"宝贝宝贝"},{"name":"宝宝"},{"name":"宝儿"},{"name":"宝贝儿"},{"name":"宝贝宝贝"}]},
{char:"C", personItem:[{"name":"草莓"},{"name":"菜菜"},{"name":"小菜"},{"name":"小仓"},{"name":"小虫"},{"name":"菜菜"},{"name":"小菜"},]}
]
//定义一个状态selectedIndex,初始值为0,表示选中的索引。
@State selectedIndex:number = 0
//创建一个Scroller实例,用于滚动列表。
scroller:Scroller = new Scroller()
//定义一个名为GroupHeader的构建器函数,接受一个字符串参数word,返回一个组件。用于显示字母A、B、C这些组
@Builder GroupHeader(word:string){
Row(){
Text(word)
.fontSize(18)
.width("100%")
.padding(5)
.margin({left:10})
}
}
build() {
Column(){
//头信息
HeadComponent({textInfo:"通讯录",img:$r("app.media.icon_add")})
//剩余的内容放在一起, 主要是拼音列表要堆叠在用户列表上面
Stack({alignContent:Alignment.End}){//alignContent:Alignment.End设置字母表,在右侧显示
List(){
ListItem(){
Column(){
//搜索框
SearchComponent({img:$r("app.media.icon_search"), textInfo:"搜索"}).margin({top:10, bottom:10})
//仅聊天的朋友、新的朋友、标签、公众号
NoteBookListComponent()
.height(180)
.padding({left:10,top:14,right:10,bottom:14})
.backgroundColor(Color.White)
//好友列表
List({scroller:this.scroller}){
//循环显示用户信息
ForEach(this.personList,(wordItem:ContractPersonInterface, index)=>{
ListItemGroup({
header:this.GroupHeader(wordItem.char) //显示组名字母,例如A
}){
ForEach(wordItem.personItem, (p:PersonInterface, index2)=>{ //显示A组对应的用户
ListItem(){//循环取出组中的信息
Row(){
//显示用户昵称
Text(p.name).fontSize(16).width("100%")
}
.margin({top:20})
}
})
}
.padding({left:25, top:20, right:25})
.divider({ strokeWidth: 1, color: "#F0FFF0" }) //分割线
} )
}
.backgroundColor(Color.White)
.sticky(StickyStyle.Header) //设置ListItemGroup中header和footer是否要吸顶或吸底。
.onScrollIndex((index:number)=>{//列表滑动时触发。计算索引值时,ListItemGroup作为一个整体占一个索引值,不计算ListItemGroup内部ListItem的索引值。
this.scroller.scrollToIndex(index) //滑动到指定Index。
this.selectedIndex = index //滑动后修改索引值,以此来控制下面的字母改变
console.info(`本次列表选中的索引为:${index}`)
})
}
}
}
//可以与容器组件联动用于按逻辑结构快速定位容器显示区域的组件。 uppercaseLetters 字母索引字符串 selected:0默认初始化值
AlphabetIndexer({arrayValue:uppercaseLetters, selected:0})
.selected(this.selectedIndex) //设置选中项索引值。
.onSelect((index)=>{ //索引条选中回调,返回值为当前选中索引。
this.selectedIndex = index
this.scroller.scrollToIndex(index)
})
}
.height("100%")
}
.size({width:"100%", height:"100%"})
.backgroundColor("#F5F5F5")
}
}
3.4.测试
在Index.ets中添加上面的通讯录组件,然后进行测试,效果如下:
四、发现页面
页面拆解图如下:
4.1.准备数据
在model包下的,InfoData.ets下准备数据内容如下:
export interface InfoDataItem{
icon:Resource
title:string
headIcon?:Resource
desc?:string
isRadPoint?:Boolean //小红点
}
export let InfoDataList:InfoDataItem[] = [
{
icon:$r("app.media.icon_friends"),
title:"朋友圈",
headIcon:$r("app.media.icon_friend_head"),
desc:"",
isRadPoint:true
},
{
icon:$r("app.media.icon_video_number"),
title:"视频号",
headIcon:$r("app.media.icon_video_head"),
desc:"卓伟又爆了大瓜了",
isRadPoint:true
},
{
icon:$r("app.media.icon_live_broadcast"),
title:"直播",
headIcon:$r("app.media.icon_broadcast_head"),
desc:"50个朋友关注",
isRadPoint:true
},
{
icon:$r("app.media.icon_sweep"),
title:"扫一扫"
},
{
icon:$r("app.media.icon_shake"),
title:"摇一摇"
},
{
icon:$r("app.media.icon_see"),
title:"看一看",
headIcon:$r("app.media.icon_see_head"),
desc:"2个朋友在看",
isRadPoint:true
},
{
icon:$r("app.media.icon_search_finder"),
title:"搜一搜"
},
{
icon:$r("app.media.icon_nearby"),
title:"附近"
},
{
icon:$r("app.media.icon_shop"),
title:"购物"
},
{
icon:$r("app.media.icon_game"),
title:"游戏",
headIcon:$r("app.media.icon_game_head"),
desc:"朋友刚刚发布动态",
isRadPoint:true
},
{
icon:$r("app.media.icon_applet"),
title:"小程序"
},
]
4.2.创建组件1
朋友圈、扫一扫、摇一摇、搜一搜、附近、购物、小程序这几个功能页面布局分析如下:
然后在components包下创建Finder子包,然后新建FinderItem01.ets,实现组件,代码内容如下:
@Component
export struct FinderItem01 {
//朋友圈、扫一扫、摇一摇、搜一搜、附近、购物、小程序
icon:Resource //图标
title:string //名称
headIcon?:Resource //用户头像
desc?:string //描述
isRadPoint?:Boolean //是否小红点
build() {
Column(){
Row(){
//头像和分类名称
Row(){
//图片
Image(this.icon).width(28).height(28).margin({right:12})
//文字
Text(this.title)
}.margin({left:30, top:10})
//右侧 图标 小红点 >
Row(){
//这里是为朋友圈分类准备的,如果有为ture,会在右侧显示小红点和用户头像
if(this.isRadPoint){
//实现红点
Badge({
value:"",//没有内容就是一个红点
position: BadgePosition.RightTop, //在右上角显示
style:{badgeSize:6,badgeColor:Color.Red} //样式:大小、颜色
}){
Image(this.headIcon)
.borderRadius(10)
.width(28)
.height(28)
.margin({right:12})
}
}
//尖括号
Image($r("app.media.icon_right_angle_bracket"))
.margin({right:28})
.width(28)
.height(28)
}
}
.justifyContent(FlexAlign.SpaceBetween)
.width("100%")
.height(48)
}
.width("100%")
.height("100%")
}
}
4.3.创建组件2
视频号功能页面布局分析如下:
然后在components的Finder子包下创建FinderItem02.ets,实现组件,代码内容如下:
@Component
export struct FinderItem02 {
//视频号
icon:Resource
title:string
headIcon?:Resource
desc?:string
isRadPoint?:Boolean //小红点
build() {
Column(){
Row(){
Row(){
//图片
Image(this.icon).width(28).height(28).margin({right:12})
//文字
Text(this.title)
}.margin({left:30, top:10})
//右侧 图标 小红点 >
Row(){
if(this.isRadPoint){
//实现红点
Badge({
value:"",//没有内容就是一个红点
position: BadgePosition.RightTop, //在右上角显示
style:{badgeSize:6,badgeColor:Color.Red} //样式:大小、颜色
}){
Image(this.headIcon)
.borderRadius(10)
.width(28)
.height(28)
.margin({right:12})
}
}else {
//只显示图片
Image(this.headIcon)
.borderRadius(10)
.width(28)
.height(28)
.margin({right:12})
}
Text(this.desc).lineHeight(28).margin({right:12})
Image($r("app.media.icon_right_angle_bracket")).margin({right:28}).width(28).height(28)
}
}.justifyContent(FlexAlign.SpaceBetween)
.width("100%")
.height(48)
}
.width("100%")
.height("100%")
}
}
4.4.创建组件3
直播、看一看、游戏功能页面布局分析如下:
然后在components的Finder子包下创建FinderItem03.ets,实现组件,代码内容如下:
@Component
export struct FinderItem03 {
//直播、看一看、游戏
icon:Resource
title:string
headIcon?:Resource
desc?:string
isRadPoint?:Boolean //小红点
build() {
Column(){
Row(){
Row(){
//图片
Image(this.icon).width(28).height(28).margin({right:12})
//文字
Text(this.title)
}.margin({left:30, top:10})
//右侧 图标 小红点 >
Row(){
Text(this.desc).lineHeight(28).margin({right:12})
if(this.isRadPoint){
//实现红点
Badge({
value:"",//没有内容就是一个红点
position: BadgePosition.RightTop, //在右上角显示
style:{badgeSize:6,badgeColor:Color.Red} //样式:大小、颜色
}){
Image(this.headIcon)
.borderRadius(10)
.width(28)
.height(28)
.margin({right:12})
}
}else {
//只显示图片
Image(this.headIcon)
.borderRadius(10)
.width(28)
.height(28)
.margin({right:12})
}
Image($r("app.media.icon_right_angle_bracket")).margin({right:28}).width(28).height(28)
}
}.justifyContent(FlexAlign.SpaceBetween)
.width("100%")
.height(48)
}
.width("100%")
.height("100%")
}
}
4.5.创建发现页面
在components下创建发现页面FoundComponent.ets,代码如下:
import { InfoDataItem, InfoDataList } from '../model/InfoData'
import { FinderItem01 } from './Finder/FinderItem01'
import { FinderItem02 } from './Finder/FinderItem02'
import { FinderItem03 } from './Finder/FinderItem03'
import { HeadComponent } from './HeadComponent'
import { SearchComponent } from './SearchComponent'
@Component
export struct FoundComponent {
build() {
Column(){
Row(){
Text("发现").fontSize(25).fontWeight(FontWeight.Bold)
}
.justifyContent(FlexAlign.Center)
.width("100%")
.height(65)
.backgroundColor("#EDEDED")
List(){
ForEach(InfoDataList, (item:InfoDataItem, key)=>{
/**
* 这里根据key不同,决定之前定义的那个样式
*/
//朋友圈、扫一扫、摇一摇、附近 购物、小程序
if(key==0||key==3||key==4||key==6||key==7||key==8||key==10){
//而下面在再次判断,目的是为了让他们能有不用的样式,出现间隔
if(key==0){
ListItem(){
FinderItem01({
icon:item.icon,
title:item.title,
headIcon:item.headIcon,
desc:item.desc,
isRadPoint:item.isRadPoint
})
.backgroundColor(Color.White)
.height(48)
.margin({bottom:16})
}
}
else if(key==3){
ListItem(){
FinderItem01({icon:item.icon,
title:item.title,
headIcon:item.headIcon,
desc:item.desc,
isRadPoint:item.isRadPoint
})
.backgroundColor(Color.White)
//和上面的区别只是样式的不同
.height(48)
.margin({top:20})
}
}else if(key==7){
ListItem(){
FinderItem01({icon:item.icon,
title:item.title,
headIcon:item.headIcon,
desc:item.desc,
isRadPoint:item.isRadPoint
})
.backgroundColor(Color.White)
//和上面的区别只是样式的不同
.height(48)
.margin({top:20,bottom:20})
}
}else if(key==10){
ListItem(){
FinderItem01({icon:item.icon,
title:item.title,
headIcon:item.headIcon,
desc:item.desc,
isRadPoint:item.isRadPoint
})
.backgroundColor(Color.White)
//和上面的区别只是样式的不同
.height(48)
.margin({top:20})
}
}
else {
ListItem(){
FinderItem01({icon:item.icon,
title:item.title,
headIcon:item.headIcon,
desc:item.desc,
isRadPoint:item.isRadPoint
})
.backgroundColor(Color.White)
//和上面的区别只是样式的不同
.height(48)
}
}
}
//视频号
if(key==1){
ListItem(){
FinderItem02({
icon:item.icon,
title:item.title,
headIcon:item.headIcon,
desc:item.desc,
isRadPoint:item.isRadPoint
})
.backgroundColor(Color.White)
.height(48)
}
}
//直播、看一看、游戏
if(key==2||key==5||key==9){
if(key==5){
ListItem(){
FinderItem03({
icon:item.icon,
title:item.title,
headIcon:item.headIcon,
desc:item.desc,
isRadPoint:item.isRadPoint
})
.backgroundColor(Color.White)
.height(48)
.margin({top:20})
}
}else {
ListItem(){
FinderItem03({
icon:item.icon,
title:item.title,
headIcon:item.headIcon,
desc:item.desc,
isRadPoint:item.isRadPoint
})
.backgroundColor(Color.White)
.height(48)
}
}
}
})
}
}
.width("100%")
.height("100%")
.backgroundColor("#F5F5F5")
}
}
4.6.测试
在Index.ets中调用FoundComponent.ets中定义的组件,预览如下:
五、实现-我页面
对于页面布局进行拆解,如下图:
5.1.实现个人信息
在components目录下创建子包Me,然后创建UserInfoComponent.ets,代码如下:
@Component
export struct UserInfoComponent {
build() {
Row(){
//整个分为两列
//1.头像
Column(){
Image($r("app.media.icon_head23")).width(90).height(90).borderRadius(10).margin({right:12})
}.layoutWeight(1) //权重1,占主轴剩余空间1/3,父容器尺寸确定时,设置了layoutWeight的子元素在主轴布局尺寸按照权重进行分配,忽略本身尺寸设置。
Column(){
//昵称
Row(){
Text("站在街角等雨淋").fontSize(22).fontWeight(FontWeight.Bold)
}.width("100%")
Row(){
//微信号
Text("微信号: Tenderness").margin({right:20})
//二维码
Image($r("app.media.icon_qrcode")).width(18).height(18).margin({right:20})
//右尖括号
Image($r("app.media.icon_right_angle_bracket")).width(12).height(12).margin({left:20})
}.width("100%").margin({top:4})
//状态
Row(){
// border width:边框宽度;color:边框颜色;radius:边框半径;
Text(" + 状态").fontSize(10).border({width:1, color:"#DDDDDD",radius:10}).margin({right:10})
//堆叠三个图标
Stack({alignContent:Alignment.BottomEnd}){
Image($r("app.media.icon_001")).width(10).height(10).borderRadius(5)
Image($r("app.media.icon_002")).width(10).height(10).borderRadius(5).margin({left:10,right:10})
Image($r("app.media.icon_003")).width(10).height(10).borderRadius(5).margin({left:20,right:20})
}
Text("等20个朋友").fontSize(12).margin({left:10})
}.margin({top:4})
}
.alignItems(HorizontalAlign.Start) //水平向左排列
.justifyContent(FlexAlign.Center) //垂直方法居中排列
.layoutWeight(3) // 权重3,占主轴剩余空间3/4
.margin({top:20, left:30})
}
.height(120)
.width("100%")
.margin({left:20, top:30})
}
}
5.2.实现单个行组件
实现组件原型如下:
在包Me,然后创建MeInfoComponent.ets,代码如下:
@Component
export struct MeInfoComponent {
img:Resource //图标
title:string //文字描述
build() {
Row(){
Row(){
//图标
Image(this.img).width(28).height(28)
//名称,例如:服务、朋友圈
Text(this.title)
.margin({left:12, right:130})
.textAlign(TextAlign.Center)
.height(28)
}
.width("80%")
//右尖括号
Image($r("app.media.icon_right_angle_bracket")).width(24).height(24)
}
.height(56)
.width("100%")
.justifyContent(FlexAlign.SpaceEvenly)
}
}
5.3.准备组件列表数据
在model包下创建MeData.ets,准备组件列表数据如下:
export interface MeDataInterface{
icon:Resource
title:string
}
//定义数据
export let MeDataList:MeDataInterface[] = [
{icon:$r("app.media.icon_collect"), title:"朋友圈"},
{icon:$r("app.media.icon_wechat_moment"), title:"视频号"},
{icon:$r("app.media.icon_card_bag"), title:"卡包"},
{icon:$r("app.media.icon_emote"), title:"表情"}
]
5.4.实现组件列表
实现组件原型如下:
Me包下创建MeInfoListComponent.ets,通过List组件然后循环产生组件列表,代码如下:
import { MeDataInterface, MeDataList } from '../../model/MeData'
import { MeInfoComponent } from './MeInfoComponent'
@Component
export struct MeInfoListComponent {
build() {
Column(){
List(){
ForEach(MeDataList, (item:MeDataInterface, index)=>{
ListItem(){
//循环出现行,各个组件
MeInfoComponent({img:item.icon, title:item.title})
}
})
}.divider({ strokeWidth: 1, color: "#F5F5F5" }) //分割线
}
.width("100%")
.height("100%")
}
}
5.5.编写页面-我
利用上面创建的组件,在components包创建MeComponent.ets,如下:
import { MeInfoComponent } from './Me/MeInfoComponent'
import { MeInfoListComponent } from './Me/MeInfoListComponent'
import { UserInfoComponent } from './Me/UserInfoComponent'
@Component
export struct MeComponent {
build() {
Column(){
Row(){
//用户信息
UserInfoComponent()
}.width("100%")
//单个组件
Row(){
MeInfoComponent({img:$r("app.media.icon_service"), title:"服务"})
}
.alignItems(VerticalAlign.Center) //垂直居中
.height(48)
.margin({top:20})
.backgroundColor(Color.White)
//多个组件列表
Row(){
MeInfoListComponent()
}.height(220)
.margin({top:20, bottom:20})
.backgroundColor(Color.White)
//单个组件
Row(){
MeInfoComponent({img:$r("app.media.icon_setting"), title:"设置"})
}
.alignItems(VerticalAlign.Center) //垂直居中
.height(48)
.margin({top:20})
.backgroundColor(Color.White)
}
.width("100%")
.height("100%")
.backgroundColor("#F5F5F5")
}
}
5.6.测试
在Index.ets中调用MeComponent.ets中定义的组件,预览效果如下: