回复
#HarmonyOS NEXT体验官# 体验HarmonyOS开发流程,开发一个简单图册展示app(二) 原创
RandomBoolean
发布于 2024-7-29 16:42
浏览
0收藏
上一篇文章构建了一个登录页面,包含基本的登录流程。点击登录之后成功登录进入到首页中。
创建tabbar切换页面
在开发首页之前,需要先规划一下app底部的tab栏,本次开发只涉及两个tab,分别是首页和我的页面。
在pages目录下创建MainPage页面,UI结构代码如下。
build() {
Tabs({
barPosition: BarPosition.End,
controller: this.tabsController
}) {
TabContent() {
Home()
}
.padding({ left: $r('app.float.mainPage_padding'), right: $r('app.float.mainPage_padding') })
.backgroundColor($r('app.color.mainPage_backgroundColor'))
.tabBar(this.TabBuilder(CommonConstants.HOME_TITLE, CommonConstants.HOME_TAB_INDEX,
$r('app.media.home_selected'), $r('app.media.home_normal')))
TabContent() {
Setting()
}
.padding({ left: $r('app.float.mainPage_padding'), right: $r('app.float.mainPage_padding') })
.backgroundColor($r('app.color.mainPage_backgroundColor'))
.tabBar(this.TabBuilder(CommonConstants.MINE_TITLE, CommonConstants.MINE_TAB_INDEX,
$r('app.media.mine_selected'), $r('app.media.mine_normal')))
}
.width(CommonConstants.FULL_PARENT)
.backgroundColor(Color.White)
.barHeight($r('app.float.mainPage_barHeight'))
.barMode(BarMode.Fixed)
.onChange((index: number) => {
this.currentIndex = index;
})
}
其中 Home() 和 Setting()为引入的组件页面。分别是首页和我的页面。在view中创建Home和Setting文件。 整体目录结构如下图所示。
需要注意MainPage文件需要@Entry注解,标识为页面
这里贴一下mainpage文件完整的源码, 主要是定义一个tabs组件。
import CommonConstants from '../common/constants/CommonConstants';
import Add from '../view/Add';
import Home from "../view/Home"
import Setting from "../view/Setting"
/**
* Main page
*/
@Entry
@Component
struct MainPage {
@State currentIndex: number = CommonConstants.HOME_TAB_INDEX;
private tabsController: TabsController = new TabsController();
@Builder TabBuilder(title: string, index: number, selectedImg: Resource, normalImg: Resource) {
Column() {
Image(this.currentIndex === index ? selectedImg : normalImg)
.width($r('app.float.mainPage_baseTab_size'))
.height($r('app.float.mainPage_baseTab_size'))
Text(title)
.margin({ top: $r('app.float.mainPage_baseTab_top') })
.fontSize($r('app.float.main_tab_fontSize'))
.fontColor(this.currentIndex === index ? $r('app.color.mainPage_selected') : $r('app.color.mainPage_normal'))
}
.justifyContent(FlexAlign.Center)
.height($r('app.float.mainPage_barHeight'))
.width(CommonConstants.FULL_PARENT)
.onClick(() => {
this.currentIndex = index;
this.tabsController.changeIndex(this.currentIndex);
})
}
build() {
Tabs({
barPosition: BarPosition.End,
controller: this.tabsController
}) {
TabContent() {
Home()
}
.padding({ left: $r('app.float.mainPage_padding'), right: $r('app.float.mainPage_padding') })
.backgroundColor($r('app.color.mainPage_backgroundColor'))
.tabBar(this.TabBuilder(CommonConstants.HOME_TITLE, CommonConstants.HOME_TAB_INDEX,
$r('app.media.home_selected'), $r('app.media.home_normal')))
TabContent() {
Setting()
}
.padding({ left: $r('app.float.mainPage_padding'), right: $r('app.float.mainPage_padding') })
.backgroundColor($r('app.color.mainPage_backgroundColor'))
.tabBar(this.TabBuilder(CommonConstants.MINE_TITLE, CommonConstants.MINE_TAB_INDEX,
$r('app.media.mine_selected'), $r('app.media.mine_normal')))
}
.width(CommonConstants.FULL_PARENT)
.backgroundColor(Color.White)
.barHeight($r('app.float.mainPage_barHeight'))
.barMode(BarMode.Fixed)
.onChange((index: number) => {
this.currentIndex = index;
})
}
}
创建Setting页面
setting页面比较简单,展示一个登录用户信息和退出登录按钮。
效果图如下
完整代码就不再贴了,功能比较简单。接下来重点是首页。
创建Home主页
首页规划元素如下。
顶部是一个文字标题、接下来是轮播图、分类列表、瀑布流卡片列表。
整个首页主要为UI层,完整代码如下。
import CommonConstants from '../common/constants/CommonConstants';
import mainViewModel from '../viewmodel/MainViewModel';
import ItemData from '../viewmodel/ItemData';
import WaterFlowComponent from './WaterFlowComponent';
import { promptAction, router } from '@kit.ArkUI';
import Constants from '../common/constants/Constants';
import { httpRequestGet } from '../common/utils/HttpUtil';
import ResponseResult from '../viewmodel/ResponseResult';
/**
* Home tab content
*/
@Component
@Preview
export default struct Home {
private swiperController: SwiperController = new SwiperController();
build() {
Column() {
Scroll() {
Column({ space: CommonConstants.COMMON_SPACE }) {
Column() {
Text($r('app.string.mainPage_tabTitles_home'))
.fontWeight(FontWeight.Medium)
.fontSize($r('app.float.page_title_text_size'))
.margin({ top: $r('app.float.mainPage_tabTitles_margin') })
.padding({ left: $r('app.float.mainPage_tabTitles_padding') })
}
.width(CommonConstants.FULL_PARENT)
.alignItems(HorizontalAlign.Start)
Swiper(this.swiperController) {
ForEach(mainViewModel.getSwiperImages(), (img: Resource) => {
Image(img).borderRadius($r('app.float.home_swiper_borderRadius'))
}, (img: Resource) => JSON.stringify(img.id))
}
.margin({ top: $r('app.float.home_swiper_margin') })
.autoPlay(true)
.borderRadius($r('app.float.home_swiper_borderRadius'))
Text('分类')
.fontSize($r('app.float.normal_text_size'))
.fontWeight(FontWeight.Medium)
.width(CommonConstants.FULL_PARENT)
.margin({ top: $r('app.float.home_text_margin') })
Grid() {
GridItem() {
Column() {
Text('全部')
.fontColor(Color.White)
Text('全部作品展示')
.margin({ top: $r('app.float.home_list_margin') })
.fontSize($r('app.float.little_text_size'))
.fontColor(Color.White)
}
.alignItems(HorizontalAlign.Start)
}.columnStart(1).columnEnd(2)
.onClick(() => {
router.pushUrl({ url: 'pages/IndexPage' });
})
.padding({ top: $r('app.float.home_list_padding'), left: $r('app.float.home_list_padding') })
.borderRadius($r('app.float.home_backgroundImage_borderRadius'))
.align(Alignment.TopStart)
.backgroundImage($r("app.media.home_fenlei_1"))
.backgroundImageSize(ImageSize.Cover)
.width(CommonConstants.FULL_PARENT)
.height(CommonConstants.FULL_PARENT)
.clickEffect({
level: ClickEffectLevel.MIDDLE,
scale: 0.8
})
GridItem() {
Column() {
Text('石膏娃娃')
.fontSize($r('app.float.normal_text_size'))
.fontWeight(FontWeight.Medium)
.fontColor(Color.White)
Text('彩绘石膏娃娃')
.margin({ top: $r('app.float.home_list_margin') })
.fontSize($r('app.float.little_text_size'))
.fontColor($r('app.color.home_grid_fontColor'))
.fontColor(Color.White)
}
.alignItems(HorizontalAlign.Start)
}
.padding({ top: $r('app.float.home_list_padding'), left: $r('app.float.home_list_padding') })
.borderRadius($r('app.float.home_backgroundImage_borderRadius'))
.align(Alignment.TopStart)
.backgroundImage($r("app.media.home_fenlei_3"))
.backgroundImageSize(ImageSize.Cover)
.width(CommonConstants.FULL_PARENT)
.height(CommonConstants.FULL_PARENT)
.clickEffect({
level: ClickEffectLevel.MIDDLE,
scale: 0.8
}).onClick((secondItem) => {
httpRequestGet(`${CommonConstants.API_URL}/getArt`).then((data: ResponseResult) => {
let arr1 = []
let arr2 = []
data.data.forEach((item: ESObject, key: string) => {
if (item.category === 1) {
arr1 = arr1.concat(item.images)
} else if (item.category === 2) {
arr2 = arr2.concat(item.images)
}
})
router.pushUrl({
url: Constants.URL_LIST_PAGE,
params: { photoArr: arr1 }
});
})
})
GridItem() {
Column() {
Text('手工DIY')
.fontSize($r('app.float.normal_text_size'))
.fontWeight(FontWeight.Medium)
.fontColor(Color.White)
Text('手工DIY')
.margin({ top: $r('app.float.home_list_margin') })
.fontSize($r('app.float.little_text_size'))
.fontColor($r('app.color.home_grid_fontColor'))
.fontColor(Color.White)
}
.alignItems(HorizontalAlign.Start)
}
.padding({ top: $r('app.float.home_list_padding'), left: $r('app.float.home_list_padding') })
.borderRadius($r('app.float.home_backgroundImage_borderRadius'))
.align(Alignment.TopStart)
.backgroundImage($r("app.media.home_fenlei_4"))
.backgroundImageSize(ImageSize.Cover)
.width(CommonConstants.FULL_PARENT)
.height(CommonConstants.FULL_PARENT)
.clickEffect({
level: ClickEffectLevel.MIDDLE,
scale: 0.8
}).onClick((secondItem) => {
httpRequestGet(`${CommonConstants.API_URL}/getArt`).then((data: ResponseResult) => {
let arr1 = []
let arr2 = []
data.data.forEach((item: ESObject, key: string) => {
if (item.category === 1) {
arr1 = arr1.concat(item.images)
} else if (item.category === 2) {
arr2 = arr2.concat(item.images)
}
})
router.pushUrl({
url: Constants.URL_LIST_PAGE,
params: { photoArr: arr2 }
});
})
})
}
.width(CommonConstants.FULL_PARENT)
.height($r('app.float.home_secondGrid_height'))
.columnsTemplate('1fr 1fr')
.rowsTemplate('1fr 1fr')
.columnsGap($r('app.float.home_grid_columnsGap'))
.rowsGap($r('app.float.home_grid_rowGap'))
Column({ space: CommonConstants.COMMON_SPACE }) {
Text('列表')
.fontSize($r('app.float.normal_text_size'))
.fontWeight(FontWeight.Medium)
.width(CommonConstants.FULL_PARENT)
.margin({ top: $r('app.float.home_text_margin') })
WaterFlowComponent()
}
}
}
.scrollBar(BarState.Off)
.width("100%").height("100%")
.onReachStart(() => {
// promptAction.showToast({ message: '到顶' })
})
.onReachEnd(() => {
// promptAction.showToast({ message: '到底' })
})
}
}
}
其中提取了 WaterFlowComponent() 为瀑布流的组件。
瀑布流展示效果如下图所示。
在这里可能会遇到一个问题,Scroll组件和瀑布流的组件滑动有冲突!解决办法在WaterFlowComponent组件中。
主要是在WaterFlow组件中设置nestedScroll属性。
WaterFlowComponent的源码如下。
import ProductItem from '../viewmodel/ProductItem';
import { WaterFlowDataSource } from '../viewmodel/WaterFlowDataSource';
import Const from '../common/constants/CommonConstants';
import { waterFlowData } from '../viewmodel/HomeViewModel';
import FlowItemComponent from '../view/FlowItemComponent';
import { httpRequestPost } from '../common/utils/HttpUtil';
import CommonConstants from '../common/constants/CommonConstants';
import ResponseResult from '../viewmodel/ResponseResult';
import { router } from '@kit.ArkUI';
/**
* Water flow component.
*
* Usage: Directly reference WaterFlowComponent().
*/
@Component
export default struct WaterFlowComponent {
@State listPosition: number = 0; // 0代表滚动到List顶部,1代表中间值,2代表滚动到List底部。
private datasource: WaterFlowDataSource = new WaterFlowDataSource();
@State ArrData: Array<object | undefined> = [];
aboutToAppear() {
httpRequestPost(`${CommonConstants.API_URL}/getArt`).then((data: ResponseResult) => {
// this.dataArray = data.data || []
this.ArrData = data.data
})
}
build() {
WaterFlow({ footer: (): void => this.itemFoot() }) {
ForEach(this.ArrData, (item: ESObject) => {
FlowItem() {
FlowItemComponent({ item: item })
.clickEffect({
level: ClickEffectLevel.MIDDLE,
scale: 0.8
}).onClick(() => {
router.pushUrl({
url: 'pages/ArtDetail',
params: {
id: item?._id || ''
}
})
})
}
}, (item: ProductItem) => JSON.stringify(item))
}
.nestedScroll({ scrollForward: NestedScrollMode.PARENT_FIRST, scrollBackward: NestedScrollMode.SELF_FIRST })
.layoutWeight(Const.WATER_FLOW_LAYOUT_WEIGHT)
.layoutDirection(FlexDirection.Column)
.columnsTemplate(Const.WATER_FLOW_COLUMNS_TEMPLATE)
.columnsGap($r('app.float.water_flow_columns_gap'))
.rowsGap($r('app.float.water_flow_row_gap'))
}
@Builder
itemFoot() {
Column() {
Text($r('app.string.footer_text'))
.fontColor(Color.Gray)
.fontSize($r('app.float.footer_text_size'))
.width(Const.FULL_WIDTH)
.height($r('app.float.footer_text_height'))
.textAlign(TextAlign.Center)
}
}
}
本次也可以当成Scroll组件和WaterFlow组件嵌套使用的一个案例。未做触底加载更多的逻辑,但是保留了其方法。方便后续实现。
后续详情页面和相册页面,再做一个小篇幅的介绍。本次更多的是代码上的演示。主要通过代码来介绍的是UI层的构建思路。
©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
标签
已于2024-7-29 16:44:50修改
赞
1
收藏
回复
相关推荐