【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,
          
        })
相关推荐
Dream-Y.ocean19 小时前
鸿蒙PC平台宅匠 3D 室内设计适配实战:基于 Electron 壳方案的 Three.js 双渲染引擎与参数化户型编辑器开发
javascript·3d·harmonyos
行者-全栈开发19 小时前
【共创稿事节】HarmonyOS 应用上架全流程中的隐私合规:权限最小化、数据本地化与 AppAnalyzer 体检
harmonyos·鸿蒙·隐私合规·应用上架·agc·appanalyzer
贾伟康20 小时前
HarmonyOS API 26 UKey PIN 授权门禁:状态查询、失败归因与资源闭环
华为·harmonyos
Dream-Y.ocean1 天前
鸿蒙PC平台星图遥感适配实战:基于 Electron 壳方案的纯 JavaScript 遥感图像处理引擎开发
javascript·electron·harmonyos
七月稻草人1 天前
鸿蒙平板能当电脑第二块屏幕吗?ToDesk、向日葵镜像/副屏实测
华为·电脑·harmonyos
贾伟康1 天前
【共创稿事节】HarmonyOS 7.0 Want隐式跳转:从接入到生产验证
性能优化·实战·harmonyos·arkts·arkui
NJPJI_Yang1 天前
鸿蒙 HarmonyOS 7 应用内存优化:appMemoryOptimizer 释放 so 页缓存实战
pytorch·深度学习·harmonyos
翰德恩咨询1 天前
IPD咨询洞察:华为如何以项目为中心,激活组织
华为
熊猫钓鱼>_>1 天前
三方库 NDK 原生模块跨平台适配与调试【鸿蒙心迹】
开发语言·华为·ai编程·harmonyos·鸿蒙·openharmony·鸿蒙心迹
行者-全栈开发2 天前
【鸿蒙心迹】三方库移植(二)——CMake 交叉编译与符号冲突排查实录(HarmonyOS 7.x)
harmonyos·cmake·交叉编译·三方库移植·ohos·符号冲突