【HarmonyOS Next 自定义可拖拽image】

效果图:
请添加图片描述
代码:

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:

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 ,这样写就行:

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Jmeter快速实操入门

以下操作需要提前安装了JDK&#xff08;JDK版本要Java8&#xff09;&#xff0c;并且配置了环境变量。 1、下载Jmeter,下载连接。选择zip版本&#xff0c;解压即可。 2、解压后的文件目录如下。 3、进入bin文件夹&#xff0c;双击ApacheJMeter&#xff0c;运行Jmeter。 4、在测…

学习 PostgreSQL 流复制

PostgreSQL 流复制 PostgreSQL数据库异常中止后&#xff0c;数据库刚重启时&#xff0c;会重放停机前最后一个checkpoint点之后的 WAL日志&#xff0c;在把数据库恢复到停机的状态后&#xff0c;自动进入正常的状态&#xff0c;可以接收其他用户的查询和修改。 想象另一个场景…

macbook2015升级最新MacOS 白苹果变黑苹果

原帖&#xff1a;https://www.bilibili.com/video/BV13V411c7xz/MAC OS系统发布了最新的Sonoma&#xff0c;超酷的动效锁屏壁纸&#xff0c;多样性的桌面小组件&#xff0c;但是也阉割了很多老款机型的升级权利&#xff0c;所以我们可以逆向操作&#xff0c;依旧把老款MAC设备强…

2025年最新版武书连SCD期刊(中国科学引文数据库)来源期刊已更新,可下载PDF版!需要的作者进来了解~

2025年最新版武书连SCD期刊&#xff08;中国科学引文数据库&#xff09;来源期刊已更新&#xff01; 官网是不提供免费查询的。小编给大家两个路径&#xff0c;无需下载PDF&#xff0c;随时随地都能查25版SCD目录。 路径一&#xff1a;中州期刊联盟官网&#xff0c;25版SCD目…

deepseek大模型集成到idea

1 下载插件 安装CodeGPT打开 IntelliJ IDEA&#xff0c;鼠标点击左上角导航栏&#xff0c;File --> Setting 2 申请API key 3 配置deepseek 在 Settings 界面中的搜索框中&#xff0c;搜索 CodeGPT&#xff0c;路径 Tools --> CodeGPT --> Providers --> 如下一…

本地部署DeepSeek,并使用UI界面进行快速交互

一.需要本地部署的原因 1.我们在deepseek的官网界面进行交互时&#xff0c;经常会出现如下问题&#xff0c;不能正常交互&#xff0c;很是困扰&#xff1a; 2.本地部署的好处 就是能够很流畅的与deepseek进行交互&#xff1b;也有缺点&#xff0c;现在官网交互的版本更高一点…

8.flask+websocket

http是短连接&#xff0c;无状态的。 websocket是长连接&#xff0c;有状态的。 flask中使用websocket from flask import Flask, request import asyncio import json import time import websockets from threading import Thread from urllib.parse import urlparse, pars…

深度学习之神经网络框架搭建及模型优化

神经网络框架搭建及模型优化 目录 神经网络框架搭建及模型优化1 数据及配置1.1 配置1.2 数据1.3 函数导入1.4 数据函数1.5 数据打包 2 神经网络框架搭建2.1 框架确认2.2 函数搭建2.3 框架上传 3 模型优化3.1 函数理解3.2 训练模型和测试模型代码 4 最终代码测试4.1 SGD优化算法…

【Matlab优化算法-第15期】基于NSGA-II算法的铁路物流园区功能区布局优化

基于NSGA-II算法的铁路物流园区功能区布局优化 一、前言 铁路物流园区的合理布局对于提高物流效率、降低运营成本具有重要意义。随着铁路物流的快速发展&#xff0c;传统的铁路货场需要升级为综合物流园区&#xff0c;以满足多式联运和综合物流服务的需求。本文将介绍一种基于…

手写一个C++ Android Binder服务及源码分析

