ArkTS开发系列之导航 (2.6 图形)

上篇回顾:ArkTS开发系列之导航 (2.5.2 页面组件导航)

本篇内容: 显示图片、自定义图形和画布自定义图形的学习使用

一、知识储备

1. 图片组件(Image)

  • 可以展示jpg 、png 、svg 、gif等各格式的网络和本地资源文件图片的组件
  • 接口调用
Image(src: string | Resource | media.PixelMap)
  • 实际代码调用
Image('images/view.jpg').width(200)//ets本次资源目录下
Image('https://www.example.com/example.JPG') // 网络图片实际使用时请替换为真实地址
Image($r('app.media.ic_hm_logo'))//resources/base/media目录下
Image($rawfile('snap'))//resources/rawfile目录下
Image('file://media/Photos/5').width(200)//手机媒体库中图片资源
  • 从手机媒体库中选择图片
//从手机媒体库中选择图片
   try {
     let photoSelectOptions = new picker.PhotoSelectOptions(); //媒体库选择器设置
     photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE; //图片类型
     photoSelectOptions.maxSelectNumber = 5; //最多 选取五张

     let photoPicker = new picker.PhotoViewPicker; //初始化图片选择器
     photoPicker.select(photoSelectOptions).then(photoSelectResult => { //选择结果回调
       this.imgListData = photoSelectResult.photoUris;
       console.error(`imgListData size is ${this.imgListData.length}`)
     }).catch(err=>{
       console.error(`select failed code is ${err.code}, msg : ${err.message}`)
     })
   } catch (err) {
     console.error(`load photo failed ${err.code}, msg: ${err.message}`)
   }
  • 多媒体像素图
 http.createHttp().request(this.imgUrl, (err, data) => {
      if (err) {
        console.error(`err is ${JSON.stringify(err)}`)
      } else {
        let code = data.responseCode;
        if (ResponseCode.ResponseCode.OK == code) {
          let res: any = data.result;
          let imageSource = image.createImageSource(res)
          let options = {
            alphaTye: 0, //透明度
            editable: false, //是否可编辑
            pixelFormat: 3, //像素格式
            scaleMode: 1, //缩略值
            size: { height: 100, wight: 100 } //创建图片大小
          }
          imageSource.createPixelMap(options).then(pixelMap => {
            this.image = pixelMap;
          })
        }
      }
    })
  • 常用函数
  • .objectFit(ImageFit.Fill)// 缩放类型
  • .interpolation(ImageInterpolation.High)//图片插值,抗锯齿,使图片看着更清晰
  • .renderMode(ImageRenderMode.Template) //图片渲染模式
  • .objectRepeat(ImageRepeat.X)//设置图片在xy轴上重复显示
  • .sourceSize({//设置图片解码尺寸
    width: 65, height: 40
    })
  • .colorFilter([//添加滤镜效果
    1,1,0,0,0,
    0,1,0,0,0,
    0,0,1,0,0,
    0,0,0,1,0
    ])
  • .syncLoad(true)//同步加载图片
  • .onComplete(msg=>{ 加载成功和失败的事件回调
    if (msg) {
    console.error(widthVal = ${msg.width}\n height = ${msg.height} \n componentW = ${msg.componentWidth} \n status = ${msg.loadingStatus})
    }
    })
    .onError(()=>{
    console.error(‘err’)
    })

2. 自定义图形(shape)

  • 有两种创建形式,一种以Shape为父组件,一种是绘制组件单独使用
Shape() {
  Rect().width(300).height(50)//以Shape作为父组件使用
}
Circle({ width: 150, height: 150 })//单独使用
  • 绘制组件有七种类型:圆形(Circle)、椭圆形(Ellipse)、直线(Line)、拆线(Polyline)、多边形(Polygon)、路径(Path)、矩形(Rect)。
  • 形状视口 viewPort
 Shape() {
        Rect({ width: 100, height: 100 }).fill(0xf7f7f7)
        Circle({ width: 150, height: 150 }).fill(0x00c250)
      }.viewPort({ x: 0, y: 0, width: 100, height: 100 })//根据这个视口与宽高比进行放大shape内的组件大小
      .width(150)
      .height(150)
  • 绘制一个“吉”字
Path()
         .width(100)
         .height(100)
         .commands(`M${this._50} 0 L${this._50} ${this._50} L0 ${this._50} L${this._100} ${this._50} L${this._50} ${this._50} L${this._50} ${this._100} L${this._15} ${this._100} L${this._85} ${this._100} L${this._50} ${this._100} Z`)
         .fillOpacity(0) //实心不填充颜色
         .fill(Color.Red)
         .stroke(Color.Red)
         .strokeWidth(5)

       Polyline()
         .width(100)
         .height(100)
         .stroke(Color.Red)
         .strokeWidth(5)
         .points([[10, 10], [90, 10], [90, 90], [10, 90], [10, 10]])
         .fillOpacity(0) //实心不填充颜色

