写点什么

【HarmonyOS】组件长截屏方案

作者:zhongcx
  • 2024-10-09
    广东
  • 本文字数:6531 字

    阅读完需:约 21 分钟

【HarmonyOS】普通组件与 web 组件长截屏方案:原则是利用 Scroll 内的组件可以使用 componentSnapshot 完整的截屏

【普通组件长截屏】


import { componentSnapshot, promptAction } from '@kit.ArkUI'import { common } from '@kit.AbilityKit'import { photoAccessHelper } from '@kit.MediaLibraryKit'import fs from '@ohos.file.fs';import { image } from '@kit.ImageKit';import { BusinessError } from '@kit.BasicServicesKit';
@Entry@Componentstruct Page37 { @State lineHeight: number = 0 // 单行文本的高度 @State pageHeight: number = 0 // 每页的最大高度 @State totalContentHeight: number = 0 // 整个文本内容的高度 @State textContent: string = " " // 文本内容,默认一个空格是为了计算单行文本的高度 @State scrollOffset: number = 0 // 当前滚动偏移量 @State totalPages: number = 1 // 总页数 @State currentPage: number = 1 // 当前页数 scroller: Scroller = new Scroller() // 滚动条实例
resetMaxLineHeight() { if (this.lineHeight > 0 && this.pageHeight > 0 && this.totalContentHeight > 0) { this.pageHeight = (Math.floor(this.pageHeight / this.lineHeight)) * this.lineHeight this.totalPages = Math.ceil(this.totalContentHeight / this.pageHeight) //向上取整得到总页数
} }
build() { Column() { SaveButton().onClick(async (event: ClickEvent, result: SaveButtonOnClickResult) => { if (result === SaveButtonOnClickResult.SUCCESS) { const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // 免去权限申请和权限请求等环节,获得临时授权,保存对应图片 let helper = photoAccessHelper.getPhotoAccessHelper(context); try { // onClick触发后5秒内通过createAsset接口创建图片文件,5秒后createAsset权限收回。 let uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg'); // 使用uri打开文件,可以持续写入内容,写入过程不受时间限制 let file = await fs.open(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); componentSnapshot.get("aaaa").then((pixelMap) => { let packOpts: image.PackingOption = { format: 'image/png', quality: 100 } const imagePacker: image.ImagePacker = image.createImagePacker(); return imagePacker.packToFile(pixelMap, file.fd, packOpts).finally(() => { imagePacker.release(); //释放 fs.close(file.fd); promptAction.showToast({ message: '图片已保存至相册', duration: 2000 }); }); }) } catch (error) { const err: BusinessError = error as BusinessError; console.error(`Failed to save photo. Code is ${err.code}, message is ${err.message}`); }
} else { promptAction.showToast({ message: '设置权限失败!', duration: 2000 }); } }) Text('第一章') .margin({ top: 10, bottom: 10 }) .backgroundColor(Color.Pink) .width('100%') .textAlign(TextAlign.Center)
Column() { Scroll(this.scroller) { Column() { Text(this.textContent) .id('aaaa') .backgroundColor(Color.Orange) .fontSize(20) .lineHeight(40) .fontColor(Color.Black)// .textOverflow({ overflow: TextOverflow.Clip }) .margin({ top: this.scrollOffset }) .onAreaChange((oldArea: Area, newArea: Area) => { if (this.lineHeight == 0 && newArea.height > 0) { this.lineHeight = newArea.height as number this.resetMaxLineHeight() //添加数据测试 let str = "" for (let i = 1; i <= 20; i++) { str += ` ${i}、荣誉和耻辱,是荣辱观中的一对基本范畴,是指社会对人们行为褒贬评价以及人们对这种评价的自我感受。知荣辱,是人性的标志,是人区别于动物、人之为人的重要标准。` } this.textContent = str return } if (this.totalContentHeight != newArea.height) { console.info(`newArea.height:${newArea.height}`) this.totalContentHeight = newArea.height as number this.resetMaxLineHeight() } }) }.hitTestBehavior(HitTestMode.Block) //禁止滑动 }.scrollBar(BarState.Off) .constraintSize({ maxHeight: this.pageHeight == 0 ? 1000 : this.pageHeight })
} .width('100%') .layoutWeight(1)
.onAreaChange((oldArea: Area, newArea: Area) => { if (this.pageHeight == 0 && newArea.height > 0) { this.pageHeight = newArea.height as number this.resetMaxLineHeight() } })
Row() { Button('上一页').onClick(() => { if (this.currentPage == 1) { promptAction.showToast({ message: "没有上一页了" }) return; } this.scrollOffset += this.pageHeight this.currentPage--; }) Text(`${this.currentPage}/${this.totalPages}`) Button('下一页').onClick(() => { if (this.currentPage == this.totalPages) { promptAction.showToast({ message: "没有下一页了" }) return; } this.scrollOffset -= this.pageHeight this.currentPage++; }) }.margin({ top: 10, bottom: 10 }).backgroundColor(Color.Pink).width('100%').justifyContent(FlexAlign.SpaceAround) } .width('100%') .height('100%') .backgroundColor(Color.Gray) }}
复制代码

【web 组件长截屏】

src/main/resources/rawfile/test.html

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8" />    <script>        //用于根据浏览器对 CSS.supports 和 env/constant 的支持情况,动态地调整视口元标签的内容,以达到最佳的页面显示效果。        var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||            CSS.supports('top: constant(a)'))        document.write(            '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +            (coverSupport ? ', viewport-fit=cover' : '') + '" />')    </script>
<title></title> <!--用于设置浏览器页签上显示的小图标 start--> <!-- <link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" /> --> <link rel="stylesheet" href="mycss.css" /> <link rel="icon" href="./static/favicon.ico" /> <!--用于设置浏览器页签上显示的小图标 end--> <!--preload-links--> <!--app-context--></head><body><div>测试测试</div><div>测试测试</div><div>测试测试</div><div>测试测试</div><div>测试测试</div><div>测试测试</div><div>测试测试</div><div>测试测试</div><div>哈哈哈哈</div><div>哈哈哈哈</div><div>哈哈哈哈</div><div>哈哈哈哈</div><div>哈哈哈哈</div><div>哈哈哈哈</div><div>哈哈哈哈</div><div>哈哈哈哈</div><div>1111111</div><div>1111111</div><div>1111111</div><div>1111111</div><div>1111111</div><div>1111111</div><div>1111111</div><div>1111111</div><div>1111111</div><div>2222222</div><div>2222222</div><div>2222222</div><div>2222222</div><div>2222222</div><div>2222222</div><div>2222222</div><div>2222222</div><div>2222222</div><div>2222222</div><div>2222222</div><div>2222222</div><div>2222222</div><div>2222222</div><div>2222222</div><div>2222222</div><div>2222222</div><div>2222222</div><div>aaaaaaa</div><div>aaaaaaa</div><div>aaaaaaa</div><div>aaaaaaa</div><div>aaaaaaa</div><div>aaaaaaa</div><div>aaaaaaa</div><div>aaaaaaa</div><div>aaaaaaa</div><div>aaaaaaa</div><div>aaaaaaa</div><div>aaaaaaa</div><div>aaaaaaa</div><div>bbbbbbb</div><div>bbbbbbb</div><div>bbbbbbb</div><div>bbbbbbb</div><div>bbbbbbb</div><div>bbbbbbb</div><div>bbbbbbb</div><div>bbbbbbb</div><div>bbbbbbb</div><div>bbbbbbb</div><div>bbbbbbb</div><div>bbbbbbb</div><div>bbbbbbb</div><div>bbbbbbb</div><div>到底了</div><div id="webBottom"></div></body><script>
//Android禁止微信调整字体大小 (function() { if (typeof WeixinJSBridge == "object" && typeof WeixinJSBridge.invoke == "function") { handleFontSize(); } else { if (document.addEventListener) { document.addEventListener("WeixinJSBridgeReady", handleFontSize, false); } else if (document.attachEvent) { document.attachEvent("WeixinJSBridgeReady", handleFontSize); document.attachEvent("onWeixinJSBridgeReady", handleFontSize); } }
function handleFontSize() { WeixinJSBridge.invoke('setFontSizeCallback', { 'fontSize': 0 }); WeixinJSBridge.on('menu:setfont', function() { WeixinJSBridge.invoke('setFontSizeCallback', { 'fontSize': 0 }); }); } })(); function setWebHeight() { window.hm.setWebHeight(document.getElementById('webBottom').offsetTop); }
// 在文档加载完成后执行 setWebHeight 函数 window.onload = function() { setWebHeight(); };</script>
</html>
复制代码

