HarmonyOS鸿蒙Next中如何解决使用组件componentSnapshot长列表截图不全问题
HarmonyOS鸿蒙Next中如何解决使用组件componentSnapshot长列表截图不全问题
【问题现象】
将一个列表的视图内容保存到本地一张图片,使用组件componentSnapshot.get
以及componentSnapshot.createFromBuilder
都无法获取视图完整内容;例如Scroll
组件有2屏的内容,需要将2屏的内容截图保存,componentSnapshot
截不完整。
问题现象如下:
【定位思路】
首先需确认ohos.arkui.componentSnapshot
模块提供获取组件截图的能力,是否能截取超过组件区域的内容。
【解决方案】
- 截长图需要使用滚动拼接,并计算好滚动距离,拼接的代码如下:
// 长屏拼接截图
createSnap = async () => {
let i = 0
// 这个判断条件可以优化,根据scroll的实际长度和一屏长度,计算次数
while (!this.scroller.isAtEnd()) {
// 一定要放在最上面
this.scroller.scrollPage({ next: true })
// 默认单位都是vp
// 图片资源,绘制区域左上角在x轴的位置,绘制区域左上角在y 轴的位置,绘制区域的宽度,绘制区域的高度
let curSnip: image.PixelMap = await componentSnapshot.get("builder")
this.offContext.drawImage(curSnip, 0, this.ScrollHeight * i, this.scrollWidth, 2000);
i++
}
this.pixmap = this.offContext.getPixelMap(0, 0, this.screenWidth, this.screenHeight); // 2100也可以优化,我这里随便写的数字
}
拼接完成后,将图片保存即可。
完整流程如下:
import componentSnapshot from '@ohos.arkui.componentSnapshot'
import image from '@ohos.multimedia.image'
import { common } from '@kit.AbilityKit';
import window from '@ohos.window';
@Entry
@Component
struct Index {
private context = getContext(this) as common.UIAbilityContext;
private settings: RenderingContextSettings = new RenderingContextSettings(true);
private canvasContext: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 2100)
private offContext = this.offCanvas.getContext("2d", this.settings)
@State pixmap: image.PixelMap | undefined = undefined
@State scrollWidth: number = 0
@State ScrollHeight: number = 0
@State screenWidth: number = 0
@State screenHeight: number = 0
@State shareStas: boolean = false
scroller: Scroller = new Scroller()
private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
aboutToAppear(): void {
window.getLastWindow(this.context, (err, data) => {
if (err.code) {
console.error('Failed to obtain the top window. Cause: ' + JSON.stringify(err));
return;
}
let properties = data.getWindowProperties();
// 单位px 转成 vp
this.screenWidth = px2vp(properties.windowRect.width)
this.screenHeight = px2vp(properties.windowRect.height)
console.info('window. Data: ' + this.screenWidth + '-------' + this.screenHeight);
});
}
// 长屏拼接截图
createSnap = async () => {
let i = 0
// 这个判断条件可以优化,根据scroll的实际长度和一屏长度,计算次数
while (!this.scroller.isAtEnd()) {
// 一定要放在最上面
this.scroller.scrollPage({ next: true })
// 默认单位都是vp
// 图片资源,绘制区域左上角在x轴的位置,绘制区域左上角在y 轴的位置,绘制区域的宽度,绘制区域的高度
let curSnip: image.PixelMap = await componentSnapshot.get("builder")
this.offContext.drawImage(curSnip, 0, this.ScrollHeight * i, this.scrollWidth, this.ScrollHeight);
i++
}
this.pixmap = this.offContext.getPixelMap(0, 0, this.screenWidth, 2100); // 2100也可以优化,我这里随便写的数字
}
build() {
Stack() {
Scroll(this.scroller) {
Column() {
ForEach(this.arr, (item: number) => {
Text(item.toString())
.width('90%')
.height(150)
.backgroundColor(Color.Orange)
.borderRadius(15)
.fontSize(16)
.textAlign(TextAlign.Center)
.margin({ top: 10 })
}, (item: string) => item)
}.width('100%')
}
.scrollable(ScrollDirection.Vertical) // 滚动方向纵向
.scrollBar(BarState.On) // 滚动条常驻显示
.scrollBarColor(Color.Gray) // 滚动条颜色
.scrollBarWidth(10) // 滚动条宽度
.friction(0.6)
.edgeEffect(EdgeEffect.None)
.onScrollEdge((side: Edge) => {
console.info('To the edge')
})
.onReachStart(() => {
// init会默认触发一次,shareStas 标记
if (this.shareStas) {
this.createSnap()
}
console.log('onReachStart----------')
})
.onScrollStop(() => {
console.info('Scroll Stop')
})
.onAreaChange((oldValue: Area, newValue: Area) => {
// 单位是vp
this.scrollWidth = newValue.width as number;
this.ScrollHeight = newValue.height as number
console.log(`Scroll component width: ${this.scrollWidth}, height: ${this.ScrollHeight}`);
})
.id("builder")
Scroll() {
Column() {
Button('生成截图')
.onClick(() => {
const yOffset: number = this.scroller.currentOffset().yOffset;
console.log('yOffset----', yOffset)
if (yOffset !== 0) {
// scroll 没有置顶
this.shareStas = true;
this.scroller.scrollEdge(Edge.Top)
} else {
this.createSnap()
}
})
Image(this.pixmap)
.border({ color: Color.Black, width: 2 })
}
}.backgroundColor(Color.Red)
}
}
}
【总结】
使用代码实现长截图,可参考上述Demo,滚动拼接方式实现;
若有Web组件网页长截图,可参考Web组件长截图方案。
更多关于HarmonyOS鸿蒙Next中如何解决使用组件componentSnapshot长列表截图不全问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html
1 回复
更多关于HarmonyOS鸿蒙Next中如何解决使用组件componentSnapshot长列表截图不全问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙Next中,使用componentSnapshot
截取长列表时,若出现截图不全问题,可通过滚动拼接方式解决。具体步骤如下:
- 使用
Scroller
组件控制滚动,逐屏截取内容。 - 通过
componentSnapshot.get
获取每屏截图,并利用OffscreenCanvas
进行拼接。 - 计算滚动距离,确保每屏截图无缝拼接。
- 最终将拼接后的图片保存。
示例代码:
createSnap = async () => {
let i = 0
while (!this.scroller.isAtEnd()) {
this.scroller.scrollPage({ next: true })
let curSnip: image.PixelMap = await componentSnapshot.get("builder")
this.offContext.drawImage(curSnip, 0, this.ScrollHeight * i, this.scrollWidth, this.ScrollHeight);
i++
}
this.pixmap = this.offContext.getPixelMap(0, 0, this.screenWidth, 2100);
}
完整流程可参考上述代码实现。