0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

鸿蒙系统的手势操控组件代码现已开源

OpenHarmony技术社区 来源:鸿蒙技术社区 作者:朱伟ISRC 2021-06-24 18:16 次阅读

基于安卓平台的手势操控组件 PinchImageView-ohos,实现鸿蒙的功能化迁移和重构。代码已经开源,欢迎各位开发者提出宝贵意见。

开源地址:

https://gitee.com/isrc_ohos/pinch-image-view-ohos

PinchImageView-ohos 是一个支持多点触控的 ImageView 手势操控组件,通过识别单指双击、双指捏合、单指滑动等手势指令,实现图片的放大、缩小、滑动等效果。

该组件功能丰富且使用简单,被广泛应用于各类图片预览类应用。

01

组件效果展示

①双指相向或相对捏合,实现图片的缩放变化。

②单指双击实现图片的放大缩小。

③单指双击后单指移动,实现图片的放大后平移。

02

Sample 解析

Sample 部分主要负责整体显示布局的搭建。首先为 PinchImageView-ohos 组件设置显示图片,然后将组件对象添加到显示布局中。

下面将详细介绍组件的使用方法:

步骤 1:创建整体的显示布局。

步骤 2:导入相关类并实例化 PinchImageView-ohos 组件对象。

步骤 3:设置显示图片。

步骤 4:将 PinchImageView-ohos 组件对象添加到整体显示布局中。

//步骤1 创建整体的显示布局

DirectionalLayout directionalLayout = new DirectionalLayout(this);

//步骤2 导入相关类并实例化对象

PinchImageViewnew pinchImageView = new PinchImageViewnew(this);

//步骤3 设置显示图片

pinchImageView.setPixelMap(this, ResourceTable.Media_1111);

//步骤4 将pinchImageView添加到整体显示布局中

directionalLayout.addComponent(pinchImageView);

setUIContent(directionalLayout);

03

Library 解析

Library 主要为 PinchImageView-ohos 组件实现手势获取功能和图片操控功能。

开发者通过设置监听器来捕捉各类手势,根据不同的手势执行不同的图片操控方法,从而显示不同的图片操控效果,如放大、缩小、移动。

①手势获取方法

手势获取对实现 PinchImageView-ohos 组件的功能尤为重要,此处主要通过 onTouchEvent() 方法来捕捉对应的手势。

主要用到的手势包含:

PRIMARY_POINT_UP(最后一根手指从屏幕上抬起)

PRIMARY_POINT_DOWN(第一根手指触摸屏幕)

OTHER_POINT_DOWN(当一根或多根手指已经触摸屏幕时,另一个手指触摸屏幕 )

OTHER_POINT_UP(一些手指从屏幕上抬起,而一些手指仍留在屏幕上 )

POINT_MOVE(手指在屏幕上移动)

通过监控各类手势的操作顺序和触碰时间等条件,达到识别捏合、滑动、单击、双击等复杂手势的效果。

onTouchEvent() 函数首先通过 TouchEvent.getAction() 方法获取当前的手势,当手势为:

(1)PRIMARY_POINT_UP

需要判断图片之前是否处于缩放模式(此时图片处于缩放状态)。如果是缩放模式,则触发结束缩放动画,后将手势状态置于自由模式。

//最后一个点抬起或者取消,结束所有模式if (action == TouchEvent.PRIMARY_POINT_UP || action == TouchEvent.CANCEL) {

//如果之前是缩放模式,还需要结束缩放动画

if (mPinchMode == PINCH_MODE_SCALE) {

scaleEnd();//缩放结束

}

//手势状态置于自由模式

mPinchMode = PINCH_MODE_FREE;

}

(2)PRIMARY_POINT_DOWN

需要判断图片是否在缩放动画中,若不在,图片将切换到滚动模式(此时图片处于可自由移动状态),并保存触发点的位置,用于(5)中的计算。