3. 画布自定义图形(Canvas)

  • 初始化画布组件
  Canvas(this.context)
    .width('100%')
    .height('100%')
    .backgroundColor(Color.Yellow)
    .onReady(() => {
  • 画圆形
this.context.beginPath()
this.context.arc(110, 150, 50, 0, 6.28)
this.context.stroke()
this.context.font = '56px'
this.context.fillText('圆形', 120, 220)//画圆形
  • 画矩形
 this.context.beginPath()
            this.context.rect(110, 10, 210, 110)
            this.context.stroke()
            this.context.font = '46px'
            this.context.fillText('矩形', 120, 20)//画矩形
  • 画椭圆形
this.context.beginPath()
            this.context.ellipse(110, 250, 50, 100, Math.PI * 0.25, Math.PI * 0, Math.PI * 2)
            this.context.stroke()//画椭圆形
  • 写字
 let line = this.context.createLinearGradient(110, 500, 110, 600)
            line.addColorStop(0, '#f00')
            line.addColorStop(0.5, '#ff0')
            line.addColorStop(1, '#f0f')
            this.context.fillStyle = line
            this.context.fillRect(110, 500, 100, 100)//渐变色
            this.context.fillText('我是中华人民共和国的公民', 110, 500)//写字
  • 截图画图
  this.offContext.drawImage(this.image, 110, 400, 130, 130)
            let imageData = this.offContext.getImageData(150, 450, 130, 130)
            this.offContext.putImageData(imageData, 130, 130)
            let img = this.offContext.transferToImageBitmap();
            this.context.transferFromImageBitmap(img)//.截图画图
  • 再次画个“吉”
let path = new Path2D();
 path.moveTo(100, 100)
   path.lineTo(100, 150)
   path.lineTo(25, 150)
   path.lineTo(175, 150)
   path.lineTo(100, 150)
   path.lineTo(100, 200)
   path.lineTo(40, 200)
   path.lineTo(160, 200)
   path.lineTo(100, 200)
   path.closePath()
   this.context.strokeStyle = '#f00'
   this.context.lineWidth = 5
   this.context.stroke(path)

   let path2 = new Path2D();
   path2.moveTo(40, 215)
   path2.lineTo(160, 215)
   path2.lineTo(160, 335)
   path2.lineTo(40, 335)
   path2.lineTo(40, 215)
   this.context.stroke(path2)//再次画个“吉”

二、 效果一览

在这里插入图片描述

三、 源码剖析

import http from '@ohos.net.http';
import ResponseCode from '@ohos.net.http';
import image from '@ohos.multimedia.image';
import picker from '@ohos.file.picker';

@Entry
@Component
struct MyRouter {
  private tabsController: TabsController = new TabsController();
  @State currentIndex: number = 0;

  @Builder TabBuild(title: string, targetIndex: number, SelectedImg: Resource, normalImg: Resource) {
    Column() { //自定义tab
      Image(this.currentIndex == targetIndex ? SelectedImg : normalImg)
        .size({ width: 25, height: 25 })
      Text(title)
        .fontSize(16).fontColor(this.currentIndex == targetIndex ? 0x00c250 : 0x333333)
    }
    .width('100%')
    .height(48)
    .justifyContent(FlexAlign.Center)
    .onClick(() => {
      console.error(`targetIndex is ${targetIndex}`)
      this.currentIndex = targetIndex;
      this.tabsController.changeIndex(this.currentIndex)
    })
  }

  @State image: PixelMap = undefined; //创建PixelMap状态变量

  private imgUrl: string = 'https://img1.baidu.com/it/u=3241660985,1063915045&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1194';

  loadImg() { //获取网络美女图片
    http.createHttp().request(this.imgUrl, (err, data) => {
      if (err) {
        console.error(`err is ${JSON.stringify(err)}`)
      } else {
        let code = data.responseCode;
        if (ResponseCode.ResponseCode.OK == code) {
          let res: any = data.result;
          let imageSource = image.createImageSource(res)
          let options = {
            alphaTye: 0, //透明度
            editable: false, //是否可编辑
            pixelFormat: 3, //像素格式
            scaleMode: 1, //缩略值
            size: { height: 100, wight: 100 } //创建图片大小
          }
          imageSource.createPixelMap(options).then(pixelMap => {
            this.image = pixelMap;
          })
        }
      }
    })
  }

  aboutToAppear() {

    // this.context = getContext();
    this.loadImg()
  }

  settings: RenderingContextSettings = new RenderingContextSettings(true)
  context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
  offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
  img: ImageBitmap = new ImageBitmap('../../../resources/base/media/ic_hm_logo.svg')
  scroller: Scroller = new Scroller();
  @State _50: number = vp2px(50)
  @State _100: number = vp2px(100)
  @State _85: number = vp2px(85)
  @State _15: number = vp2px(15)
  @State _: number = vp2px(50)

  build() {
    Tabs({
      barPosition: BarPosition.End,
      controller: this.tabsController
    }) { //end start  首尾位置设置   controller 绑定tabs的控制器
      TabContent() { //内容页面组件
        MyNavigation().backgroundColor(0xf7f7f7)
      }
      .tabBar(this.TabBuild('首页', 0, $r('app.media.ic_hm_home_selected'), $r('app.media.ic_hm_home_normal')))

      TabContent() {
        Image(this.image).height('100%').width('100%')
      }
      .tabBar(this.TabBuild('直播', 1, $r('app.media.ic_hm_living_selected'), $r('app.media.ic_hm_living_normal')))

      TabContent() {
        Scroll(this.scroller) {
          Column() {
            Row() {
              Image(this.imgUrl)
                .width('30%')
                .height('20%')
                .border({ width: 1 })
                .objectFit(ImageFit.Contain) //等比缩放,图片完全显示
                .margin(15)
                .overlay('Contain', { align: Alignment.Bottom, offset: { x: 0, y: 30 } })
                .colorFilter([ //添加滤镜效果
                  1, 1, 0, 0, 0,
                  0, 1, 0, 0, 0,
                  0, 0, 1, 0, 0,
                  0, 0, 0, 1, 0
                ])
                .syncLoad(true) //同步加载图片
                .onComplete(msg => {
                  if (msg) {
                    console.error(`widthVal = ${msg.width}\n height = ${msg.height} \n componentW = ${msg.componentWidth} \n status = ${msg.loadingStatus}`)
                  }
                })
                .onError(() => {
                  console.error('err')
                })

              Image(this.imgUrl)
                .width('30%')
                .height('20%')
                .border({ width: 1 })
                .objectFit(ImageFit.Cover) //等比缩放, 图片显示部分
                .margin(15)
                .overlay('Cover', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })

              Image(this.imgUrl)
                .width('30%')
                .height('20%')
                .border({ width: 1 })
                .objectFit(ImageFit.Auto) //自适应显示
                .margin(15)
            }

            Row() {
              Image(this.imgUrl)
                .width('30%')
                .height('20%')
                .border({ width: 1 })
                .objectFit(ImageFit.Fill) //填充显示,不保持等比缩放
                .renderMode(ImageRenderMode.Template) //图片渲染模式
                .margin(15)
                .overlay('fill', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })

              Image(this.imgUrl)
                .sourceSize({ //设置图片解码尺寸
                  width: 65, height: 40
                })
                .width('30%')
                .height('20%')
                .border({ width: 1 })
                .objectFit(ImageFit.ScaleDown) //保持原宽高比 等比缩放或不变
                .objectRepeat(ImageRepeat.XY) //设置图片在xy轴上重复显示
                .margin(15)
                .overlay('scaleDown', { align: Alignment.Bottom, offset: { x: 0, y: 30 } })

              Image(this.imgUrl)
                .width('30%')
                .height('20%')
                .border({ width: 1 })
                .objectFit(ImageFit.None) //保持图片原尺寸
                .interpolation(ImageInterpolation.High) //图片插值,抗锯齿,使图片看着更清晰
                .margin(15)
                .overlay("none", { align: Alignment.Bottom, offset: { x: 0, y: 30 } })
            }

          }

        }.width('100%')
        .height('100%')
      }
      .tabBar(this.TabBuild('朋友圈', 2, $r('app.media.ic_hm_friend_selected'), $r("app.media.ic_hm_friend_normal")))

      TabContent() {
        Canvas(this.context)
          .width('100%')
          .height('100%')
          .backgroundColor(Color.Yellow)
          .onReady(() => {

            this.offContext.drawImage(this.image, 110, 400, 130, 130)
            let imageData = this.offContext.getImageData(150, 450, 130, 130)
            this.offContext.putImageData(imageData, 130, 130)
            let img = this.offContext.transferToImageBitmap();
            this.context.transferFromImageBitmap(img)//.截图画图

            this.context.beginPath()
            this.context.rect(110, 10, 210, 110)
            this.context.stroke()
            this.context.font = '46px'
            this.context.fillText('矩形', 120, 20)//画矩形

            this.context.beginPath()
            this.context.arc(110, 150, 50, 0, 6.28)
            this.context.stroke()
            this.context.font = '56px'
            this.context.fillText('圆形', 120, 220)//画圆形

            this.context.beginPath()
            this.context.ellipse(110, 250, 50, 100, Math.PI * 0.25, Math.PI * 0, Math.PI * 2)
            this.context.stroke()//画椭圆形

            let line = this.context.createLinearGradient(110, 500, 110, 600)
            line.addColorStop(0, '#f00')
            line.addColorStop(0.5, '#ff0')
            line.addColorStop(1, '#f0f')
            this.context.fillStyle = line
            this.context.fillRect(110, 500, 100, 100)//渐变色
            this.context.fillText('我是中华人民共和国的公民', 110, 500)//写字

            let path = new Path2D();
            path.moveTo(100, 100)
            path.lineTo(100, 150)
            path.lineTo(25, 150)
            path.lineTo(175, 150)
            path.lineTo(100, 150)
            path.lineTo(100, 200)
            path.lineTo(40, 200)
            path.lineTo(160, 200)
            path.lineTo(100, 200)
            path.closePath()
            this.context.strokeStyle = '#f00'
            this.context.lineWidth = 5
            this.context.stroke(path)

            let path2 = new Path2D();
            path2.moveTo(40, 215)
            path2.lineTo(160, 215)
            path2.lineTo(160, 335)
            path2.lineTo(40, 335)
            path2.lineTo(40, 215)
            this.context.stroke(path2)//再次画个“吉”
          })
      }
      .tabBar(this.TabBuild('画布', 3, $r('app.media.ic_hm_logo'), $r('app.media.icon')))

      TabContent() {
        Column() {

          Text('原始尺寸Circle')
          Circle({ width: 100, height: 100 }).fill(0x00c250)
          Row({ space: 10 }) {

            Column() {
              Text('shape内放大的Circle')
              Shape() {
                Rect({ width: 100, height: 100 }).fill(0xf7f7f7)
                Circle({ width: 150, height: 150 }).fill(0x00c250)
              }.viewPort({ x: 0, y: 0, width: 100, height: 100 }) //根据这个视口与宽高比进行放大shape内的组件大小
              .width(150)
              .height(150)


              Path()
                .width(100)
                .height(100)
                .commands(`M${this._50} 0 L${this._50} ${this._50} L0 ${this._50} L${this._100} ${this._50} L${this._50} ${this._50} L${this._50} ${this._100} L${this._15} ${this._100} L${this._85} ${this._100} L${this._50} ${this._100} Z`)
                .fillOpacity(0) //实心不填充颜色
                .fill(Color.Red)
                .stroke(Color.Red)
                .strokeWidth(5)

              Polyline()
                .width(100)
                .height(100)
                .stroke(Color.Red)
                .strokeWidth(5)
                .points([[10, 10], [90, 10], [90, 90], [10, 90], [10, 10]])
                .fillOpacity(0) //实心不填充颜色


            }
          }
        }
      }
      .tabBar(this.TabBuild('我的', 4, $r('app.media.ic_hm_my_selected'), $r('app.media.ic_hm_my_normal')))
    }
    .vertical(false) //tabs垂直与横向设置
    .scrollable(false) //禁止页面滑动
    .barMode((BarMode.Fixed)) //Fixed 固定    Scrollable  可以滑动,当tab多时用
    .onChange((index) => { //页面滑动监听
      console.error(`this is ${index}`)
      this.currentIndex = index;
      // this.tabsController.changeIndex(this.currentIndex)
    })
  }
}

