【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.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
@Component
struct 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)
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值