【HarmonyOS Next 自定义可拖拽image】

效果图:

代码:

typescript 复制代码
import display from "@ohos.display"
import { AppUtil } from "@pura/harmony-utils"

/**
 * 自定义可拖拽图标组件
 */
@Component
export default struct DraggableImage {
  imageResource?: Resource
  imageHeight: number = 50 //单位:vp
  imageWidth: number = 50 //单位:vp

  //图标初始位置,默认在左上角
  startLocationX:number = 0
  startLocationY:number = 0
  
  marginLeft:number = 0
  marginRight:number = 0
  marginTop:number = 0
  marginBottom:number = 0
 

  @State private offsetX: number = 0
  @State private offsetY: number = 0
  @State private positionX: number = 0
  @State private positionY: number = 0
  //屏幕宽
  private screenWidth: number = 0
  private screenHeight: number = 0
  // 定义贴边的阈值(距离边缘多少像素时触发贴边)
  private snapThreshold: number = 50; //单位:vp

  aboutToAppear(): void {
    this.screenWidth = px2vp(display.getDefaultDisplaySync().width)-this.marginRight
    this.screenHeight = px2vp(display.getDefaultDisplaySync().height - AppUtil.getStatusBarHeight() - AppUtil.getNavigationIndicatorHeight())-this.marginBottom

    this.snapThreshold = this.screenWidth / 2
    console.info('DraggableImage aboutToAppear ' + this.screenWidth + " " + this.screenHeight)

    this.offsetX= this.startLocationX;
    this.offsetY= this.startLocationY;
    this.positionX= this.startLocationX;
    this.positionY= this.startLocationY;
  }

  aboutToDisappear(): void {
  }

  build() {
    Image(this.imageResource)
      .height(this.imageHeight)
      .width(this.imageWidth)
      .draggable(false)
      .position({
        x: this.offsetX,
        y: this.offsetY
      })//.translate({ x: this.offsetX, y: this.offsetY, z: 0 })// 以组件左上角为坐标原点进行移动
        // 左右滑动触发该手势事件
      .gesture(
        PanGesture()
          .onActionStart((event: GestureEvent) => {
            console.info('DraggableImage start')
          })
          .onActionUpdate((event: GestureEvent) => {
            if (event) {
              // 计算新的位置
              let newOffsetX = this.positionX + event.offsetX;
              let newOffsetY = this.positionY + event.offsetY;

              // 防止图标滑出左边界
              if (newOffsetX < this.marginLeft) {
                newOffsetX = this.marginLeft;
              }
              // 防止图标滑出右边界
              if (newOffsetX + this.imageWidth > this.screenWidth) { // imageWidth 是图标的宽度
                newOffsetX = this.screenWidth - this.imageWidth;
              }
              // 防止图标滑出上边界
              if (newOffsetY < this.marginTop) {
                newOffsetY = this.marginTop;
              }
              // 防止图标滑出下边界
              if (newOffsetY + this.imageHeight > this.screenHeight) { // imageHeight 是图标的高度
                newOffsetY = this.screenHeight - this.imageHeight;
              }

              // 更新图标位置
              this.offsetX = newOffsetX;
              this.offsetY = newOffsetY;

              console.info('DraggableImage onActionUpdate ' + this.offsetX + " " + this.offsetY)


            }
          })
          .onActionEnd((event: GestureEvent) => {


            let newOffsetX = this.marginLeft

            // 检查是否靠近左边缘
            if (this.offsetX < this.snapThreshold) {
              newOffsetX = this.marginLeft; // 贴到左边缘
            } else if (this.offsetX + this.imageWidth > this.screenWidth - this.snapThreshold) { // imageWidth 是图标的宽度
              // 检查是否靠近右边缘
              newOffsetX = this.screenWidth - this.imageWidth; // 贴到右边缘
            } else {
              newOffsetX = this.marginLeft
            }

            // 检查是否靠近上边缘
            /*  if (this.offsetY < this.snapThreshold) {
                this.offsetY = 0; // 贴到上边缘
              }
              // 检查是否靠近下边缘
              else if (this.offsetY + 50 > this.screenHeight - this.snapThreshold) { // 50 是图标的高度
                this.offsetY = this.screenHeight - 50; // 贴到下边缘
              }*/

            animateTo({ duration: 300, curve: Curve.Linear }, () => {
              this.offsetX = newOffsetX;
            })

            this.positionX = this.offsetX
            this.positionY = this.offsetY
            console.info('DraggableImage end')
          })
      )
  }
}
       

关键代码处都做了注释,这里也不在过多说明啦。

这里用了一个工具类 harmony-utils 来获取状态栏高度和底部导航栏高度,大家自行下载。

如何使用 DraggablePage.ets:

typescript 复制代码
import DraggableImage from './DraggableImage'
import { display } from '@kit.ArkUI'
import { AppUtil } from '@pura/harmony-utils'

@Entry
@Component
struct DraggablePage {
  marginBottom: number = 30
  marginRight: number = 10
  imageSize: number = 50

  build() {
    Column() {
      Stack({ alignContent: Alignment.Center }) {

        Text("我是内容布局")
          .fontSize(30)
          .fontColor(Color.Black)

        DraggableImage({
          imageResource: $r('app.media.update'),
          imageHeight: this.imageSize,
          imageWidth: this.imageSize,

          startLocationX: px2vp(display.getDefaultDisplaySync().width) - this.imageSize - this.marginRight,
          startLocationY: px2vp(display.getDefaultDisplaySync().height - AppUtil.getStatusBarHeight() - AppUtil.getNavigationIndicatorHeight()) - this.imageSize - this.marginBottom,

          marginTop: this.marginBottom,
          marginBottom: this.marginBottom,
          marginLeft: this.marginRight,
          marginRight: this.marginRight,
        })
        //注意:拖拽图标的边距,不能这样设置
        // .margin({ bottom: this.marginBottom, right: this.marginRight })

      }
      .width('100%')
      .layoutWeight(1)
    }

    .backgroundColor('#ffde7b7b')
    .width('100%')
    .height('100%')
  }
}

如果你不想设置拖拽图标的 margin ,这样写就行:

typescript 复制代码
  DraggableImage({
          imageResource: $r('app.media.update'),
          imageHeight: this.imageSize,
          imageWidth: this.imageSize,
          
        })
相关推荐
一只栖枝8 小时前
华为 HCIE 大数据认证中 Linux 命令行的运用及价值
大数据·linux·运维·华为·华为认证·hcie·it
zhanshuo11 小时前
在鸿蒙里优雅地处理网络错误:从 Demo 到实战案例
harmonyos
zhanshuo12 小时前
在鸿蒙中实现深色/浅色模式切换:从原理到可运行 Demo
harmonyos
whysqwhw17 小时前
鸿蒙分布式投屏
harmonyos
whysqwhw18 小时前
鸿蒙AVSession Kit
harmonyos
whysqwhw20 小时前
鸿蒙各种生命周期
harmonyos
whysqwhw21 小时前
鸿蒙音频编码
harmonyos
whysqwhw21 小时前
鸿蒙音频解码
harmonyos
whysqwhw21 小时前
鸿蒙视频解码
harmonyos
whysqwhw21 小时前
鸿蒙视频编码
harmonyos