1 微信应用App概述
基于HarmonyOS 6 来实现类似于微信界面效果的应用。
微信界面主要包含4部分,即微信、联系人、发现、我,,本节所演示的例子也要实现这4部分。
1.1“微信”页面
“微信”页面是微信应用的首页,主要是展示联系人之间的沟通信息。如图所示是"微信"页面的效果图。

1.2“联系人”页面
“联系人”页面展示了用户所关联的联系人。

1.3“发现”页面
“发现”页面是微信进入其他子程序的入口。如图所示是“发现”页面的效果图。


1.4“我”页面
“我”页面展示用户个人信息的页面,如图所示是“我”页面的效果图。

2 实战:“微信”页面
这里会演示如何实现“微信”页面。“微信”页面主要是展示联系人的沟通记录列表。列表的每个项,都包含联系人头像、联系人名称、联系人聊天记录以及时间。
2.1 创建“微信”页面ChatPage
在pages创建ChatPage.ets作为"微信"页面。"微信"页面主要分为标题栏及沟通记录列表两部分。代码如下:
|
import {ChatItemStyle, WeChatTitle} from '../model/CommonStyle' import { CONTACTS} from '../model/WeChatData' import {Person} from '../model/Person'
@Component export struct ChatPage {
build() {
Column() {
// 标题
WeChatTitle({ text: "微信" })
// 列表
List() {
ForEach(CONTACTS, (item: Person) => {
ListItem() {
ChatItemStyle({
weChatImage: item.weChatImage,
weChatName: item.weChatName,
chatInfo: item.chatInfo,
time: item.time
})
} }, (item: Person) => item.id.toString())
}
.height('100%')
.width('100%')
} } } |
上述代码中,通过ForEach来遍历CONTACTS数组所返回的联系人数据,并生成ChatemStyle数据项。
2.2 定义联系人Person
联系人是用Person类作为表示。在ets目录下,创建model目录,并在该model目录创建Person.ets,代码如下:
|
export class Person {
id: number = 0;
weChatImage: string = "";
weChatName: string = "";
chatInfo: string = "";
time: string = ""; } |
Person内包含了头像、名称、聊天记录以及时间等信息。
2.3 定义联系人数据
在model目录下创建WeChatData.ets作为联系人数据。代码如下:
|
import { Person } from './Person' export const CONTACTS: Person[] = [
{
id: 1,
weChatImage: "person (1).jpg",
weChatName: "李白", // 诗人名
chatInfo: "天生我材必有用,千金散尽还复来。", // 《将进酒》诗句
time: "09:45" // 随机时间
},
{
id: 2,
weChatImage: "person (2).jpg",
weChatName: "杜甫", // 诗人名
chatInfo: "安得广厦千万间,大庇天下寒士俱欢颜!", // 《茅屋为秋风所破歌》诗句
time: "11:12" // 随机时间
},
{
id: 3,
weChatImage: "person (3).jpg",
weChatName: "王维", // 诗人名
chatInfo: "行到水穷处,坐看云起时。", // 《终南别业》诗句
time: "08:30" // 随机时间
},
...
{
id: 15,
weChatImage: "person (15).jpg",
weChatName: "李煜", // 诗人名
chatInfo: "问君能有几多愁?恰似一江春水向东流。", // 《虞美人·春花秋月何时了》词句
time: "18:05" // 随机时间
} ] export const WE_CHAT_COLOR: string = "#ededed" |
2.4 定义样式
在model目录下创建CommonStyle.ets作为样式类。在该类中定义标题的样式,代码如下:
|
import {WE_CHAT_COLOR} from './WeChatData'; import router from '@system.router';
@Component export struct WeChatTitle {
private text: string = "";
build() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text(this.text).fontSize('18fp').padding('20px')
}.height('120px').backgroundColor(WE_CHAT_COLOR)
} }
// 定义沟通记录的样式 @Component export struct ChatItemStyle {
weChatImage: string = "";
weChatName: string = "";
chatInfo: string = "";
time: string = "";
build() {
Column() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Start }) {
Image($rawfile(this.weChatImage)).width('120px').height('120px').margin({ left: '50px', right: "50px" })
Column() {
Text(this.weChatName).fontSize('16fp')
Text(this.chatInfo).fontSize('12fp').width('620px').fontColor("#c2bec2").maxLines(1)
}.alignItems(HorizontalAlign.Start).flexGrow(1)
Text(this.time).fontSize('12fp')
.margin({ right: "50px" }).fontColor("#c2bec2")
}
.height('180px')
.width('100%')
Row() {
Text().width('190px').height('3px')
Divider()
.vertical(false)
.color(WE_CHAT_COLOR)
.strokeWidth('3px')
}
.height('3px')
.width('100%')
} } }
// 定义沟通联系人的样式 @Component export struct ContactItemStyle {
private imageSrc: string = "";
private text: string = "";
build() {
Column() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Image($rawfile(this.imageSrc)).width('100px').height('100px').margin({ left: '50px' })
Text(this.text).fontSize('15vp').margin({ left: '40px' }).flexGrow(1)
}
.height('150px')
.width('100%')
Row() {
Text().width('190px').height('3px')
Divider()
.vertical(false)
.color(WE_CHAT_COLOR)
.strokeWidth('3px')
}
.height('3px')
.width('100%')
} } }
// 定义发现样式 @Component export struct WeChatItemStyle {
private imageSrc: string = "";
private text: string = "";
private arrow: string = "arrow.png"
build() {
Column() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Image($rawfile(this.imageSrc)).width('75px').height('75px').margin({ left: '50px' })
Text(this.text).fontSize('15vp').margin({ left: '40px' }).flexGrow(1)
Image($rawfile(this.arrow))
.margin({ right: '40px' })
.width('75px')
.height('75px')
}
.height('150px')
.width('100%')
}.onClick(() => {
if (this.text === "视频号") {
router.push({ uri: 'pages/VideoPage' })
} })
} }
// 定义分割线样式,用于发现页面 @Component export struct MyDivider {
private style: string = "
build() {
Row() {
Divider()
.vertical(false)
.color(WE_CHAT_COLOR)
.strokeWidth(this.style == "1" ? '3px' : '23px')
}
.height(this.style == "1" ? '3px' : '23px')
.width('100%')
} } |
上述代码中,CommonStyle中的ChatItemStyle 表示定义沟通记录的样式,实现效果如图:

