android 仿ios光标移动,iOS 自定义键盘 左右划动移动光标 实现

news/2025/2/5 4:09:08/

最近更新:5th 9月, 2016

我们都直到,第三方输入法比如搜狗输入法有个经典的手势操作——在键盘上左右划动即可移动光标。而这个功能我自己也十分的常用,所以,我想要自己来实现它。

首先我想到的就是

UISwipeGestureRecognizer ,不过结果可想而知,划动一次只能移动一格光标,这可不是我想要的。

看来唯一的办法就是用

UIPanGestureRecognizer 来自己实现了。

最初的想法

最一开始,我想到的就是像捕捉拖动一样来落去手指在键盘上的位置,我只需要获取 x 轴,如果是正的就往右,负的就往左。

代码看起来大概像这样:

1

2

3

4

5

6

7

@IBActionfuncmoveCurser(sender:UIPanGestureRecognizer){

ifsender.translationInView(keyboardView).x<0{

self.textDocumentProxy.adjustTextPositionByCharacterOffset(-1)

}else{

self.textDocumentProxy.adjustTextPositionByCharacterOffset(1)

}

}

因为我只有按照相对方向移动光标的权限,所以只好如此。当然,缺点就是不论移动的快慢,光标的移动速度是与函数调用的频率一致的。

另一个致命的缺点是如果我手指向一个方向划动比较远,再移动回来——这个过程中光标依然会傻傻地超先前的方向继续移动!

改用加速度而不是坐标作为判断

好吧,这次我改用

UIPanGestureRecognizer 内置的

velocityInView 来获取加速度,因为加速度是有方向的!显然,光标傻傻的朝一个方向移动的问题解决了……可是,它还是依靠系统调用频率来决定移动的速度,这就导致了光标移动太快。

对系统调用频率滤波

好在,系统的调用频率是固定的,这样的话我们可以轻易地实现滤波,加一个属性,用来储存调用的次数,当次数达到了指定的值比如调用了100次,我们才真正执行一次函数:

1

2

3

4

5

6

7

8

9

10

11

varrecognizerCount=0

@IBActionfuncmoveCurser(sender:UIPanGestureRecognizer){

recognizerCount+=1

guardrecognizerCount>100else{return}

recognizerCount=0

ifsender.velocityInView(keyboardView).x<0{

self.textDocumentProxy.adjustTextPositionByCharacterOffset(-1)

}else{

self.textDocumentProxy.adjustTextPositionByCharacterOffset(1)

}

}

根据移动速度动态改变光标移动速度

这下光标的移动终于显得比较合适了,那么接下来的问题就是光标的移动速度改变了,现在移动速度是固定的,无论你是想要快一点移动还是慢一点移动,都不行。要达到这一目的,我们还得在加速度上做文章。

加速度会根据你手指在屏幕上移动的速度而改变,简而言之就是你划动的越快,那么加速度就越大——这么一来我们就有了两个方案:

根据加速度改变一次移动光标的字数;

根据加速度跟边函数调用的频率。

方案 1 比较简单,把加速度计算到个位数然后直接扔给

adjustTextPositionByCharacterOffset(_:) 就好了,可是这有个问题——定位精确度会下降。这里我选择了更类似搜狗输入法的后者,我依旧每次移动光标 1 个字符的距离,只需要改变函数的调用频率——也就是说,改变我们的滤波算法就好了。

现在的滤波只是单纯的每 100 次取 1 次,那么我们提前获取一次加速度,把它算进去试试,由于加速度有方向——你总不能给滤波器增量减回去吧?我们用

abs 全局数学函数来求一下绝对值,再进行处理,同时由于加速度变化巨大,经过多次测试,缩小10倍比较合适,那么代码看起来就是这个样子的:

1

2

3

4

5

6

7

8

9

10

11

12

varrecognizerCount=0

@IBActionfuncmoveCurser(sender:UIPanGestureRecognizer){

letv=Int(sender.velocityInView(keyboardView).x)

recognizerCount+=Int(abs(v)/10)

guardrecognizerCount>100else{return}

recognizerCount=0

ifsender.velocityInView(keyboardView).x<0{

self.textDocumentProxy.adjustTextPositionByCharacterOffset(-1)

}else{

self.textDocumentProxy.adjustTextPositionByCharacterOffset(1)

}

}

这样,函数实际的调用频率会由滤波器决定,而滤波器的增量又由你实际划动时在屏幕上产生的加速度来决定,从而实现了光标跟手指几乎同步移动的效果。

误操作兼容

最后,我们再来点收尾的工作。由于识别层在键盘的按钮下边,那么我们就要让它们合作无间才行——

UIPanGestureRecognizer 会立即取消