手写一个C Android Binder服务及源码分析 前言一、 基于C语言编写Android Binder跨进程通信Demo总结及改进二、C语言编写自己的Binder服务Demo1. binder服务demo功能介绍2. binder服务demo代码结构图3. binder服务demo代码实现3.1 IHelloService.h代码实现3.2 BnHelloService.c…

WebSocket connection failed 解决

WebSocket connection failed 解决 前言 这里如果是新手小白不知道 WebSocket 是什么的&#xff1f; 怎么使用的&#xff1f;或者想深入了解的 那可以 点击这里 几分钟带你快速了解并使用&#xff0c;已经一些进阶讲解&#xff1b; WebSocket&#xff0c;多应用于需要双向数据…

Python截图轻量化工具

一、兼容局限性 这是用Python做的截图工具&#xff0c;不过由于使用了ctypes调用了Windows的API, 同时访问了Windows中"C:/Windows/Cursors/"中的.cur光标样式文件, 这个工具只适用于Windows环境&#xff1b; 如果要提升其跨平台性的话&#xff0c;需要考虑替换cty…

字节跳动后端一面

&#x1f4cd;1. Gzip压缩技术详解 Gzip是一种流行的无损数据压缩格式&#xff0c;它使用DEFLATE算法来减少文件大小&#xff0c;广泛应用于网络传输和文件存储中以提高效率。 &#x1f680; 使用场景&#xff1a; • 网站优化&#xff1a;通过压缩HTML、CSS、JavaScript文件来…

Visual Studio踩过的坑

统计Unity项目代码行数 编辑-查找和替换-在文件中查找 查找内容输入 b*[^:b#/].*$ 勾选“使用正则表达式” 文件类型留空 也有网友做了指定&#xff0c;供参考 !*\bin\*;!*\obj\*;!*\.*\*!*.meta;!*.prefab;!*.unity 打开Unity的项目 注意&#xff1a;只是看&#xff0…

智慧机房解决方案(文末联系,领取整套资料,可做论文)

智慧机房解决方案-软件部分 一、方案概述 本智慧机房解决方案旨在通过硬件设备与软件系统的深度整合&#xff0c;实现机房的智能化管理与服务&#xff0c;提升机房管理人员的工作效率&#xff0c;优化机房运营效率&#xff0c;确保机房设备的安全稳定运行。软件部分包括机房管…

ubuntu中如何在vscode的终端目录后显示(当前的git分支名) 实测有用

效果展示 配置过程&#xff1a; 在 Ubuntu 中&#xff0c;如果你想在 VS Code 的终端提示符后显示当前的 Git 分支名&#xff0c;可以通过修改 Shell 配置文件&#xff08;如 ~/.bashrc 或 ~/.zshrc&#xff09;来实现。以下是具体步骤&#xff1a; 1. 确定使用的 Shell 首…

【机器学习案列】车辆二氧化碳排放量预测

这里是引用 &#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中…

SpringCloud - Sentinel服务保护

前言 该博客为Sentinel学习笔记&#xff0c;主要目的是为了帮助后期快速复习使用 学习视频&#xff1a;7小快速通关SpringCloud 辅助文档&#xff1a;SpringCloud快速通关 源码地址&#xff1a;cloud-demo 一、简介 官网&#xff1a;https://sentinelguard.io/zh-cn/index.h…

基于 GEE 利用插值方法填补缺失影像

目录 1 完整代码 2 运行结果 利用GEE合成NDVI时&#xff0c;如果研究区较大&#xff0c;一个月的影像覆盖不了整个研究区&#xff0c;就会有缺失的地方&#xff0c;还有就是去云之后&#xff0c;有云量的地区变成空值。 所以今天来用一种插值的方法来填补缺失的影像&#xf…

海云安开发者智能助手(D10)全面接入DeepSeek,赋能开发者安全高效编码新范式

海云安正式宣布完成与DeepSeek&#xff08;深度求索&#xff09;的深度技术融合&#xff0c;旗下核心产品D10开发者智能助手全面接入DeepSeek R1模型。此次合作标志着海云安在"AI驱动开发安全"领域实现重要突破。数据显示&#xff0c;通过DeepSeek R1模型的优化与蒸馏…