“答开发者问”之HarmonyOS鸿蒙Next技术问题解析 第8期
“答开发者问”之HarmonyOS鸿蒙Next技术问题解析 第8期 向所有参与社区互助的开发者致以最诚挚的感谢!
特别感谢本期优质答复贡献者:@小夜呆呆、@冉冉同学
社区的蓬勃发展,离不开每一位积极参与者的贡献。本期“答开发者问”栏目,精选自广大热心开发者针对提问帖所贡献的众多优质答复之中。它们不仅是智慧与经验的璀璨结晶,更是“众人拾柴火焰高”这一真理的生动体现。
在此,我们由衷地感谢每一位热心参与、乐于分享的开发者,是你们的热情与智慧,让这个社区充满了生机与活力,每一次的解答都是对技术探索精神的最好诠释。同时,我们也诚挚邀请更多的开发者加入到这场智慧碰撞的盛宴中来。无论是抛出难题寻求解答,还是慷慨解囊分享经验,您的每一份参与都将为鸿蒙开发者社区注入新的活力,推动我们共同前行,在技术的海洋中扬帆远航。
本期问题如下:
- 如何在自定义类中展示带图片的toast?
- 怎么使用colorFilter修改图片的颜色?
- 如何实现一个气泡聊天框?
- 要实现
promptAction.openCustomDialog的弹窗关闭动画完成后蒙层才消失,应该怎么做? - scroll和tabs关联,想让tabBar的标签可以划出屏幕,除了自定义tab以外还有其他办法吗?
答开发者问系列汇总:
往期问题回顾:
"答开发者问"之HarmonyOS技术问题解析 第1期-华为开发者问答 | 华为开发者联盟 (huawei.com)
"答开发者问"之HarmonyOS技术问题解析 第2期-华为开发者问答 | 华为开发者联盟 (huawei.com)
"答开发者问"之HarmonyOS技术问题解析 第3期-华为开发者问答 | 华为开发者联盟 (huawei.com)
"答开发者问"之HarmonyOS技术问题解析 第4期-华为开发者问答 | 华为开发者联盟 (huawei.com)
"答开发者问"之HarmonyOS技术问题解析 第5期-华为开发者问答 | 华为开发者联盟 (huawei.com)
"答开发者问"之HarmonyOS技术问题解析 第6期-华为开发者问答 | 华为开发者联盟 (huawei.com)
"答开发者问"之HarmonyOS技术问题解析 第7期-华为开发者问答 | 华为开发者联盟 (huawei.com)
注意:
更多关于“答开发者问”之HarmonyOS鸿蒙Next技术问题解析 第8期的实战教程也可以访问 https://www.itying.com/category-93-b0.html
问题一:如何在自定义类中展示带图片的toast?
问题描述:
我想在自定义类的方法中调用自定义组件的toast展示,怎么实现呢?
代码如下图,在action方法中,通过接收toast的参数属性值,传给UI组件,最终展示需要的toast效果。这里官方提供的promptAction.showToast是可以正常显示的,但自定义组件不知道应该如何展示?

