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

    文章

    6288

    浏览量

    121887
  • 鸿蒙系统
    +关注

    关注

    183

    文章

    2625

    浏览量

    65274
  • HarmonyOS
    +关注

    关注

    79

    文章

    1853

    浏览量

    29267

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

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

收藏 人收藏

    评论

    相关推荐

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

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

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

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

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

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

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

    鸿蒙ArkUI开发-Tabs组件的使用
    的头像 发表于 01-19 16:01 438次阅读
    <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

    华为鸿蒙系统

    华为鸿蒙系统(HUAWEI Harmony OS),是华为公司在2019年8月9日于东莞举行的华为开发者大会(HDC.2019)上正式发布的操作系统。 华为鸿蒙
    发表于 11-02 19:39

    鸿蒙 OS 应用开发初体验

    Setup HarmonyOS-SDK:鸿蒙操作系统软件开发工具包 Previewer:预览器 Toolchains:工具链 OpenHarmony-SDK:开源鸿蒙操作
    发表于 11-02 19:38

    Orange Pi OS(OH)发布,开源鸿蒙PC端来了!

    了Orange Pi OS(OH)对PC的初步适配,这是国内首次将开源鸿蒙操作系统运行在PC设备上,意味着迅龙软件将领先于华为、深开鸿等,在业内率先推出PC端的开源
    发表于 10-26 11:32

    鸿蒙操作系统的前世今生

    部分,OpenHarmonyOS、包括HMS在内的闭源应用与服务,以及其他开放源代码。 其中OpenHarmonyOS 是鸿蒙操作系统开源的部分,类似于安卓
    发表于 10-08 19:55

    手势控制机器人开源项目

    电子发烧友网站提供《手势控制机器人开源项目.zip》资料免费下载
    发表于 07-12 11:18 0次下载
    <b class='flag-5'>手势</b>控制机器人<b class='flag-5'>开源</b>项目

    手势识别功能开源案例

    电子发烧友网站提供《手势识别功能开源案例.zip》资料免费下载
    发表于 07-11 17:05 2次下载
    <b class='flag-5'>手势</b>识别功能<b class='flag-5'>开源</b>案例

    超声波手势控制开源分享

    电子发烧友网站提供《超声波手势控制开源分享.zip》资料免费下载
    发表于 06-29 14:40 0次下载
    超声波<b class='flag-5'>手势</b>控制<b class='flag-5'>开源</b>分享

    手势游戏模拟器开源设计

    电子发烧友网站提供《手势游戏模拟器开源设计.zip》资料免费下载
    发表于 06-19 14:55 0次下载
    <b class='flag-5'>手势</b>游戏模拟器<b class='flag-5'>开源</b>设计