【HarmonyOS】组件长截屏方案

【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
@Component
struct 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.lineHeightthis.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 numberthis.resetMaxLineHeight()//添加数据测试let str = ""for (let i = 1; i <= 20; i++) {str += ` ${i}、荣誉和耻辱,是荣辱观中的一对基本范畴,是指社会对人们行为褒贬评价以及人们对这种评价的自我感受。知荣辱,是人性的标志,是人区别于动物、人之为人的重要标准。`}this.textContent = strreturn}if (this.totalContentHeight != newArea.height) {console.info(`newArea.height:${newArea.height}`)this.totalContentHeight = newArea.height as numberthis.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 numberthis.resetMaxLineHeight()}})Row() {Button('上一页').onClick(() => {if (this.currentPage == 1) {promptAction.showToast({ message: "没有上一页了" })return;}this.scrollOffset += this.pageHeightthis.currentPage--;})Text(`${this.currentPage}/${this.totalPages}`)Button('下一页').onClick(() => {if (this.currentPage == this.totalPages) {promptAction.showToast({ message: "没有下一页了" })return;}this.scrollOffset -= this.pageHeightthis.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
@Component
struct Page42 {controller: webview.WebviewController = new webview.WebviewController();webService: WebService = new WebService( );methodList: Array<string> = []@State isShort: boolean = true@State webHeight: number | undefined = undefinedaboutToAppear(): 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)}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1547459.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

001、视频添加字幕

1. 腾讯智影 (可用) https://zenvideo.qq.com/ 1.1 操作步骤 https://zenvideo.qq.com/ https://zenvideo.qq.com/my/material?typeexport 上传资源 自动字幕识别 修改字幕 下载字幕 上传字幕 https://zenvideo.qq.com/my/material?typeexport 2. 秒剪–手机版app &a…

华为云分布式缓存服务Redis®版9月企业版、灵活的购买方式全新上市

华为云分布式缓存服务&#xff08;Distributed Cache Service&#xff0c;简称DCS&#xff09;是华为云提供的一款兼容Redis的高速内存数据处理引擎&#xff0c;为您提供即开即用、安全可靠、弹性扩容、便捷管理的在线分布式缓存能力&#xff0c;满足用户高并发及数据快速访问的…

MacOS多桌面调度快捷键

单桌面调度快捷键 可能是我用着妙控鼠标用着不习惯&#xff0c;所以追求快捷键操作&#xff0c;看起来也比较酷。而且在Windows上&#xff0c;我基本不使用多桌面&#xff0c;但是看着同事用Mac的多桌面用的飞起&#xff0c;炫酷程度不亚于win7的Windows键Tab。在不使用多桌面的…

SSM+Vue家教平台系统

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 spring-mybatis.xml3.5 spring-mvc.xml3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质创作…

水平分库分表的方法策略

分库分表介绍 在当前业务量迅猛增加的情况下&#xff0c;数据库经常面临性能的极致挑战。尤其是在处理大规模的数据集&#xff0c;例如超过千万条数据记录的情况下&#xff0c;SQL查询的性能将显著下降。随着数据量的增加&#xff0c;查询所需要扫描的数据范围变得更广&#x…

AOT源码解析4.4 -decoder生成预测mask并计算loss

3、生成ref_imgs的预测mask和loss 这一步在训练阶段调用 3.1 数据处理 图1&#xff0c;如图1所示&#xff0c;将enc_embs的最后一个比例的特征图和有ref_imgs相关的特征图得到的LSTT特征图相拼接作为输入 curr_enc_embs self.curr_enc_embscurr_lstt_embs self.curr_lstt_o…

了解针对基座大语言模型(类似 ChatGPT 的架构,Decoder-only)的重头预训练和微调训练

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 随着自然语言处理&#xff08;NLP&#xff09;技术的飞速进步&#xff0c;基于 Transformer 架构的大语言模型在众多任务中取得了显著成就。特别是 Decoder-only 架构&#xff0c;如 GPT 系列模型&…

8.7基于数学形态学的边缘检测

基本概念 数学形态学&#xff08;Mathematical Morphology&#xff09;是一套用于图像处理的技术&#xff0c;它包括膨胀&#xff08;Dilation&#xff09;、腐蚀&#xff08;Erosion&#xff09;、开运算&#xff08;Opening&#xff09;和闭运算&#xff08;Closing&#xf…

使用电子模拟器 Wokwi 运行 ESP32 示例(Arduino IDE、VSCode、ESP32C3)