else if (action == TouchEvent.PRIMARY_POINT_DOWN) {

//在缩放动画过程中不允许启动滚动模式

if (!(mScaleAnimator != null && mScaleAnimator.isRunning())) {

//在动画过程中不允许启动滚动模式,停止所有动画

cancelAllAnimator();

//切换到滚动模式

mPinchMode = PINCH_MODE_SCROLL;

//保存触发点的位置用于(5)中的计算

mLastMovePoint.modify(event.getPointerPosition(0).getX(), event.getPointerPosition(0).getY());

}

}

(3)OTHER_POINT_DOWN

需要将图片模式切换到缩放模式,并保存两个触发点的位置,用于(5)中的计算。

else if (action == TouchEvent.OTHER_POINT_DOWN) {

//在动画过程中不允许启动缩放模式,停止所有动画

cancelAllAnimator();

//切换到缩放模式

mPinchMode = PINCH_MODE_SCALE;

//保存缩放的两个触发点的位置,用于(5)中的计算

saveScaleContext(event.getPointerPosition(0).getX(), event.getPointerPosition(0).getY(), event.getPointerPosition(1).getX(), event.getPointerPosition(1).getY());

}

(4)OTHER_POINT_UP

需要判断手指抬起后图片是否处于缩放模式。如果处于缩放模式下,判断识别到的手指是否超过两个。

在剩余手指超过两个(缩放模式未结束)的情况下,第一个触摸的手指抬起,那么让第二个触摸的手指和第三个触摸的手指所在的点作为缩放控制点。

在剩余手指超过两个(缩放模式未结束)的情况下,第二个触摸的手指抬起,那么让第一个触摸的手指和第三个触摸的手指所在的点作为缩放控制点。

如果处于缩放模式下,判断识别到的手指只有一个。此时不能允许它切换到滚动模式,因为图片可能没有在初始的位置上。

手指抬起后图片未处于缩放模式时(屏幕上仅剩余一个手指),开启滚动模式,并记录开始滚动的点。

else if (action == TouchEvent.OTHER_POINT_UP) {

//多个手指情况下抬起一个手指,此时需要是缩放模式才触发

if (mPinchMode == PINCH_MODE_SCALE) {

//抬起的点如果大于2,那么缩放模式还有效,但是有可能初始点变了,重新测量初始点

if (event.getPointerCount() 》 2) {

//如果还没结束缩放模式,但是第一个点抬起了,那么让第二个点和第三个点作为缩放控制点

if (event.getAction() 》》 8 == 0) {

event.getPointerPosition(1).getX();

saveScaleContext(event.getPointerPosition(1).getX(), event.getPointerPosition(1).getY(), event.getPointerPosition(2).getX(), event.getPointerPosition(2).getY());

//如果还没结束缩放模式,但是第二个点抬起了,那么让第一个点和第三个点作为缩放控制点

} else if (event.getAction() 》》 8 == 1) {

saveScaleContext(event.getPointerPosition(0).getX(), event.getPointerPosition(0).getY(), event.getPointerPosition(2).getX(), event.getPointerPosition(2).getY());

}

}

//如果抬起的点等于2,那么此时只剩下一个点,也不允许进入单指模式,因为此时可能图片没有在正确的位置上

}

}

(5)POINT_MOVE

需要判断当前图片的模式。当为滚动模式时,执行 scrollBy() 方法来实现图片的移动效果;当它为缩放模式时,计算两个缩放点的距离和缩放点的中心,并执行 scale() 方法实现图片的缩放效果。

scrollBy() 方法和 scale() 方法的具体逻辑在图片操控方法中有详细介绍,此处就不做过多赘述。

else if (action == TouchEvent.POINT_MOVE) {

if (!(mScaleAnimator != null && mScaleAnimator.isRunning())) {

//在滚动模式下移动

if (mPinchMode == PINCH_MODE_SCROLL) {

//每次移动产生一个差值累积到图片位置上

scrollBy(event.getPointerPosition(0).getX() - mLastMovePoint.position[0], event.getPointerPosition(0).getY() - mLastMovePoint.position[1]);

//记录新的移动点

mLastMovePoint.modify(event.getPointerPosition(0).getX(), event.getPointerPosition(0).getY());

//在缩放模式下移动

} else if (mPinchMode == PINCH_MODE_SCALE && event.getPointerCount() 》 1) {

//两个缩放点间的距离

float distance = MathUtils.getDistance(event.getPointerPosition(0).getX(), event.getPointerPosition(0).getY(), event.getPointerPosition(1).getX(), event.getPointerPosition(1).getY());

//保存缩放点中心

float[] lineCenter = MathUtils.getCenterPoint(event.getPointerPosition(0).getX(), event.getPointerPosition(0).getY(), event.getPointerPosition(1).getX(), event.getPointerPosition(1).getY());

mLastMovePoint.modify(lineCenter[0], lineCenter[1]);

//处理缩放

scale(mScaleCenter, mScaleBase, distance, mLastMovePoint);

}

}

}

