做項目時發現,在一個界面上的2個button竟然可以同時點擊,依次push進去了2個 controller!我就產生了疑問,一個view的multipleTouchEnabled屬性默認是false啊,那怎么會可以同時點擊這個view上的2個子view呢?原來是對multipleTouchEnabled屬性理解不對!下面看看對這個屬性的理解。
multipleTouchEnabled的官方解釋如下:
When set to true, the receiver receives all touches associated with a multi-touch sequence. When set to false, the receiver receives only the first touch event in a multi-touch sequence. The default value of this property is false. Other views in the same window can still receive touch events when this property is false. If you want this view to handle multi-touch events exclusively, set the values of both this property and the exclusiveTouch property to true.
exclusiveTouch的官方解釋如下:
Setting this property to true causes the receiver to block the delivery of touch events to other views in the same window. The default value of this property is false.
注意:touch events的發送,是以window為一個組,而不是某個在window下的子view。
看到這里其實就可以得出結論了,如果你不想讓2個button同時點擊,只需要把它們的exclusiveTouch都設定為YES,就行了!multipleTouchEnabled沒這個作用,我用錯了屬性!
參考的官方文檔 Event Handling Guide,這個文檔需要仔細閱讀!
一個父view的multipleTouchEnabled屬性不會影響它的子view的multipleTouchEnabled屬性,也就是說,在一個multipleTouchEnabled = false的父view里,仍然可以有接受多個手指點擊消息的子view。
再來看這個函數touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent),這里有2個參數,官方說明如下:
The set object. The passed-in NSSet contains all touches that are new or have changed in the phase represented by the method, such as UITouchPhaseBegan for the touchesBegan:withEvent: method.
The event object. The passed-in UIEvent object contains all of the touches for a given multitouch sequence.
The multipleTouchEnabled property is set to NO by default, which means that a view receives only the first touch in a multitouch sequence. When this property is disabled, you can retrieve a touch object by calling the anyObject method on the set object because there is only one object in the set.
下面是另一部分解釋
The set of touches is a set (NSSet) of UITouch objects, representing new or changed touches for that phase. For example, when a touch transitions from the Began phase to the Moved phase, the app calls the touchesMoved:withEvent: method. The set of touches passed in to the touchesMoved:withEvent: method will now include this touch and all other touches in the Moved phase. The other parameter is an event (UIEvent object) that includes all touch objects for the event. This differs from the set of touches because some of the touch objects in the event may not have changed since the previous event message.
這里提到了一個名詞 a multitouch sequence,一個sequence指從第一個手指按下到最后一個手指抬起,也可以通過以下的話理解:
iOS recognizes touches as part of a multitouch sequence. During a multitouch sequence, the app sends a series of event messages to the target responder.
上面的意思就是ios把所有的touch事件都作為 a multitouch sequence 的一部分,在a multitouch sequence生命周期內,不斷發送touch event到target。
Each of these touch methods correspond to a touch phase: Began, Moved, Ended, and Canceled. When there are new or changed touches for a given phase, the app object calls one of these methods. Each method takes two parameters: a set of touches and an event.
所謂的multipleTouchEnabled = false 指的是這個view 只接收一個multitouch sequence中的第一個點在自己上面的手指的event信息,其余的手指event變化信息,都不會被這個view理會,所以對於一個multipleTouchEnabled = false的view來說,touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) ,第一個參數中永遠只有一個touch對象,就是那個手指的event信息,而后邊的event則會包含整個multitouch sequence 中的點擊信息。
因此,可以看出multipleTouchEnabled這個屬性不是為了控制這個view下的整個 tree 的點擊控制的。這就導致了即使在一個multipleTouchEnabled=false的view上,放置了多個button,可以用多個手指同時點擊這些button!
我們看一個例子,代碼如下
class TouchView: UIView { override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) { var touchSet = event.allTouches() println("touchesBegan...touches set count is \(touches.count)") println("UIEvent touch count is \(touchSet!.count)") } }
class ViewController: UIViewController {
@IBOutlet weak var view1: UIView!
@IBOutlet weak var view2: UIView!
override func viewDidLoad() {
super.viewDidLoad()
self.view.multipleTouchEnabled = false
view1.multipleTouchEnabled = true
view2.multipleTouchEnabled = false
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
println("self view touchesBegan.....")
}
}
界面截圖如下
黃色是self.view 藍色和紅色是2個touchview,我們的點擊方式如下
1.點擊藍色view,不放開
2.點擊藍色view,不放開
3.點擊紅色view,不放開
4.點擊紅色view,不放開
5.點擊藍色view,不放開
控制台輸出如下:
touchesBegan...touches set count is 1 UIEvent touch count is 1 touchesBegan...touches set count is 1 UIEvent touch count is 2 touchesBegan...touches set count is 1 UIEvent touch count is 3 touchesBegan...touches set count is 1 UIEvent touch count is 5
這里的第三條是紅色view第一次點擊的輸出,第二次的紅色view點擊輸出沒有,因為它的view2.multipleTouchEnabled = false
再來另一個測試:
1.點擊黃色,不放開
2.點擊藍色,不放
3.點擊紅色,不放
輸出如下:
self view touchesBegan..... touchesBegan...touches set count is 1 UIEvent touch count is 2 touchesBegan...touches set count is 1 UIEvent touch count is 3
另外說一點,如果這里我們沒有對紅色和藍色的類重寫 touchesBegan 方法,那么系統默認會把消息交給 self.view 也就是黃色view處理。