
回复
@toc
大家好,我是若城!欢迎来到 HarmonyOS 5 开发实战系列。本系列致力于为开发者提供实用的技术方案和即拿即用的代码示例,帮助大家快速掌握 HarmonyOS Next 应用开发中的核心功能。
本篇文章将深入讲解在应用中如何实现自定义文案分享,以及单机应用中如何根据当前时间结合既定时间来处理状态展示。这两个功能在实际开发中非常实用,特别是在内容类应用、工具类应用中有着广泛的应用场景。
如图所示,图中的四个界面截图分别展示了:
在 HarmonyOS 5 中,系统提供了强大的 ShareKit,允许应用将内容分享到其他应用。相比传统的复制粘贴操作,系统分享具有以下优势:
import { SolarTerm } from '../Utils/Type'
import { SolarTerms } from '../Utils/SolarTerms'
import promptAction from '@ohos.promptAction'
import { systemShare } from '@kit.ShareKit'; // 系统分享能力
import { uniformTypeDescriptor as utd } from '@kit.ArkData'; // 统一数据类型描述
import { common } from '@kit.AbilityKit'; // 应用上下文能力
import { BusinessError } from '@kit.BasicServicesKit'; // 业务错误处理
代码解析:
@kit.ShareKit
:提供系统级分享功能@kit.ArkData
:定义数据类型,确保分享内容格式正确@kit.AbilityKit
:获取应用上下文,分享操作需要上下文支持@kit.BasicServicesKit
:处理分享过程中可能出现的错误创建 Utils/Type.ets
文件:
export interface SolarTerm {
/** 节气名称 */
name: string;
/** 节气日期(公历) */
date: string;
/** 节气状态(如"已过"、"今天"、"未到"等) */
status: string;
/** 农历日期说明 */
lunar_date: string;
/** 节气源文本信息 */
source_text: string;
/** 本地图标路径 */
local_icon_path: string;
/** 节气描述 */
description: string;
}
设计说明:
创建 Utils/SolarTerms.ets
文件(仅展示部分):
import {SolarTerm} from "./Type"
export const SolarTerms: SolarTerm[] = [
{
"name": "小寒",
"date": "2025-01-05",
"status": "已过",
"lunar_date": "【 公历1月5、6 或 7日 】",
"source_text": "冬\n已过\n小寒\n2025-01-05\n【 公历1月5、6 或 7日 】",
"local_icon_path": "iconsSolar/XH.png",
"description": "小寒,是二十四节气中的第23个节气,也是冬季的第5个节气..."
},
{
"name": "大寒",
"date": "2025-01-20",
"status": "已过",
"lunar_date": "【 公历1月19、20 或 21日 】",
"source_text": "冬\n已过\n大寒\n2025-01-20\n【 公历1月19、20 或 21日 】",
"local_icon_path": "iconsSolar/DH.png",
"description": "大寒,是二十四节气中的最后一个节气..."
}
// ... 更多数据
]
@State currentSolarTerm: SolarTerm | null = null // 当前选中的节气信息
/**
* 系统分享函数
* @param title 分享标题
* @param content 分享内容
* @param description 分享描述
*/
private async share(title: string, content: string, description: string) {
try {
// 创建分享数据对象
let shareData: systemShare.SharedData = new systemShare.SharedData({
utd: utd.UniformDataType.TEXT, // 指定数据类型为文本
content: content, // 分享的主要内容
title: title, // 分享标题
description: description, // 分享描述
thumbnail: new Uint8Array() // 缩略图(可选)
});
// 创建分享控制器
let controller: systemShare.ShareController = new systemShare.ShareController(shareData);
// 获取UI上下文和应用上下文
const uiContext: UIContext = this.getUIContext();
const context: common.UIAbilityContext = uiContext.getHostContext() as common.UIAbilityContext;
// 显示分享界面
await controller.show(context, {
selectionMode: systemShare.SelectionMode.SINGLE, // 单选模式
previewMode: systemShare.SharePreviewMode.DEFAULT, // 默认预览模式
});
console.log('分享成功');
} catch (error: BusinessError) {
console.error('分享失败:', error);
promptAction.showToast({
message: '分享失败,请重试',
duration: 2000
});
}
}
技术要点解析:
utd.UniformDataType.TEXT
明确指定分享内容为文本类型getUIContext()
和 getHostContext()
获取必要的上下文SelectionMode.SINGLE
:用户只能选择一个目标应用SharePreviewMode.DEFAULT
:使用系统默认的预览样式Button() {
Text('🔗')
.fontSize(20)
}
.width(44)
.height(44)
.borderRadius(22)
.backgroundColor('#FFFFFF')
.shadow({
radius: 8,
color: '#00000015',
offsetY: 2
})
.onClick(() => {
this.shareSolarTerm() // 调用分享处理函数
})
UI 设计说明:
/**
* 分享节气信息的核心处理函数
*/
private shareSolarTerm() {
const solarTerm = this.currentSolarTerm!
// 获取季节信息和表情符号
const season = this.getSeason()
const seasonEmoji = this.getSeasonEmoji()
// 处理描述文本,避免内容过长
const shortDescription = solarTerm.description.length > 100
? solarTerm.description.substring(0, 100) + '...'
: solarTerm.description
// 构建分享标题
const title = `🌟 ${solarTerm.name} ${seasonEmoji}`
// 构建分享内容(使用模板字符串格式化)
const content = `
📅 节气时间:${solarTerm.date}
🗓️ 农历时间:${solarTerm.lunar_date}
🌸 所属季节:${season}
📖 节气介绍:
${shortDescription}
🎯 节气特点:
• 这是二十四节气中的重要节点
• 标志着${season}时节的重要时刻
• 反映了中华民族对自然规律的深刻认识
🏮 民族宝典 - 传承中华文化,探索节气智慧
#二十四节气 #${solarTerm.name} #中华文化 #传统节气`
const description = `节气知识分享`
// 执行分享
this.share(title, content, description)
// 显示成功提示
promptAction.showToast({
message: `已分享${solarTerm.name}节气信息`,
duration: 2000
})
}
内容格式化技巧:
/**
* 根据节气名称获取所属季节
*/
private getSeason(): string {
const name = this.currentSolarTerm!.name
const springTerms = ['立春', '雨水', '惊蛰', '春分', '清明', '谷雨']
const summerTerms = ['立夏', '小满', '芒种', '夏至', '小暑', '大暑']
const autumnTerms = ['立秋', '处暑', '白露', '秋分', '寒露', '霜降']
const winterTerms = ['立冬', '小雪', '大雪', '冬至', '小寒', '大寒']
if (springTerms.includes(name)) return '春季'
if (summerTerms.includes(name)) return '夏季'
if (autumnTerms.includes(name)) return '秋季'
if (winterTerms.includes(name)) return '冬季'
return '未知'
}
/**
* 根据季节获取对应的表情符号
*/
private getSeasonEmoji(): string {
const season = this.getSeason()
switch (season) {
case '春季': return '🌸'
case '夏季': return '☀️'
case '秋季': return '🍂'
case '冬季': return '❄️'
default: return '🌍'
}
}
在很多应用场景中,我们需要根据当前时间与目标时间的关系来显示不同的状态。比如:
如图所示,数据中的 date
字段是目标时间,当前时间是对比基准,通过两者的差值计算出相应的状态。
/**
* 计算节气状态的核心算法
* @param solarTerm 节气数据对象
* @returns 状态字符串
*/
private calculateSolarTermStatus(solarTerm: SolarTerm): string {
const today = new Date()
const solarTermDate = new Date(solarTerm.date)
// 重置时间为当天0点,只比较日期部分
// 这样可以避免时分秒对比较结果的影响
today.setHours(0, 0, 0, 0)
solarTermDate.setHours(0, 0, 0, 0)
// 计算时间差(毫秒)
const timeDiff = today.getTime() - solarTermDate.getTime()
// 转换为天数差
const daysDiff = Math.floor(timeDiff / (1000 * 60 * 60 * 24))
// 根据天数差返回不同状态
if (daysDiff > 0) {
// 目标日期已过
return '已过'
} else if (daysDiff === 0) {
// 目标日期是今天
return '今日'
} else {
// 目标日期在未来
const daysUntil = Math.abs(daysDiff)
if (daysUntil <= 7) {
// 一周内:显示具体天数
return `${daysUntil}天后`
} else if (daysUntil <= 30) {
// 一个月内:显示周数
return `${Math.ceil(daysUntil / 7)}周后`
} else {
// 超过一个月:显示"未到"
return '未到'
}
}
}
算法设计要点:
getTime()
获取时间戳进行精确计算为了让状态显示更加直观,我们为不同状态设计了对应的颜色方案:
/**
* 获取状态对应的文字颜色
*/
private getStatusColor(): string {
const status = this.getCurrentStatus()
if (status === '已过') {
return '#E74C3C' // 红色:表示已过期
} else if (status === '今日') {
return '#F39C12' // 橙色:表示正在进行
} else if (status.includes('天后') || status.includes('周后')) {
return '#3498DB' // 蓝色:表示即将到来
} else {
return '#27AE60' // 绿色:表示较远的未来
}
}
/**
* 获取状态对应的背景颜色
*/
private getStatusBgColor(): string {
const status = this.getCurrentStatus()
if (status === '已过') {
return '#FADBD8' // 浅红色背景
} else if (status === '今日') {
return '#FEF9E7' // 浅橙色背景
} else if (status.includes('天后') || status.includes('周后')) {
return '#EBF3FD' // 浅蓝色背景
} else {
return '#D5F4E6' // 浅绿色背景
}
}
颜色设计原则:
下面是整合了两个核心功能的完整代码示例:
import { SolarTerm } from '../utils/types'
import { SolarTerms } from '../utils/SolarTerms'
import router from '@ohos.router'
import promptAction from '@ohos.promptAction'
import { systemShare } from '@kit.ShareKit';
import { uniformTypeDescriptor as utd } from '@kit.ArkData';
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct SolarTermsDetail {
@State currentSolarTerm: SolarTerm = {
"name": "小寒",
"date": "2025-01-05",
"status": "已过",
"lunar_date": "【 公历1月5、6 或 7日 】",
"source_text": "冬\n已过\n小寒\n2025-01-05\n【 公历1月5、6 或 7日 】",
"local_icon_path": "iconsSolar/XH.png",
"description": "小寒,是二十四节气中的第23个节气,也是冬季的第5个节气。斗指子;太阳黄经为285°;公历1月5-7日交节。小寒,标志着季冬时节的正式开始。冷气积久而寒,小寒是天气寒冷但还没有到极点的意思。它与大寒、小暑、大暑及处暑一样,都是表示气温冷暖变化的节气。小寒的天气特点是:天渐寒,尚未大冷。俗话有讲:"冷在三九",由于隆冬"三九"也基本上处于该节气之内,因此有"小寒胜大寒"之讲法。\n根据中国的气象资料,小寒是气温最低的节气,只有少数年份的大寒气温低于小寒的。小寒时节,我国大部分地区已进入严寒时期,土壤冻结,河流封冻,加之北方冷空气不断南下,天气寒冷,人们叫做"数九寒天"。在我国南方虽然没有北方峻冷凛冽,但是气温亦明显下降。在南方最寒冷的时候是小寒及雨水和惊蛰之间这两个时段。小寒时是干冷,而雨水后是湿冷。"
}
/**
* 系统分享功能实现
*/
private async share(title: string, content: string, description: string) {
try {
let shareData: systemShare.SharedData = new systemShare.SharedData({
utd: utd.UniformDataType.TEXT,
content: content,
title: title,
description: description,
thumbnail: new Uint8Array()
});
let controller: systemShare.ShareController = new systemShare.ShareController(shareData);
const uiContext: UIContext = this.getUIContext();
const context: common.UIAbilityContext = uiContext.getHostContext() as common.UIAbilityContext;
await controller.show(context, {
selectionMode: systemShare.SelectionMode.SINGLE,
previewMode: systemShare.SharePreviewMode.DEFAULT,
});
} catch (error: BusinessError) {
console.error('分享失败:', error);
}
}
build() {
Column({ space: 20 }) {
// 分享按钮
Button(`分享${this.currentSolarTerm?.name}节气`)
.width(200)
.height(44)
.backgroundColor('#007AFF')
.borderRadius(22)
.onClick(() => {
this.shareSolarTerm()
})
// 状态显示
Text(this.calculateSolarTermStatus(this.currentSolarTerm!))
.fontSize(14)
.fontColor(this.getStatusColor())
.backgroundColor(this.getStatusBgColor())
.padding({ left: 12, right: 12, top: 4, bottom: 4 })
.borderRadius(12)
}
.width('100%')
.height('100%')
.padding(20)
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
.linearGradient({
direction: GradientDirection.Bottom,
colors: [['#E8F4FD', 0.0], ['#F8F9FA', 0.3], ['#FFFFFF', 1.0]]
})
}
// ==================== 工具方法 ====================
/**
* 获取节气所属季节
*/
private getSeason(): string {
const name = this.currentSolarTerm!.name
const springTerms = ['立春', '雨水', '惊蛰', '春分', '清明', '谷雨']
const summerTerms = ['立夏', '小满', '芒种', '夏至', '小暑', '大暑']
const autumnTerms = ['立秋', '处暑', '白露', '秋分', '寒露', '霜降']
const winterTerms = ['立冬', '小雪', '大雪', '冬至', '小寒', '大寒']
if (springTerms.includes(name)) return '春季'
if (summerTerms.includes(name)) return '夏季'
if (autumnTerms.includes(name)) return '秋季'
if (winterTerms.includes(name)) return '冬季'
return '未知'
}
/**
* 获取季节对应的表情符号
*/
private getSeasonEmoji(): string {
const season = this.getSeason()
switch (season) {
case '春季': return '🌸'
case '夏季': return '☀️'
case '秋季': return '🍂'
case '冬季': return '❄️'
default: return '🌍'
}
}
/**
* 计算节气状态
*/
private calculateSolarTermStatus(solarTerm: SolarTerm): string {
const today = new Date()
const solarTermDate = new Date(solarTerm.date)
// 重置时间为当天0点,只比较日期
today.setHours(0, 0, 0, 0)
solarTermDate.setHours(0, 0, 0, 0)
const timeDiff = today.getTime() - solarTermDate.getTime()
const daysDiff = Math.floor(timeDiff / (1000 * 60 * 60 * 24))
if (daysDiff > 0) {
return '已过'
} else if (daysDiff === 0) {
return '今日'
} else {
const daysUntil = Math.abs(daysDiff)
if (daysUntil <= 7) {
return `${daysUntil}天后`
} else if (daysUntil <= 30) {
return `${Math.ceil(daysUntil / 7)}周后`
} else {
return '未到'
}
}
}
/**
* 获取当前计算出的状态
*/
private getCurrentStatus(): string {
return this.calculateSolarTermStatus(this.currentSolarTerm!)
}
/**
* 获取状态对应的文字颜色
*/
private getStatusColor(): string {
const status = this.getCurrentStatus()
if (status === '已过') {
return '#E74C3C'
} else if (status === '今日') {
return '#F39C12'
} else if (status.includes('天后') || status.includes('周后')) {
return '#3498DB'
} else {
return '#27AE60'
}
}
/**
* 获取状态对应的背景颜色
*/
private getStatusBgColor(): string {
const status = this.getCurrentStatus()
if (status === '已过') {
return '#FADBD8'
} else if (status === '今日') {
return '#FEF9E7'
} else if (status.includes('天后') || status.includes('周后')) {
return '#EBF3FD'
} else {
return '#D5F4E6'
}
}
/**
* 分享节气信息
*/
private shareSolarTerm() {
const solarTerm = this.currentSolarTerm!
const status = this.calculateSolarTermStatus(solarTerm)
const season = this.getSeason()
const seasonEmoji = this.getSeasonEmoji()
// 获取简短描述(前100个字符)
const shortDescription = solarTerm.description.length > 100
? solarTerm.description.substring(0, 100) + '...'
: solarTerm.description
const title = `🌟 ${solarTerm.name} ${seasonEmoji}`
const content = `
📅 节气时间:${solarTerm.date}
🗓️ 农历时间:${solarTerm.lunar_date}
⏰ 当前状态:${status}
🌸 所属季节:${season}
📖 节气介绍:
${shortDescription}
🎯 节气特点:
• 这是二十四节气中的重要节点
• 标志着${season}时节的重要时刻
• 反映了中华民族对自然规律的深刻认识
🏮 民族宝典 - 传承中华文化,探索节气智慧
#二十四节气 #${solarTerm.name} #中华文化 #传统节气`
const description = `节气知识分享`
this.share(title, content, description)
promptAction.showToast({
message: `已分享${solarTerm.name}节气信息`,
duration: 2000
})
}
}
这两个功能可以广泛应用于:
本文详细介绍了 HarmonyOS 5 中自定义文案分享和时间状态处理的实现方案。通过系统的 ShareKit 和精确的时间算法,我们可以为用户提供优秀的分享体验和直观的状态展示。
这些技术方案不仅适用于节气应用,还可以灵活应用到各种业务场景中。希望本文能够帮助开发者快速掌握这些实用技能,在实际项目中发挥价值。