②图片操控方法

1、图片缩放

双指捏合:顾名思义是表示两根手指向相反方向移动的操作,该操作可实现图片放大缩小的效果。双指捏合完成图片缩放的功能是由 scale() 方法实现的。

在 scale() 方法体中需要设置各种缩放参数:scaleBase 是缩放系数、scaleCenter 代表图片缩放中点、distance 指两指间距离、lineCenter 是两指中点。

scaleBase 和 distance 相乘会得到缩放比例,图片依旧缩放比例进行变化。

在缩放过程中,图片缩放中点 scaleCenter 会跟随两指中点 lineCenter 移动,实现以两指中点为中心对图片进行放大缩小的效果,缩放效果如图 4 所示。图 4:图片双指缩放

private void scale(Point scaleCenter, float scaleBase, float distance, Point lineCenter) {

if (!isReady()) {

return;

}

//计算图片从fit center状态到目标状态的缩放比例

float scale = scaleBase * distance;

Matrix matrix = MathUtils.matrixTake();

//按照图片缩放中心缩放,并且让缩放中心在缩放点中点上

matrix.postScale(scale, scale, scaleCenter.position[0], scaleCenter.position[1]);

//让图片的缩放中点跟随手指缩放中点

matrix.postTranslate(lineCenter.position[0] - scaleCenter.position[0], lineCenter.position[1] - scaleCenter.position[1]);

//应用变换

mOuterMatrix.setMatrix(matrix);

MathUtils.matrixGiven(matrix);

dispatchOuterMatrixChanged();

//重绘

invalidate();

}

单指双击:表示用单根手指双击屏幕的操作,该操作可实现图片放大缩小的效果,单指双击完成图片缩放的功能是由 doubleTap() 方法实现的。

在 doubleTap() 方法体中我们初始化了一个缩放动画的对象 mScaleAnimator(),它有两个参数分别为 mOuterMatrix(开始矩阵)和 animEnd(结束矩阵)。

开始矩阵表示图片原来的位置与大小;结束矩阵表示图片缩放后的位置与大小,是根据放大比例和双击点位置确定的。

确定图片的开始和结束矩阵后,启动缩放动画,便可以实现缩放效果,如图 5 所示:

private void doubleTap(float x, float y) {

...

//开始计算缩放动画的结果矩阵

Matrix animEnd = MathUtils.matrixTake(mOuterMatrix);

//计算还需缩放的倍数

animEnd.postScale(nextScale / currentScale, nextScale / currentScale, x, y);

//将放大点移动到控件中心

animEnd.postTranslate(displayWidth / 2f - x, displayHeight / 2f - y);

RectFloat testBound = MathUtils.rectFTake(0,0,mp.getImageInfo().size.width,mp.getImageInfo().size.height);

...

//清理当前可能正在执行的动画

cancelAllAnimator();

//启动矩阵动画

mScaleAnimator = new ScaleAnimator(mOuterMatrix, animEnd);

mScaleAnimator.start();

...

}

2、图片在缩放状态下移动

单指滑动表示手指在屏幕上完成矢量平移,是图片移动的唯一方式。该功能是通过 scrollBy() 方法实现的。

以实现图片左右移动为例,在 scrollBy() 方法中,需要判断缩放状态下图片位移的最大距离,有以下几种不同的情况:

图片移动后,左侧边缘超出控件的左侧边缘,图片无法移动。

图片移动后,右侧边缘超出控件的右侧边缘,图片无法移动。