@Component
struct MyNavigation {
  private arr: number[] = [1, 2, 3];

  build() {
    Column() {
      Navigation() {
        TextInput({ placeholder: '请输入...' })
          .width('90%')
          .height(40)
          .backgroundColor('#ffffff')

        List({ space: 12 }) {
          ForEach(this.arr, item => {
            ListItem() {
              NavRouter() {
                Text("NavRouter" + item)
                  .width('100%')
                  .height(72)
                  .backgroundColor(Color.White)
                  .borderRadius(36)
                  .fontSize(16)
                  .fontWeight(500)
                  .textAlign(TextAlign.Center)
                NavDestination() {
                  Text(`NavDestinationContent${item}`)
                }
                .title(`NavDestinationTitle${item}`)
              }
            }
          })
        }
      }
      .title('主标题')
      .mode(NavigationMode.Stack)
      .titleMode(NavigationTitleMode.Mini)
      .menus([
        { value: "", icon: './../../../resources/base/media/icon.png', action: () => {
        } },
        { value: "", icon: './../../../resources/base/media/icon.png', action: () => {
        } }
      ])
      .toolBar({ items: [
        { value: 'func', icon: './../../../resources/base/media/icon.png', action: () => {
        } },
        { value: 'func', icon: './../../../resources/base/media/icon.png', action: () => {
        } }
      ] })
    }
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值