跟iOS UI的捉迷藏(如何獲取用戶點擊行爲的控件title)

近期,接到一個需求,需要獲取用戶點擊行爲的操作路徑,除了點擊的座標,classname等常用數據外,還需要控件的title,這樣就可以更加直觀的瞭解到用戶的操作行爲。

乍一聽,熟悉Android的同學會說, View的onClick事件監聽就好了,然而,iOS與Android並不相同,一方面,iOS沒有統一的獲取title的方式,另一方面,不同UI控件title的位置不盡相同,所以,要想獲取常用控件的的title,着實需要對控件的層級結構有一定的瞭解,本文目前只對常用的7個控件進行介紹,後期可能會增加,歡迎大家一起探討嘗試,如有留言案例我會一起嘗試。

1.如何獲取用戶控件的點擊行爲

事實上,由於獲取的“所見所得”點擊view行爲,所以,思路上應該是對uiview或者及其子類得某個事件方法hook到,這樣觸發點擊(廣義上是觸摸)行爲後,可以根據發送的事件確定點擊的UI控件類型,進一步獲取對應title

事實上,具體流程比較複雜,如下圖:

這裏有篇文章講的比較詳細:

https://www.jianshu.com/p/ae6466d3e89e 裏面不僅講了整個流程,還對不同控件的優先順序進行了說明,這對比較複雜的自定義的UI是比較重要的。

根據上文可知,當UIControl監聽到需要處理的交互事件時,會調用 sendAction:to:forEvent: 將target、action以及event對象發送給全局應用,Application對象再通過 sendAction:to:from:forEvent: 向target發送action。

我們只需要通過hook UIControl的 sendAction:to:forEvent: 或 sendAction:to:from:forEvent: 自定義事件執行的target及action。

這裏我們用第一個,sendAction:to:forEvent:

裏面有三個參數,最後一個是event,可以通過allTouches方法,可以獲得觸摸點的集合,可以判斷多點觸摸事件

而touch.view或touch.window可以獲取對應的uiview或者uiwindow

對應的點擊位置信息可以用過 [uiTouch locationInView:uiTouch.view]獲取;

這樣我們就能對uiview進行判斷,並獲取title了

觸摸事件參考文章:https://www.cnblogs.com/syxchina/archive/2012/10/14/2723541.html

2.如何獲取不同控件的title

至此,我們可以獲取到uiview,這裏就需要判斷目標是uiview的哪個子類

沒錯,iOS沒有統一的title獲取方式,所以要對每種控件單獨判斷。。。

先從簡單的開始

一階獲取的控件:UIButton

響應的uiview是UIButton,即用戶點擊的是按鈕,則立馬獲取(即一階獲取)

NSString * title = [[button titleLabel] text];

下面加大難度,獲取UITableView的cell內容

二階獲取的控件:UITableView的cell

通過上面的方法,當用戶點擊了紅色字體的內容後,響應的view是UITableViewCellContentView

這個方法與UITableView的關係如下:

這裏有兩種方法,一種是獲取UITableViewCellContentView的subview,再獲取label的text,也可以獲取UITableViewCellContentView的superview,通過[[uitableview textLabel] text]方法獲得,拐了一個彎,需要父view或子view,即二階獲取

二階獲取的控件:UITabBar

UITabBar也是一個常用的佈局

層級關係如下:

向下一層即可獲取,也是二階獲取

 

下面繼續,獲取頁面上面的button(UINavigationController的leftBarButtonItem和rightBarButtonItems)

三階獲取的控件:UINavigationController的leftBarButtonItem、rightBarButtonItems

通過上面響應的uiview是_UIButtonBarButton(注意下劃線)

查詢層級結構如下:

從上圖可知需要獲取_UIButtonBarButton子view(_UIModernBarButton)的子view,即UIButtonLabel,才能獲取title,即三階獲取

四階獲取的控件:UINavigationController的backButton

還有一個跟它類似的地方,即vc的返回按鈕

層級關係如下:

雖然響應的都是_UIModernBarButton,但子view是_UIBackButtonContainerView,再是_UIModernBarButton,再是UIButtonLabel,可以稱爲四階獲取

五階獲取的控件:UIswitch

下一個UIswitch,UIswitch比較特殊,它本身沒有title,但一般都與某個cell合併使用,所以直接獲取父view的cell的title

層級關係如下:

這裏響應的view比較靠下,需要一直向上找4層,再向下找1層,才能找到ULTableViewLabel,所以爲五階獲取

平行獲取的控件:UINavigationController的backButton

這是個比較有意思的空間,點擊UICollectionViewCell,響應的是一個UIView

層級關係如下:

它與UILabel是平行的,獲取的方法是先找到父viewUICollectionViewCell,再找到其子view,纔可以

錯位獲取,UISegmentedControl

通過上面的獲取,基本上把父view和子view的關係搞清,層級可能比較多,但都可獲取,但UISegmented是個例外

當我們點擊“傢俱”這個segment時,獲取是UISegmentedControl

層級關係如下:

UISegmentedControl裏面有好幾個UISegment。。。。。。

這樣就無法確定是哪個UISegment

換條路

通過打印UISegmentedControl的方法列表,我們找到了一個selectedSegmentIndex

這個對應的內容爲最後一個被選中的UISegment,額,所以當用戶點擊任何一個UISegment時,我們可以獲得前一個UISegment,即離開的UISegment是哪個。

難道真的沒有SegmentIndex可以獲取嗎?

查官方文檔

找到了一個,但是iOS14纔開放的方法

可以升級後好好試一下,如果大家有好的方法獲取,請留言。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章