iOS 自定義鍵盤 左右劃動移動光標 實現

我們都直到,第三方輸入法比如搜狗輸入法有個經典的手勢操作——在鍵盤上左右劃動即可移動光標。而這個功能我自己也十分的常用,所以,我想要自己來實現它。

首先我想到的就是 UISwipeGestureRecognizer ,不過結果可想而知,劃動一次只能移動一格光標,這可不是我想要的。

看來唯一的辦法就是用 UIPanGestureRecognizer 來自己實現了。

最初的想法

最一開始,我想到的就是像捕捉拖動一樣來落去手指在鍵盤上的位置,我只需要獲取 x 軸,如果是正的就往右,負的就往左。

代碼看起來大概像這樣:

因為我只有按照相對方向移動光標的權限,所以只好如此。當然,缺點就是不論移動的快慢,光標的移動速度是與函數調用的頻率一致的。

另一個致命的缺點是如果我手指向一個方向劃動比較遠,再移動回來——這個過程中光標依然會傻傻地超先前的方向繼續移動!

改用加速度而不是坐標作為判斷

好吧,這次我改用 UIPanGestureRecognizer 內置的 velocityInView 來獲取加速度,因為加速度是有方向的!顯然,光標傻傻的朝一個方向移動的問題解決了……可是,它還是依靠系統調用頻率來決定移動的速度,這就導致了光標移動太快。

對系統調用頻率濾波

好在,系統的調用頻率是固定的,這樣的話我們可以輕易地實現濾波,加一個屬性,用來儲存調用的次數,當次數達到了指定的值比如調用了100次,我們才真正執行一次函數:

根據移動速度動態改變光標移動速度

這下光標的移動終於顯得比較合適了,那麼接下來的問題就是光標的移動速度改變了,現在移動速度是固定的,無論你是想要快一點移動還是慢一點移動,都不行。要達到這一目的,我們還得在加速度上做文章。

加速度會根據你手指在屏幕上移動的速度而改變,簡而言之就是你劃動的越快,那麼加速度就越大——這麼一來我們就有了兩個方案:

  1. 根據加速度改變一次移動光標的字數;
  2. 根據加速度跟邊函數調用的頻率。

方案 1 比較簡單,把加速度計算到個位數然後直接扔給 adjustTextPositionByCharacterOffset(_:) 就好了,可是這有個問題——定位精確度會下降。這裡我選擇了更類似搜狗輸入法的後者,我依舊每次移動光標 1 個字符的距離,只需要改變函數的調用頻率——也就是說,改變我們的濾波算法就好了。

現在的濾波只是單純的每 100 次取 1 次,那麼我們提前獲取一次加速度,把它算進去試試,由於加速度有方向——你總不能給濾波器增量減回去吧?我們用 ABS 全局數學函數來求一下絕對值,再進行處理,同時由於加速度變化巨大,經過多次測試,縮小10倍比較合適,那麼代碼看起來就是這個樣子的:

這樣,函數實際的調用頻率會由濾波器決定,而濾波器的增量又由你實際劃動時在屏幕上產生的加速度來決定,從而實現了光標跟手指幾乎同步移動的效果。

誤操作兼容

最後,我們再來點收尾的工作。由於識別層在鍵盤的按鈕下邊,那麼我們就要讓它們合作無間才行—— UIPanGestureRecognizer 會立即取消 的UIButton 的點擊操作,也就是說,如果用戶打字比較快,而手指又不小心在鍵盤上搓了一下,那麼系統就會識別為微小但加速度很大的劃動而不是點擊。

所以,第一步,我們需要取消 cancelsTouchesInView ,給它賦值為 false 或者在圖形配置裡取消這個的勾選。

光這一點還不夠,我們還得繼續加大相應的閾值,在濾波器前邊再獲取拖動的絕對值,如果拖動小於一定的距離,就同​​樣不執行函數,給用戶留下一定的緩衝空間,只有用戶真的想要劃動來移動光標的時候才去移動光標,那麼,最終的函數應該是這樣的:

 

本文由 落格博客 原創撰寫:落格博客 » iOS 自定義鍵盤 左右劃動移動光標 實現

轉載請保留出處和原文鏈接:https://www.logcg.com/archives/1987.html

由...出版 落格博客

如非聲明,本人所著文章均為原創手打,轉載請註明本頁面鏈接和我的名字。

發表評論

您的電子郵件地址不會被公開. 必填字段標 *