文章目录 Wokwi 简介安装客户端&#xff08;Mac/Linux&#xff09;创建 Token Arduino IDEVSCode 配置安装 wokwi 插件打开编译后目录 ESP32C3 示例Arduino IDE创建模拟器运行模拟器 Wokwi 简介 Wokwi 是一款在线电子模拟器。您可以使用它来模拟 Arduino、ESP32、STM32 以及许…

HTML·第3章 表格布局与表单交互

3.1 表格概述 3.1.1 表格的结构 表格是由行和列组成的二维表&#xff0c;而每行又由一个或多个单元格组成&#xff0c;用于放置数据或其他内容。表格中的单元格是行与列的交叉部分&#xff0c;是组成表格的最基本单元。单元格的内容是数据&#xff0c;也称数据单元格。数据单元…

线上环境排故思路与方法GC优化策略

前言 这是针对于我之前[博客]的一次整理&#xff0c;因为公司需要一些技术文档的定期整理与分享&#xff0c;我就整理了一下。(https://blog.csdn.net/TT_4419/article/details/141997617?spm1001.2014.3001.5501) 其实&#xff0c;nginx配置 服务故障转移与自动恢复也是可以…

人工智能开发实战照片智能搜索功能实现

内容提要 项目分析预备知识项目实战 一、项目分析 1、提出问题 随着人民生活水平的提高和手机照相功能的日趋完美&#xff0c;我们不经意中拍摄了很多值得回忆的时刻&#xff0c;一场说走就走的旅行途中也记录下许多令人心动的瞬间&#xff0c;不知不觉之中&#xff0c;我们…

【CSS in Depth 2 精译_040】6.3 CSS 定位技术之:相对定位(下)—— 用纯 CSS 绘制一个三角形

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09;第二章 相对单位&#xff08;已完结&#xff09;第三章 文档流与盒模型&#xff08;已完结&#xff09;第四章 Flexbox 布局&#xff08;已…

RabbitMQ应用

RabbitMQ 共提供了7种⼯作模式, 进⾏消息传递 一、七种模式的概述 1、Simple(简单模式) P&#xff1a;生产者&#xff0c;就是发送消息的程序 C&#xff1a;消费者&#xff0c;就是接收消息的程序 Queue&#xff1a;消息队列&#xff0c;类似⼀个邮箱, 可以缓存消息; ⽣产者…

【微服务即时通讯系统】——brpc远程过程调用、百度开源的RPC框架、brpc的介绍、brpc的安装、brpc使用和功能测试

文章目录 brpc1. brpc的介绍1.1 rpc的介绍1.2 rpc的原理1.3 grpc和brpc 2. brpc的安装3. brpc使用3.1 brpc接口介绍 4. brpc使用测试4.1 brpc同步和异步调用 brpc 1. brpc的介绍 1.1 rpc的介绍 RPC&#xff08;Remote Procedure Call&#xff09;远程过程调用&#xff0c;是一…

使用Postman搞定各种接口token实战

现在许多项目都使用jwt来实现用户登录和数据权限&#xff0c;校验过用户的用户名和密码后&#xff0c;会向用户响应一段经过加密的token&#xff0c;在这段token中可能储存了数据权限等&#xff0c;在后期的访问中&#xff0c;需要携带这段token&#xff0c;后台解析这段token才…

Java Stream流编程入门

流式编程 stream流式编程分为 首先转化为stream中间函数的链接最后的终结函数 怎么转化为stream 单列集合 List<String> list new ArrayList<String>(); Collections.addAll(list,"1","2","3","4","5","…

【MySQL】MVCC及其实现原理

目录 1. 概念介绍 什么是MVCC 什么是当前读和快照读 MVCC的好处 2. MVCC实现原理 隐藏字段 Read View undo-log 数据可见性算法 3. RC和RR隔离级别下MVCC的差异 4. MVCC&#xff0b;Next-key-Lock 防止幻读 1. 概念介绍 什么是MVCC Multi-Version Concurrency Cont…

FGPA实验——触摸按键

本文系列都基于正点原子新起点开发板 FPGA系列 1&#xff0c;verlog基本语法&#xff08;随时更新&#xff09; 2&#xff0c;流水灯&#xff08;待定&#xff09; 3&#xff0c;FGPA实验——触摸按键 一、触摸操作原理实现 分类&#xff1a;电阻式&#xff08;不耐用&…

LeetCode - 850 矩形面积 II

题目来源 850. 矩形面积 II - 力扣&#xff08;LeetCode&#xff09; 题目描述 给你一个轴对齐的二维数组 rectangles 。 对于 rectangle[i] [x1, y1, x2, y2]&#xff0c;其中&#xff08;x1&#xff0c;y1&#xff09;是矩形 i 左下角的坐标&#xff0c; (xi1, yi1) 是该…