src/main/ets/pages/Page42.ets

import { webview } from '@kit.ArkWeb';import web_webview from '@ohos.web.webview';import dataPreferences from '@ohos.data.preferences';import { common } from '@kit.AbilityKit';import { photoAccessHelper } from '@kit.MediaLibraryKit';import { componentSnapshot, promptAction } from '@kit.ArkUI';import fs from '@ohos.file.fs';import { image } from '@kit.ImageKit';import { BusinessError } from '@kit.BasicServicesKit';
class WebService {
setWebHeight = (height: string) => { console.info('web高度:', height); getContext().eventHub.emit("设置web高度",height) }}
@Entry@Componentstruct Page42 { controller: webview.WebviewController = new webview.WebviewController(); webService: WebService = new WebService( ); methodList: Array<string> = [] @State isShort: boolean = true @State webHeight: number | undefined = undefined aboutToAppear(): void { this.methodList.splice(0) //清空原数组 console.info('====this.testObjtest', JSON.stringify(this.webService)) Object.keys(this.webService).forEach((key) => { this.methodList.push(key) console.info('====key', key) });
getContext().eventHub.on("设置web高度",(height:number)=>{ this.webHeight = height }) } build() { Scroll() { Column() { SaveButton().onClick(async (event: ClickEvent, result: SaveButtonOnClickResult) => { if (result === SaveButtonOnClickResult.SUCCESS) { const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // 免去权限申请和权限请求等环节,获得临时授权,保存对应图片 let helper = photoAccessHelper.getPhotoAccessHelper(context); try { // onClick触发后5秒内通过createAsset接口创建图片文件,5秒后createAsset权限收回。 let uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg'); // 使用uri打开文件,可以持续写入内容,写入过程不受时间限制 let file = await fs.open(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); componentSnapshot.get("aaaa").then((pixelMap) => { let packOpts: image.PackingOption = { format: 'image/png', quality: 100 } const imagePacker: image.ImagePacker = image.createImagePacker(); return imagePacker.packToFile(pixelMap, file.fd, packOpts).finally(() => { imagePacker.release(); //释放 fs.close(file.fd); promptAction.showToast({ message: '图片已保存至相册', duration: 2000 }); }); }) } catch (error) { const err: BusinessError = error as BusinessError; console.error(`Failed to save photo. Code is ${err.code}, message is ${err.message}`); }
} else { promptAction.showToast({ message: '设置权限失败!', duration: 2000 }); } }) Text('1234测试顶部').backgroundColor(Color.Red).width('100%').height('800lpx') Web({ src: $rawfile('test.html'), controller: this.controller, renderMode: RenderMode.SYNC_RENDER }) .width('100%') .height(this.webHeight) .layoutMode(WebLayoutMode.FIT_CONTENT) .javaScriptAccess(true)//设置是否允许执行JavaScript脚本,默认允许执行。 .mixedMode(MixedMode.All)//HTTP和HTTPS混合 .javaScriptProxy({ name: "hm", object: this.webService, methodList: this.methodList, controller: this.controller, }).id("aaaa") Text('测试底部').backgroundColor(Color.Blue).width('100%').height('800lpx') } }.width('100%').height('100%').align(Alignment.Top) }}
复制代码


用户头像

zhongcx

关注

还未添加个人签名 2024-09-27 加入

还未添加个人简介

评论

发布
暂无评论
【HarmonyOS】组件长截屏方案_zhongcx_InfoQ写作社区