解决方案:
ArkUI中的自定义组件展示是需要window的,比如所有界面都是EntryAbility中的windowStage.loadContent()执行后,才被展示的。单个页面内部也有UIContext来执行toast/dialog的操作。
可以将UIContext作为参数传入action方法实现,示例demo如下,其余业务逻辑可以自行补充:
import { ComponentContent, UIContext, window } from '[@kit](/user/kit).ArkUI'
import { hilog } from '[@kit](/user/kit).PerformanceAnalysisKit'
class FakeToastManager {
private currentContent: ComponentContent<Object> | undefined = undefined
action(uiContext: UIContext) {
this.currentContent = new ComponentContent<string>(uiContext, wrapBuilder(BuilderFake), '我是传递的内容')
uiContext.getPromptAction().openCustomDialog(this.currentContent, {
autoCancel: false,
alignment: DialogAlignment.Bottom,
isModal: false,
offset: {
dx: 0,
dy: '-90vp'
}
})
setTimeout(() => {
uiContext.getPromptAction().closeCustomDialog(this.currentContent)
}, 2000)
}
// Preview不可用,需要运行在模拟器跟真机
actionFake() {
window.getLastWindow(getContext()).then((windowClass) => {
let uiContext = windowClass.getUIContext()
this.action(uiContext)
})
}
}
[@Entry](/user/Entry)
[@ComponentV2](/user/ComponentV2)
struct Index {
private fakeToast: FakeToastManager = new FakeToastManager()
build() {
Navigation() {
Column() {
Button('Fake Toast').onClick(() => {
this.fakeToast.action(this.getUIContext())
})
Blank()
Text('在fake toast展示时不影响界面点击').onClick(() => {
hilog.debug(0x000000, 'rainrain', 'click ---')
})
}.size({ width: '100%', height: '100%' })
}.size({ width: '100%', height: '100%' })
}
}
[@Builder](/user/Builder)
function BuilderFake(text: string) {
FakeToast({ text: text })
}
[@ComponentV2](/user/ComponentV2)
struct FakeToast {
[@Param](/user/Param) text: string = ''
build() {
Column() {
Text('我是假Toast')
Text(this.text)
}.backgroundColor(Color.Green)
}
}
``>
原链接:
[如何在普通类中调用自定义组件,并正常展示-华为开发者问答 | 华为开发者联盟 (huawei.com)](https://developer.huawei.com/consumer/cn/forum/topic/0203171882627439025?fid=0101587866109860105&pid=0302171892804342012)更多关于“答开发者问”之HarmonyOS鸿蒙Next技术问题解析 第8期的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
问题五:scroll和tabs关联,想让tabBar的标签可以划出屏幕,除了自定义tab以外还有其他办法吗?
问题描述: 如图,除了自定义tab,有没有办法实现tabBar的标签可以划出屏幕?
解决方案: 可以利用calc计算tabs的高度。高度为 100%(List高度) + barHeight高度,这样tabs实际高度超一屏,可以利用scroll滑动把titlebar滑动到上面去。只要高度计算正确,效果就符合预期。参考以下示例,代码为写死高度为60vp的情况,实际情况可以根据onVisibleAreaChange和this.getUIContext().getComponentUtils().getRectangleById()等API算出具体的高度。
补充知识——calc() 函数用于动态计算长度值。
- 需要注意的是,运算符前后都需要保留一个空格,例如:width: calc(100% - 10px);
- 任何长度值都可以使用calc()函数进行计算;
- calc()函数支持 “+”, “-”, “*”, “/” 运算;
- calc()函数使用标准的数学运算优先级规则;
原链接: scroll和tabs关联,想让tabBar的标签能划出屏幕,除了自定义外还有其他办法吗?-华为开发者问答 | 华为开发者联盟 (huawei.com)
问题四:要实现promptAction.openCustomDialog的弹窗关闭动画完成后蒙层才消失,应该怎么做?
问题描述:
使用promptAction.openCustomDialog如何实现,在打开的时候蒙层立马出现,弹窗从底部向上划出;关闭的时候弹窗先向下划出去,然后蒙层再消失?
目前只实现了打开的效果,弹窗关闭的动画好像只有在蒙层消失了才会触发。
export function openActionSheet() {
window.getLastWindow(getContext()).then((windowClass) => {
const uiContext = windowClass.getUIContext()
const promptAction = uiContext.getPromptAction()
let contentNode = new ComponentContent<boolean>(uiContext, wrapBuilder(ActionBuilder), false)
promptAction.openCustomDialog(contentNode, {
autoCancel: true,
alignment: DialogAlignment.Bottom,
transition: TransitionEffect.opacity(0.99).animation({ duration: 200 }),
onWillDismiss: (action) => {
animateTo({
duration: 200,
onFinish: () => {
action.dismiss()
}
}, () => {
contentNode.update(true)
})
}
})
})
}
@Builder
export function ActionBuilder(isEnd: boolean) {
Column() {
Row() {
Text('2173781637163')
}.width('100%').height(40)
Row() {
Text('2173781637163')
}.width('100%').height(59)
Row() {
Text('2173781637163')
}.width('100%').height(90)
}
.translate({
y: isEnd ? '100%' : 0
})
.backgroundColor(Color.White)
.transition(TransitionEffect.translate({ y: '100%' }).animation({ duration: 200 }))
}
解决方案:
可以通过onWillDismiss拦截返回事件,在事件回调中通过animateTo和update自定义关闭动画,以下示例供参考:
export function openActionSheet() {
window.getLastWindow(getContext()).then((windowClass) => {
const uiContext = windowClass.getUIContext()
const promptAction = uiContext.getPromptAction()
let contentNode = new ComponentContent<boolean>(uiContext, wrapBuilder(ActionBuilder), false)
promptAction.openCustomDialog(contentNode, {
autoCancel: true,
alignment: DialogAlignment.Bottom,
transition: TransitionEffect.opacity(0.99).animation({ duration: 200 }),
onWillDismiss: (action) => {
animateTo({
duration: 200,
onFinish: () => {
action.dismiss()
}
}, () => {
contentNode.update(true)
})
}
})
})
}
@Builder
export function ActionBuilder(isEnd: boolean) {
Column() {
Row() {
Text('2173781637163')
}.width('100%').height(40)
Row() {
Text('2173781637163')
}.width('100%').height(59)
Row() {
Text('2173781637163')
}.width('100%').height(90)
}
.translate({
y: isEnd ? '100%' : 0
})
.backgroundColor(Color.White)
.transition(TransitionEffect.translate({ y: '100%' }).animation({ duration: 200 }))
}
问题三:如何实现一个气泡聊天框?
问题描述:
气泡聊天框的内容可能是文字、或图片、或图文混排的,背景是个.9图的气泡图,如何实现呢?
解决方案:
Image组件已经提供了与点九图相同功能的API设置,可以通过设置resizable属性来设置ResizableOptions,也就是图像拉伸时可调整大小的图像选项。ResizableOptions的参数slice中有top、left、bottom和right四个属性,分别代表图片上下左右四个方向拉伸时保持不变距离。参考代码如下:
import { MeasureText } from '@kit.ArkUI'
@Component
struct ChatBubbleStretchDemo {
@State text: string = 'Hello World Hello World Hello World Hello World';
@State left: number = 10;
@State right: number = 10;
@State top: number = 10;
@State bottom: number = 10;
@State line: number = 2;
@State textSize: SizeOptions = MeasureText.measureTextSize({
textContent: this.text
});
build() {
Column() {
Stack() {
Image($r("app.media.lightBluexhdpi"))
.width(px2vp(Number(`${this.textSize.width}`)) < 350 ? 60 + px2vp
(Number(`${this.textSize.width}`)) : 350)
.height(this.text.length < 40 ? 50 + px2vp(Number(`${this.textSize.height}`))
: 50 + (px2vp(Number(`${this.textSize.height}`)) * this.line))
.resizable({
slice: {
top: this.top,
left: this.left,
bottom: this.bottom,
right: this.right
}
})
Text(this.text)
}
.width(350)
.height(200)
}
.height('100%')
.width('100%')
}
}
正常大小
左右拉伸
多行上下左右拉伸
问题二:怎么使用colorFilter修改图片的颜色?
问题描述: 怎么使用colorFilter修改图片的颜色?
解决方案: 参考下面示例,通过colorFilter实现了给图像设置颜色滤镜效果:
import { drawing, common2D } from '@kit.ArkGraphics2D';
@Entry
@Component
struct ImageExample3 {
private imageOne: Resource = $r('app.media.1');
private imageTwo: Resource = $r('app.media.2');
@State src: Resource = this.imageOne
@State src2: Resource = this.imageTwo
private ColorFilterMatrix: number[] = [1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0]
private color: common2D.Color = { alpha: 255, red: 255, green: 0, blue: 0 };
@State drawingColorFilterFirst: ColorFilter | undefined = undefined
@State drawingColorFilterSecond: ColorFilter | undefined = undefined
@State drawingColorFilterThird: ColorFilter | undefined = undefined
build() {
Column() {
Image(this.src)
.width(100)
.height(100)
.colorFilter(this.drawingColorFilterFirst)
.onClick(() =>{
this.drawingColorFilterFirst = drawing.ColorFilter.createBlendModeColorFilter(this.color, drawing.BlendMode.SRC_IN);
})
Image(this.src2)
.width(100)
.height(100)
.colorFilter(this.drawingColorFilterSecond)
.onClick(() =>{
this.drawingColorFilterSecond = new ColorFilter(this.ColorFilterMatrix);
})
//当加载图片为SVG格式时
Image($r('app.media.test_self'))
.width(110).height(110).margin(15)
.colorFilter(this.drawingColorFilterThird)
.onClick(() =>{
this.drawingColorFilterThird = drawing.ColorFilter.createBlendModeColorFilter(this.color, drawing.BlendMode.SRC_IN);
})
}
}
}
在“答开发者问”之HarmonyOS鸿蒙Next技术问题解析第8期中,主要讨论了鸿蒙Next的技术细节和开发相关问题。鸿蒙Next是华为推出的新一代操作系统,旨在构建全场景智能生态。其核心特性包括分布式能力、微内核设计、一次开发多端部署等。
分布式能力是鸿蒙Next的显著特点,支持设备间的无缝协同。开发者可以通过分布式任务调度、分布式数据管理等技术,实现多设备间的数据共享与任务协同。微内核设计则提升了系统的安全性和稳定性,鸿蒙Next采用微内核架构,减少了内核的复杂性,增强了系统的模块化与可扩展性。
鸿蒙Next还提供了丰富的开发工具和框架,如ArkUI、ArkTS等,帮助开发者高效构建应用。ArkUI是鸿蒙的UI框架,支持声明式编程,简化了UI开发流程。ArkTS是基于TypeScript的编程语言,适用于鸿蒙应用开发,提供了类型安全和现代化的语言特性。
此外,鸿蒙Next支持一次开发多端部署,开发者只需编写一次代码,即可在手机、平板、智能穿戴等多种设备上运行应用。这大大降低了开发成本,提升了开发效率。
总体而言,鸿蒙Next通过其分布式能力、微内核设计、丰富的开发工具和一次开发多端部署等特性,为开发者提供了强大的技术支持,助力构建全场景智能生态。
在HarmonyOS鸿蒙Next技术问题解析第8期中,我们深入探讨了鸿蒙Next的核心特性与开发者常见问题。鸿蒙Next作为华为新一代操作系统,强调了分布式能力与跨设备协同,开发者需关注其应用架构、API调用及性能优化。常见问题包括如何实现多设备无缝连接、应用兼容性调试及资源高效管理。建议开发者参考官方文档,利用鸿蒙提供的开发工具链,如DevEco Studio,进行高效开发与测试,以确保应用在鸿蒙Next上的稳定运行与卓越用户体验。