图片移动后,两侧都未超出控件边缘的情况下,将以手指触碰点作为控制点,对图片进行水平移动。

图片上下平移的情况与左右平移类似,这里不做赘述,图片移动效果如图 6 所示:

图 6:图片移动的最大距离

public boolean scrollBy(float xDiff, float yDiff) {

...

if (bound.right - bound.left 《 displayWidth) {

xDiff = 0;

//如果图片左边在移动后超出控件左边

} else if (bound.left + xDiff 》 0) {

//如果在移动之前是没超出的,计算应该移动的距离

if (bound.left 《 0) {

xDiff = -bound.left;

//否则无法移动

} else {

xDiff = 0;

}

//如果图片右边在移动后超出控件右边

} else if (bound.right + xDiff 《 displayWidth) {

//如果在移动之前是没超出的,计算应该移动的距离

if (bound.right 》 displayWidth) {

xDiff = displayWidth - bound.right;

//否则无法移动

} else {

xDiff = 0;

}

}

...

}

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 操作系统
    +关注

    关注

    37

    文章

    6727

    浏览量

    123182
  • 鸿蒙系统
    +关注

    关注

    183

    文章

    2634

    浏览量

    66203
  • HarmonyOS
    +关注

    关注

    79

    文章

    1967

    浏览量

    30001

原文标题:鸿蒙手势操控组件,代码已开源!