UIButton 的点击操作,也就是说,如果用户打字比较快,而手指又不小心在键盘上搓了一下,那么系统就会识别为微小但加速度很大的划动而不是点击。

所以,第一步,我们需要取消

cancelsTouchesInView ,给它赋值为 false 或者在图形配置里取消这个的勾选。

光这一点还不够,我们还得继续加大相应的阈值,在滤波器前边再获取拖动的绝对值,如果拖动小于一定的距离,就同样不执行函数,给用户留下一定的缓冲空间,只有用户真的想要划动来移动光标的时候才去移动光标,那么,最终的函数应该是这样的:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

varrecognizerCount=0

@IBActionfuncmoveCurser(sender:UIPanGestureRecognizer){

guardabs(sender.translationInView(keyboardView).x)>70else{return}

letv=Int(sender.velocityInView(keyboardView).x)

recognizerCount+=Int(abs(v)/10)

guardrecognizerCount>100else{return}

recognizerCount=0

ifsender.velocityInView(keyboardView).x<0{

self.textDocumentProxy.adjustTextPositionByCharacterOffset(-1)

}else{

self.textDocumentProxy.adjustTextPositionByCharacterOffset(1)

}

}


http://www.ppmy.cn/news/764113.html

相关文章

微信小程序长图超过屏幕页面不能下拉_微信小程序的页面弹窗过长滚动导致的底层滚动(滚动穿透问题)解决办法...

对于微信小程序,弹窗时,如果弹窗内容过长,需要滚动,滚动同时,底部页面跟着滚动,这如何优雅的处理这个问题? 处理1(不推荐): --添加 position:fixed 弹窗时通过给底部最大的view标签添加position:fixed;,从而达到页面不会跟着弹窗滚动 超长底部内容 弹窗超长内容 缺点:…

appium java滑动_JAVA+Appium 自动化实现手机屏幕滑动点击操作

背景:App某些页面元素无法通过Appium或其他方式抓取到,无法通过传统方式定位到元素。 原理:获取到当前屏幕的尺寸,在要操作的元素的屏幕位置构造像素点位,进而执行点击或滑动操作。 注:坐标定位时采用相对定位方式,可适配其他分辨率。 1、坐标点击屏幕元素 io.appium ja…

python ui测试 手机界面控件不可见时_python ui测试 手机界面控件不可见时_uiautomator2小笔记...

import uiautomator2 as u2 &#xff03;通过WIFI d u2.connect(10 .0.0.1)&#xff03;u2.connect_wifi(10 .0.0.1)的&#xff03;别名 &#xff03;通过usb获取设备 d u2.connect(123456f)&#xff03;u2.connect_usb(123456f)的&#xff03;别名 6、系统操作&#xff1a; …

unity 滑动屏幕改变视角看物体

滑动效果图&#xff1a; 做法&#xff1a; 把下面的Camera.cs脚本放在相机上&#xff0c;并给代码中的FollowObject拖拽被观察物体&#xff08;旋转中心&#xff09;即可 using UnityEngine; public class Camera : MonoBehaviour {public Transform FollowObject; //被跟随…

android 屏幕统计,OffScreen - 屏幕时间统计

编辑点评 你康康你今天又玩了多少次手机! OffScreen - 屏幕时间统计 介绍 OffScreen - 屏幕时间统计 日常生活中,大多数人有轻微甚至严重的「手机依赖症」,我们无时无刻盯着手机,不断地一边走路一边刷着朋友圈微博和抖音,没日没夜打游戏,通宵追着各种电视剧,被各种消息通…

html body自适应屏幕大小,如何让网页自适应所有屏幕宽度

随着网络的快熟发展,越来越多的人使用手机上网。移动设备正超过桌面设备,成为访问互联网的最常见终端。于是,网页设计师不得不面对一个难题:如何才能在不同大小的设备上呈现同样的网页?手机的屏幕比较小,宽度通常在600像素以下;PC的屏幕宽度,一般都在1000像素以上,有的…

bootstrap轮播图在手机上实现手指划动切换图片

$carousels $("#effect");//effect是轮播图id var startX,endX; // 在滑动的一定范围内&#xff0c;才切换图片 var offset 50; // 注册滑动事件 $carousels.on(touchstart,function (e) {// 手指触摸开始时记录一下手指所在的坐标xstartX e.originalEvent.touche…

小程序如何把按钮位置固定,不随手机屏幕上下滑动而变化

做了一款任何页面返回首页的按钮&#xff0c;代码如下 .back_home{ position: fixed; width:120rpx; height:60rpx; top: 50rpx; left: 0px; font-size: 24rpx; } <div style"z-index:30"> //用div使按钮在最高层&#xff0c;不会被遮挡 <button …