3 实战:“联系人”页面
这里演示如何实现“联系人”页面。“联系人”页面主要是展示联系人列表,列表的每个项都包含联系人头像、联系人名称。因此,实现方式与“微信”页面类似。
3.1 创建“联系人”页面ContactPage
在pages创建ContactPage.ets作为“联系人”页面。“联系人”页面主要分为标题栏及联系人列表。代码如下:
|
import {ContactItemStyle, WeChatTitle} from '../model/CommonStyle' import {Person} from '../model/Person' import { CONTACTS, WE_CHAT_COLOR} from '../model/WeChatData'
@Component export struct ContactPage {
build() {
Column() {
// 标题
WeChatTitle({ text: "通讯录" })
// 列表
Scroll() {
Column() {
// 固定列表
ContactItemStyle({ imageSrc: "new_friend.png", text: "新的朋友" })
ContactItemStyle({ imageSrc: "group.png", text: "群聊" })
ContactItemStyle({ imageSrc: "biaoqian.png", text: "标签" })
ContactItemStyle({ imageSrc: "gonzh.png", text: "公众号" })
// 企业联系人
Text(" 我的企业及企业联系人").fontSize('12fp').backgroundColor(WE_CHAT_COLOR).height('80px').width('100%')
ContactItemStyle({ imageSrc: "qiye.png", text: "企业微信联系人" })
// 微信好友
Text(" 我的微信好友").fontSize('12fp').backgroundColor(WE_CHAT_COLOR).height('80px').width('100%')
List() {
ForEach(CONTACTS, (item: Person) => {
ListItem() {
ContactItemStyle({ imageSrc: item.weChatImage, text: item.weChatName })
} }, (item: Person) => item.id.toString())
} } }
}.alignItems(HorizontalAlign.Start)
.width('100%')
.height('100%')
} }
|
联系人列表又细分为3个部分:分类、企业联系人、微信好友。
3.2 定义样式
在CommonStyle中定义联系人的样式ContactItemStyle,实现效果如图:

4 实战:“发现”页面
本节演示如何实现“发现”页面。“发现”页面是微信进入其他子程序的入口,每个子程序本质上地是一个列表项。
4.1创建“发现”页面DiscoveryPage
“发现”页面主要分为标题栏及子程序列表,在pages创建DiscoveryPage.ets作为“发现”页面。代码如下:
|
import {WeChatItemStyle, MyDivider, WeChatTitle} from '../model/CommonStyle'
@Component export struct DiscoveryPage {
build() {
Column() {
// 标题
WeChatTitle({ text: "发现" })
// 列表
WeChatItemStyle({ imageSrc: "moments.png", text: "朋友圈" })
MyDivider()
WeChatItemStyle({ imageSrc: "shipinghao.png", text: "视频号" })
MyDivider({ style: '1' })
WeChatItemStyle({ imageSrc: "zb.png", text: "直播" })
MyDivider()
WeChatItemStyle({ imageSrc: "sys.png", text: "扫一扫" })
MyDivider({ style: '1' })
WeChatItemStyle({ imageSrc: "yyy.png", text: "摇一摇" })
MyDivider()
WeChatItemStyle({ imageSrc: "kyk.png", text: "看一看" })
MyDivider({ style: '1' })
WeChatItemStyle({ imageSrc: "souyisou.png", text: "搜一搜" })
MyDivider()
WeChatItemStyle({ imageSrc: "fujin.png", text: "附近" })
MyDivider()
WeChatItemStyle({ imageSrc: "gw.png", text: "购物" })
MyDivider({ style: '1' })
WeChatItemStyle({ imageSrc: "game.png", text: "游戏" })
MyDivider()
WeChatItemStyle({ imageSrc: "xcx.png", text: "小程序" })
MyDivider()
}.alignItems(HorizontalAlign.Start)
.width('100%')
.height('100%')
} }
|
子程序用WeChatltemStyle定义样式,并通过MyDivider来进行分割。
4.2 定义样式
在CommonStyle中定义子程序的样式WeChatItemStyle,子程序主要由3部分组成:图标、名称及箭头。同时定义分割线样式MyDivider。实现效果如下:

5 实战:“我”页面
这里演示如何实现“我”页面。“我”页面是展示用户个人的信息。在pages创建MyPage.ets作为“我”页面。“我”页面主要分为用户信息部分及菜单列表。代码如下:
|
import {WeChatItemStyle, MyDivider} from '../model/CommonStyle'
@Component export struct MyPage {
private imageTitle: string = "title.png"
build() {
Column() {
// 用户信息部分
Image($rawfile(this.imageTitle)).height(144).width('100%')
// 列表
WeChatItemStyle({ imageSrc: "pay.png", text: "服务" })
MyDivider()
WeChatItemStyle({ imageSrc: "favorites.png", text: "收藏" })
MyDivider({ style: '1' })
WeChatItemStyle({ imageSrc: "moments2.png", text: "朋友圈" })
MyDivider({ style: '1' })
WeChatItemStyle({ imageSrc: "video.png", text: "视频号" })
MyDivider({ style: '1' })
WeChatItemStyle({ imageSrc: "card.png", text: "卡包" })
MyDivider({ style: '1' })
WeChatItemStyle({ imageSrc: "emoticon.png", text: "表情" })
MyDivider()
WeChatItemStyle({ imageSrc: "setting.png", text: "设置" })
MyDivider()
}.alignItems(HorizontalAlign.Start)
.width('100%')
.height('100%')
} }
|
与“发现”页面的子程序类似,“我”页面同样也是使用了WeChatltemStyle、MyDivider的样式。
6 实战:组装所有页面
在应用的Index页面,需要将微信、联系人、发现、我4个页面组装在一起,并实现自由切换此时,就可以使用HarmonyOS的Tabs组件作为导航栏。
6.1 Tabs组件作为导航栏
Tabs组件作为导航栏,Index.ets文件中,代码实现如下。
|
import { ChatPage } from './ChatPage' import { ContactPage } from './ContactPage' import { DiscoveryPage } from './DiscoveryPage' import { MyPage } from './MyPage'
@Entry @Component struct Index {
@Provide currentPage: number = 0
@State currentIndex: number = 0;
build() {
Column() {
Tabs({
index: this.currentIndex,
barPosition: BarPosition.End
}) {
TabContent() {
ChatPage()
}
.tabBar(this.TabBuilder('微信', 0, $r('app.media.wechat2'), $r('app.media.wechat1')))
TabContent() {
ContactPage()
}
.tabBar(this.TabBuilder('联系人', 1, $r('app.media.contacts2'), $r('app.media.contacts1')))
TabContent() {
DiscoveryPage()
}
.tabBar(this.TabBuilder('发现', 2, $r('app.media.find2'), $r('app.media.find1')))
TabContent() {
MyPage()
}
.tabBar(
this.TabBuilder('我', 3, $r('app.media.me2'), $r('app.media.me1')) )
}
.barMode(BarMode.Fixed)
.onChange((index: number) => {
this.currentIndex = index;
})
} } }
|
对于底部导航栏,一般作为应用主页面功能区分,为了提升用户体验,我们会组合文字以及对应义图标表示页签内容。在这种情况下,需要自定义导航页签的样式,在Index.ets中完成。代码如下:
|
@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) }
|
导航栏在选中时会呈现出高亮的效果,如图所示。

6.2 Swiper组件实现页面滑动
除了通过底部导航栏实现页面切换外,还可以使用Swiper组件来左右滑动页面从而实现页面切换。在Index.ets文件中定义。代码如下:
|
@Component struct HomeTopPage {
@Consume currentPage: number
build() {
Swiper() {
ChatPage()
ContactPage()
DiscoveryPage()
MyPage()
}
.onChange((index: number) => {
this.currentPage = index
})
.index(this.currentPage)
.loop(false)
.indicator(false)
.width('100%')
.height('100%')
} }
|
7 微信APP项目小结
本项目基于HarmonyOS6提供的组件实现了类似于微信界面效果的应用,该应用主要使用了Flex、Tabs、Column、TabBuilder、Image、Text、Swiper等组件,希望开发者能掌握这些组件在实际开发中的应用。
所有评论(0)