提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
提示:这里可以添加本文要记录的大概内容:
综合运用本学期所学内容及个人自学知识,使用HarmonyOS 4.0 及以上版本开发一款具有实用性和创新性的移动应用软件。
提示:以下是本篇文章正文内容,下面案例可供参考
一、项目名称:黑马健康运动
示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。
二、应用运行过程4
1.一次开发多端部署
运行截图:
代码如下:
BreakpointConstants.ets
import BreakpointType from '../bean/BreanpointType';
export default class BreakpointConstants {
/**
* 小屏幕设备的 Breakpoints 标记.
*/
static readonly BREAKPOINT_SM: string = 'sm';
/**
* 中等屏幕设备的 Breakpoints 标记.
*/
static readonly BREAKPOINT_MD: string = 'md';
/**
* 大屏幕设备的 Breakpoints 标记.
*/
static readonly BREAKPOINT_LG: string = 'lg';
/**
* 当前设备的 breakpoints 存储key
*/
static readonly CURRENT_BREAKPOINT: string = 'currentBreakpoint';
/**
* 小屏幕设备宽度范围.
*/
static readonly RANGE_SM: string = '(320vp<=width<600vp)';
/**
* 中屏幕设备宽度范围.
*/
static readonly RANGE_MD: string = '(600vp<=width<840vp)';
/**
* 大屏幕设备宽度范围.
*/
static readonly RANGE_LG: string = '(840vp<=width)';
static readonly BAR_POSITION: BreakpointType<BarPosition> = new BreakpointType({
sm: BarPosition.End,
md: BarPosition.Start,
lg: BarPosition.Start,
})
}
BreakpointSystem.ets
代码如下:
import mediaQuery from '@ohos.mediaquery'
import BreakpointConstants from '../constants/BreakpointConstants'
export default class BreakpointSystem{
private smListener: mediaQuery.MediaQueryListener = mediaQuery.matchMediaSync(BreakpointConstants.RANGE_SM)
private mdListener: mediaQuery.MediaQueryListener = mediaQuery.matchMediaSync(BreakpointConstants.RANGE_MD)
private lgListener: mediaQuery.MediaQueryListener = mediaQuery.matchMediaSync(BreakpointConstants.RANGE_LG)
smListenerCallback(result: mediaQuery.MediaQueryResult){//给监听器绑定回调函数
if(result.matches){//是否匹配
this.updateCurrentBreakpoint(BreakpointConstants.BREAKPOINT_SM)
}
}
mdListenerCallback(result: mediaQuery.MediaQueryResult){
if(result.matches){
this.updateCurrentBreakpoint(BreakpointConstants.BREAKPOINT_MD)
}
}
lgListenerCallback(result: mediaQuery.MediaQueryResult){
if(result.matches){
this.updateCurrentBreakpoint(BreakpointConstants.BREAKPOINT_LG)
}
}
updateCurrentBreakpoint(breakpoint: string){
AppStorage.SetOrCreate(BreakpointConstants.CURRENT_BREAKPOINT, breakpoint)
}
register(){//注册回调函数
this.smListener.on('change', this.smListenerCallback.bind(this))
this.mdListener.on('change', this.mdListenerCallback.bind(this))
this.lgListener.on('change', this.lgListenerCallback.bind(this))
}
unregister(){//取消监听
this.smListener.off('change', this.smListenerCallback.bind(this))
this.mdListener.off('change', this.mdListenerCallback.bind(this))
this.lgListener.off('change', this.lgListenerCallback.bind(this))
}
}
2.数据模型记录项
记录项 饮食或运动
记录项类型:类型id,类型名称
饮食记录中的记录项,可以是食物或运动:id;名称name;图片image;分类id categoryId;单位unit;包含的卡路里;碳水含量;蛋白质含量;脂肪含量
运行截图:
ItemModel.ets
代码如下:
import GroupInfo from '../viewmodel/GroupInfo'
import RecordItem from '../viewmodel/RecordItem'
import { FoodCategories, FoodCategoryEnum, WorkoutCategories, WorkoutCategoryEnum } from './ItemCategoryModel'
const foods: RecordItem[] = [
new RecordItem(0,'米饭',$r('app.media.rice'),FoodCategoryEnum.STAPLE,'碗',209,46.6,4.7,0.5),
new RecordItem(1,'馒头',$r('app.media.steamed_bun'),FoodCategoryEnum.STAPLE,'个',114,24.0,3.6,0.6),
new RecordItem(2,'面包',$r('app.media.bun'),FoodCategoryEnum.STAPLE,'个',188,35.2,5.0,3.1),
new RecordItem(3,'全麦吐司',$r('app.media.toast'),FoodCategoryEnum.STAPLE,'片',91,15.5,4.4,1.3),
new RecordItem(4,'紫薯',$r('app.media.purple_potato'),FoodCategoryEnum.STAPLE,'个',163,42.0,1.6,0.4),
new RecordItem(5,'煮玉米',$r('app.media.corn'),FoodCategoryEnum.STAPLE,'根',111,22.6,4.0,1.2),
new RecordItem(6,'黄瓜',$r('app.media.cucumber'),FoodCategoryEnum.FRUIT,'根',29,5.3,1.5,0.4),
new RecordItem(7,'蓝莓',$r('app.media.blueberry'),FoodCategoryEnum.FRUIT,'盒',71,18.1,0.9,0.4),
new RecordItem(8,'草莓',$r('app.media.strawberry'),FoodCategoryEnum.FRUIT,'颗',14,3.1,0.4,0.1),
new RecordItem(9,'奇异果',$r('app.media.kiwi'),FoodCategoryEnum.FRUIT,'个',25,8.4,0.5,0.3),
new RecordItem(10,'煮鸡蛋',$r('app.media.egg'),FoodCategoryEnum.MEAT,'个',74,0.1,6.2,5.4),
new RecordItem(11,'煮鸡胸肉',$r('app.media.chicken_breast'),FoodCategoryEnum.MEAT,'克',1.15,0.011,0.236,0.092),
new RecordItem(12,'煮鸡腿肉',$r('app.media.chicken_leg'),FoodCategoryEnum.MEAT,'克',1.87,0.0,0.243,0.092),
new RecordItem(13,'牛肉',$r('app.media.beef'),FoodCategoryEnum.MEAT,'克',1.22,0.0,0.23,0.033),
new RecordItem(14,'鱼肉',$r('app.media.fish'),FoodCategoryEnum.MEAT,'克',1.04,0.0,0.206,0.024),
new RecordItem(15,'牛奶',$r('app.media.milk'),FoodCategoryEnum.MEAT,'毫升',0.66,0.05,0.03,0.038),
new RecordItem(16,'酸奶',$r('app.media.yogurt'),FoodCategoryEnum.MEAT,'毫升',0.7,0.10,0.032,0.019),
new RecordItem(17,'核桃',$r('app.media.walnut'),FoodCategoryEnum.NUT,'颗',42,1.2,1.0,3.8),
new RecordItem(18,'花生',$r('app.media.peanut'),FoodCategoryEnum.NUT,'克',3.13,0.13,0.12,0.254),
new RecordItem(19,'腰果',$r('app.media.cashew'),FoodCategoryEnum.NUT,'克',5.59,0.416,0.173,0.367),
new RecordItem(20,'无糖拿铁',$r('app.media.coffee'),FoodCategoryEnum.OTHER,'毫升',0.43,0.044,0.013,0.01),
new RecordItem(21,'豆浆',$r('app.media.soybean_milk'),FoodCategoryEnum.OTHER,'毫升',0.31,0.01,0.013,0.01),
]
const workouts: RecordItem[] = [
new RecordItem(10000,'散步',$r('app.media.ic_walk'),WorkoutCategoryEnum.WALKING,'小时',111),
new RecordItem(10001,'快走',$r('app.media.ic_walk'),WorkoutCategoryEnum.WALKING,'小时',343),
new RecordItem(10002,'慢跑',$r('app.media.ic_running'),WorkoutCategoryEnum.RUNNING,'小时',472),
new RecordItem(10003,'快跑',$r('app.media.ic_running'),WorkoutCategoryEnum.RUNNING,'小时',652),
new RecordItem(10004,'自行车',$r('app.media.ic_ridding'),WorkoutCategoryEnum.RIDING,'小时',497),
new RecordItem(10005,'动感单车',$r('app.media.ic_ridding'),WorkoutCategoryEnum.RIDING,'小时',587),
new RecordItem(10006,'瑜伽',$r('app.media.ic_aerobics'),WorkoutCategoryEnum.AEROBICS,'小时',172),
new RecordItem(10007,'健身操',$r('app.media.ic_aerobics'),WorkoutCategoryEnum.AEROBICS,'小时',429),
new RecordItem(10008,'游泳',$r('app.media.ic_swimming'),WorkoutCategoryEnum.SWIMMING,'小时',472),
new RecordItem(10009,'冲浪',$r('app.media.ic_swimming'),WorkoutCategoryEnum.SWIMMING,'小时',429),
new RecordItem(10010,'篮球',$r('app.media.ic_basketball'),WorkoutCategoryEnum.BALLGAME,'小时',473),
new RecordItem(10011,'足球',$r('app.media.ic_football'),WorkoutCategoryEnum.BALLGAME,'小时',515),
new RecordItem(10012,'排球',$r('app.media.ic_volleyball'),WorkoutCategoryEnum.BALLGAME,'小时',403),
new RecordItem(10013,'羽毛球',$r('app.media.ic_badminton'),WorkoutCategoryEnum.BALLGAME,'小时',385),
new RecordItem(10014,'乒乓球',$r('app.media.ic_table_tennis'),WorkoutCategoryEnum.BALLGAME,'小时',366),
new RecordItem(10015,'哑铃飞鸟',$r('app.media.ic_dumbbell'),WorkoutCategoryEnum.STRENGTH,'小时',388),
new RecordItem(10016,'哑铃卧推',$r('app.media.ic_dumbbell'),WorkoutCategoryEnum.STRENGTH,'小时',422),
new RecordItem(10017,'仰卧起坐',$r('app.media.ic_sit_up'),WorkoutCategoryEnum.STRENGTH,'小时',515),
]
class ItemModel{
getById(id: number, isFood: boolean = true){
return isFood ? foods[id] :workouts[id - 10000]
}
list(isFood: boolean = true): RecordItem[]{
return isFood ? foods:workouts
}
listItemGroupByCategory(isFood: boolean = true){
//1.判断要处理的是食物还是运动
let categories = isFood ? FoodCategories : WorkoutCategories
let items = isFood ? foods: workouts
//2.创建空的分组
let groups = categories.map(itemCategory => new GroupInfo(itemCategory,[]))//映射,遍历前面数组的每一个元素,把当前元素转换成另一种元素
//3.遍历食记录项列表,将食物添加到对应的分组
items.forEach(item => groups[item.categoryId].items.push(item))
//4.返回结果
return groups
}
}
let itemModel = new ItemModel()
export default itemModel as ItemModel
ItemList.ets
代码如下:
import { CommonConstants } from '../../common/constants/CommonConstants'
import ItemModel from '../../model/ItemModel'
import GroupInfo from '../../viewmodel/GroupInfo'
import ItemCategory from '../../viewmodel/ItemCategory'
import RecordItem from '../../viewmodel/RecordItem'
@Component
export default struct ItemList {
showPanel:(item: RecordItem) => void
@Prop isFood: boolean
build() {
Tabs(){
TabContent(){
this.TabContentBuilder(ItemModel.list(this.isFood))
}
.tabBar('全部')
ForEach(
ItemModel.listItemGroupByCategory(this.isFood),
(group:GroupInfo<ItemCategory, RecordItem>) =>{
TabContent(){
this.TabContentBuilder(group.items)
}
.tabBar(group.type.name)
})
}
.width(CommonConstants.THOUSANDTH_940)
.height('100%')
.barMode(BarMode.Scrollable)
}
@Builder TabContentBuilder(items: RecordItem[]){
List({space:CommonConstants.SPACE_10}){
ForEach(items,(item: RecordItem) => {
ListItem(){
Row({space:CommonConstants.SPACE_6}){
Image(item.image).width(50)
Column({space:CommonConstants.SPACE_4}){
Text(item.name).fontWeight(CommonConstants.FONT_WEIGHT_500)
Text(`${item.calorie}千卡/${item.unit}`).fontSize(14).fontColor($r('app.color.light_gray'))
}
Blank()
Image($r('app.media.ic_public_add_norm_filled'))
.width(18)
.fillColor($r('app.color.primary_color'))
}
.width('100%')
.padding(CommonConstants.SPACE_6)
}
.onClick(() => this.showPanel(item))
})
}
.width('100%')
.height('100%')
}
}
3.数据模型—饮食记录
RecordModel.ets
代码如下:
import relationalStore from '@ohos.data.relationalStore'
import { ColumnInfo, ColumnType } from '../common/bean/ColumnInfo'
import RecordPO from '../common/bean/RecordPO'
import DbUtil from '../common/utils/DbUtil'
/**
* 数据库建表语句
*/
const CREATE_TABLE_SQL: string = `
CREATE TABLE IF NOT EXISTS record (
id INTEGER PRIMARY KEY AUTOINCREMENT,
type_id INTEGER NOT NULL,
item_id INTEGER NOT NULL,
amount DOUBLE NOT NULL,
create_time INTEGER NOT NULL
)
`
const COLUMNS: ColumnInfo[] = [
{name: 'id', columnName: 'id', type: ColumnType.LONG},
{name: 'typeId', columnName: 'type_id', type: ColumnType.LONG},
{name: 'itemId', columnName: 'item_id', type: ColumnType.LONG},
{name: 'amount', columnName: 'amount', type: ColumnType.DOUBLE},
{name: 'createTime', columnName: 'create_time', type: ColumnType.LONG},
]
const TABLE_NAME = 'record'
const ID_COLUMN = 'id'
const DATE_COLUMN = 'create_time'
class RecordModel {
getCreateTableSql(): string {
return CREATE_TABLE_SQL
}
insert(record: RecordPO){
return DbUtil.insert(TABLE_NAME, record, COLUMNS)
}
deleteById(id: number){
//1.删除条件
let predicates = new relationalStore.RdbPredicates(TABLE_NAME)
predicates.equalTo(ID_COLUMN, id)
//2.删除
return DbUtil.delete(predicates)
}
listByDate(date: number){
//1.查询条件
let predicates = new relationalStore.RdbPredicates(TABLE_NAME)
predicates.equalTo(DATE_COLUMN, date)
//2.查询
return DbUtil.queryForList(predicates, COLUMNS)
}
}
let recordModel = new RecordModel()
export default recordModel as RecordModel
总结
1.一次性开发多端部署
多设备响应式布局,在渲染页面时,利用媒体查询技术动态判断当前屏幕设备大小,根据屏幕大 小不同,来渲染出不同的布局效果。
媒体查询技术:1.导入媒体查询模块 import mediaQuery from ‘@ohos.mediaquery’
2.设置媒体查询条件,并且获取对应的listener
let listener = mediaQuery.matchMediaSync(‘(320vp<=width<600vp)’)
调用方法matchMediaSync,传入媒体查询条件
媒体查询语法规则:媒体类型(screen)、媒体逻辑操作和媒体特征(宽度、高度、屏幕方向…)
3.给listener设置回调函数,当设备状态变化时会执行回调函数
//设置监听回调函数
listener.on(‘change’, result =>{
//判断是否满足媒体查询条件
if(result.matches){
//记录当前设备状态
}
})
4.将设备状态记录到全局状态中
//全局存储
AppStorage.SetOrCreate(‘currentBreakpoint’, ‘SM’)//断点
@StorageProp(‘currentBreakpoint’) currentBreakpoint: String = ‘SM’//用装饰器获取值,所以可以判断。
2.数据模型—记录项
ItemCategory.ets
代码如下:
/**
* 记录项类型
*/
export default class ItemCategory{
/**
* 类型id
*/
id: number
/**
* 类型名称
*/
name: ResourceStr
constructor(id: number, name: ResourceStr) {
this.id = id
this.name = name
}
}
RecordItem.ets
代码如下:
/**
* 饮食记录中的记录项,可以是食物或运动
*/
export default class RecordItem{
/**
* id
*/
id: number
/**
* 名称
*/
name: ResourceStr
/**
* 图片
*/
image: ResourceStr
/**
* 分类id
*/
categoryId: number
/**
* 包含的卡路里
*/
calorie: number
/**
* 单位
*/
unit: ResourceStr
/**
* 碳水含量,单位(克)
*/
carbon: number
/**
* 蛋白质含量,单位(克)
*/
protein: number
/**
* 脂肪含量,单位(克)
*/
fat: number
constructor(id: number, name: ResourceStr, image: ResourceStr,
categoryId: number, unit: ResourceStr, calorie: number,
carbon: number = 0, protein: number = 0, fat: number = 0) {
this.id = id
this.name = name
this.image = image
this.categoryId = categoryId
this.unit = unit
this.calorie = calorie
this.protein = protein
this.fat = fat
this.carbon = carbon
}
}
3.数据模型—饮食记录
数据模型代码:
export default class RecordType{
/**
* 类型id
*/
id: number
/**
* 类型名称
*/
name: ResourceStr
/**
* 类型图标
*/
icon: ResourceStr
/**
* 类型推荐最小卡路里
*/
min: number
/**
* 类型推荐最大卡路里
*/
max: number
constructor(id: number, name: ResourceStr, icon: ResourceStr, min: number = 0, max: number = 0) {
this.id = id
this.name = name
this.icon = icon
this.min = min
this.max = max
}
}
RecordVO.ets
代码如下:
import RecordItem from './RecordItem'
/**
* 饮食记录的页面数据模型
*/
export default class RecordVO {
/**
* 记录id
*/
id: number
/**
* 饮食记录类型
*/
typeId: number
/**
* 卡路里总数
*/
calorie: number
/**
* 记录中的食物或运动信息
*/
recordItem: RecordItem
/**
* 食物数量或运动时长,如果是运动信息则无
*/
amount: number = 0
}
RecordTypeModel.ets
import RecordType from '../viewmodel/RecordType'
enum RecordTypeEnum {
/**
* 早餐
*/
BREAKFAST,
/**
* 午餐
*/
LUNCH,
/**
* 晚餐
*/
DINNER,
/**
* 加餐
*/
EXTRA_MEAL,
/**
* 运动
*/
WORKOUT
}
/**
* 记录类型常量
*/
const RecordTypes: RecordType[] = [
new RecordType(0,$r("app.string.breakfast"),$r("app.media.ic_breakfast"), 423, 592),
new RecordType(1,$r("app.string.lunch"),$r("app.media.ic_lunch"), 592, 761),
new RecordType(2,$r("app.string.dinner"),$r("app.media.ic_dinner"), 423, 592),
new RecordType(3,$r("app.string.extra_meal"),$r("app.media.ic_extra_m"), 0, 169),
new RecordType(4,$r("app.string.workout"),$r("app.media.ic_workout")),
]
export {RecordTypes,RecordTypeEnum}