文章出处:【微信号:gh_834c4b3d87fe,微信公众号:OpenHarmony技术社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    如何在开源鸿蒙OpenHarmony开启SELinux模式?RK3566鸿蒙开发板演示

    本文介绍开源鸿蒙OpenHarmony系统下,开启/关闭SELinux权限的方法,触觉智能Purple Pi OH鸿蒙开发板演示,已适配全新OpenHarmony5.0 Release
    的头像 发表于 11-18 19:03 140次阅读
    如何在<b class='flag-5'>开源</b><b class='flag-5'>鸿蒙</b>OpenHarmony开启SELinux模式?RK3566<b class='flag-5'>鸿蒙</b>开发板演示

    开源鸿蒙OpenHarmony系统更换开机Logo方法,RK3566鸿蒙开发板备战第九届华为ICT大赛

    本文适用开源鸿蒙OpenHarmony系统更换开机Logo,本次使用了触觉智能的Purple Pi OH鸿蒙开源主板,搭载了瑞芯微RK356
    的头像 发表于 09-26 09:18 581次阅读
    <b class='flag-5'>开源</b><b class='flag-5'>鸿蒙</b>OpenHarmony<b class='flag-5'>系统</b>更换开机Logo方法,RK3566<b class='flag-5'>鸿蒙</b>开发板备战第九届华为ICT大赛

    鸿蒙ArkTS声明式开发:跨平台支持列表【绑定手势方法】 手势处理

    组件绑定不同类型的手势事件,并设置事件的响应方法。
    的头像 发表于 06-15 09:17 710次阅读
    <b class='flag-5'>鸿蒙</b>ArkTS声明式开发:跨平台支持列表【绑定<b class='flag-5'>手势</b>方法】 <b class='flag-5'>手势</b>处理

    最新开源代码证实!“鸿蒙原生版”微信正在积极开发中

    话不多说,直接看图: 这是 MMKV 最新版本 v1.3.5 的发布说明。 MMKV 是微信团队开源的键值对(Key-Value)存储系统,也是微信客户端自用的底层基础组件 。 发布说明写道
    发表于 05-08 17:08

    腾讯突然宣布,微信鸿蒙版要来了!

    今年初, 华为宣布HarmonyOS NEXT命名为“鸿蒙星河版” ,并计划在二季度启动开发者 Beta 计划,四季度发布商用正式版。 消息一出,不少人为之振奋。 鸿蒙星河版因不再兼容安卓开源
    发表于 04-30 19:34

    开源鸿蒙】下载OpenHarmony 4.1 Release源代码

    本文介绍了如何下载开源鸿蒙(OpenHarmony)操作系统 4.1 Release版本的源代码,该方法同样可以用于下载OpenHarmony最新开发版本(master分支)或者4.0
    的头像 发表于 04-27 23:16 813次阅读
    【<b class='flag-5'>开源</b><b class='flag-5'>鸿蒙</b>】下载OpenHarmony 4.1 Release源<b class='flag-5'>代码</b>

    打造开源鸿蒙生态,国产操作系统迎“转折之战”?| 深圳卫视独家对话深开鸿王成录

    作为正在崛起的国产操作系统开源鸿蒙到底有哪些优势?深圳卫视《大湾区会客厅》主持人何嘉琪独家对话深开鸿CEO王成录博士。探究为什么发展自主操作系统势在必行?
    的头像 发表于 04-20 08:32 469次阅读
    打造<b class='flag-5'>开源</b><b class='flag-5'>鸿蒙</b>生态,国产操作<b class='flag-5'>系统</b>迎“转折之战”?| 深圳卫视独家对话深开鸿王成录

    鸿蒙系统三防平板怎么样

    系统作为华为自主研发的操作系统,具有高度的兼容性和稳定性。用户可以在设备上安装各种应用程序,满足工作、娱乐、学习等多种需求。同时,鸿蒙系统还提供了丰富的交互功能,如语音助手、
    发表于 04-12 14:26

    开源获奖案例】隔空手势识别测试系统

    ——来自迪文开发者论坛本期为大家推送迪文开发者论坛获奖开源案例——隔空手势识别测试系统。工程师采用7英寸COF智能屏,通过T5LOS核与PAJ7620U2手势识别传感器进行数据交互,不
    的头像 发表于 03-16 08:12 528次阅读
    【<b class='flag-5'>开源</b>获奖案例】隔空<b class='flag-5'>手势</b>识别测试<b class='flag-5'>系统</b>

    深圳力挺开源鸿蒙原生应用,深开鸿全力加速开源鸿蒙生态

    近日,深圳市工业和信息化局、深圳市政务服务和数据管理局联合印发《深圳市支持开源鸿蒙原生应用发展2024年行动计划》(以下简称《行动计划》)。据悉,这是全国首个针对鸿蒙原生应用发展的政府行动计划。深开
    的头像 发表于 03-06 14:33 518次阅读
    深圳力挺<b class='flag-5'>开源</b><b class='flag-5'>鸿蒙</b>原生应用,深开鸿全力加速<b class='flag-5'>开源</b><b class='flag-5'>鸿蒙</b>生态

    鸿蒙OS和开源鸿蒙什么关系?

    开源鸿蒙(Open Harmony) 鸿蒙系统愿来的设计初衷,就是让所有设备都可以运行一个系统,但是每个设备的运算能力和功能都不同,所以内核
    的头像 发表于 01-30 15:44 1079次阅读
    <b class='flag-5'>鸿蒙</b>OS和<b class='flag-5'>开源</b><b class='flag-5'>鸿蒙</b>什么关系?

    鸿蒙ArkUI开发-Tabs组件的使用

    鸿蒙ArkUI开发-Tabs组件的使用
    的头像 发表于 01-19 16:01 1754次阅读
    <b class='flag-5'>鸿蒙</b>ArkUI开发-Tabs<b class='flag-5'>组件</b>的使用

    鸿蒙开发OpenHarmony组件复用案例

    { return this.imageList[index] } ...... } 创建复用组件 创建好数据源类后,我们再看下可复用组件代码。 使用装饰器@Reusable来标记一个
    发表于 01-15 17:37

    鸿蒙开发基础-Web组件之cookie操作

    }) ... } ... 本文章主要是对鸿蒙开发当中ArkTS语言的基础应用实战,Web组件里的cookie操作。更多的鸿蒙应用开发技术,可以前往我的主页学习更多,下面是一张鸿蒙
    发表于 01-14 21:31

    [开源]万界星空开源MES系统,支持低代码大屏设计

    万界星空科技免费MES、开源MES、商业开源MES、商业开源代码MES、市面上最好的开源MES、MES源
    的头像 发表于 01-12 13:43 721次阅读
    [<b class='flag-5'>开源</b>]万界星空<b class='flag-5'>开源</b>MES<b class='flag-5'>系统</b>,支持低<b class='flag-5'>代码</b>大屏设计