Swift
Đây là nhiều cách để phân lớp UIControl
. Khi chế độ xem gốc cần phản ứng với sự kiện chạm hoặc lấy dữ liệu khác từ điều khiển, điều này thường được thực hiện bằng (1) mục tiêu hoặc (2) mẫu đại biểu có sự kiện chạm đã ghi đè. Để hoàn thành, tôi cũng sẽ chỉ cách (3) làm điều tương tự với trình nhận dạng cử chỉ. Mỗi phương pháp này sẽ hoạt động giống như các hình ảnh động sau:

Bạn chỉ cần chọn một trong những phương pháp sau đây.
Phương pháp 1: Thêm một mục tiêu
Một lớp con UIControl
đã hỗ trợ cho các mục tiêu đã được xây dựng trong Nếu bạn không cần phải vượt qua rất nhiều dữ liệu để phụ huynh, đây có lẽ là phương pháp bạn. muốn.
MyCustomControl.swift
import UIKit
class MyCustomControl: UIControl {
// You don't need to do anything special in the control for targets to work.
}
ViewController.swift
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var myCustomControl: MyCustomControl!
@IBOutlet weak var trackingBeganLabel: UILabel!
@IBOutlet weak var trackingEndedLabel: UILabel!
@IBOutlet weak var xLabel: UILabel!
@IBOutlet weak var yLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Add the targets
// Whenever the given even occurs, the action method will be called
myCustomControl.addTarget(self, action: #selector(touchedDown), forControlEvents: UIControlEvents.TouchDown)
myCustomControl.addTarget(self, action: #selector(didDragInsideControl(_:withEvent:)),
forControlEvents: UIControlEvents.TouchDragInside)
myCustomControl.addTarget(self, action: #selector(touchedUpInside), forControlEvents: UIControlEvents.TouchUpInside)
}
// MARK: - target action methods
func touchedDown() {
trackingBeganLabel.text = "Tracking began"
}
func touchedUpInside() {
trackingEndedLabel.text = "Tracking ended"
}
func didDragInsideControl(control: MyCustomControl, withEvent event: UIEvent) {
if let touch = event.touchesForView(control)?.first {
let location = touch.locationInView(control)
xLabel.text = "x: \(location.x)"
yLabel.text = "y: \(location.y)"
}
}
}
Ghi chú
- Không có gì đặc biệt là về tên phương thức hành động. Tôi có thể gọi họ là gì. Tôi chỉ cần cẩn thận để đánh vần tên phương thức chính xác như tôi đã làm nơi tôi đã thêm mục tiêu. Nếu không, bạn sẽ gặp sự cố.
- Hai dấu hai chấm trong
didDragInsideControl:withEvent:
có nghĩa là hai thông số đang được chuyển đến phương thức didDragInsideControl
. Nếu bạn quên thêm dấu hai chấm hoặc nếu bạn không có số tham số chính xác, bạn sẽ gặp sự cố.
- Cảm ơn this answer để được trợ giúp về sự kiện
TouchDragInside
.
Truyền dữ liệu khác
Nếu bạn có một số giá trị trong điều khiển tùy chỉnh của bạn
class MyCustomControl: UIControl {
var someValue = "hello"
}
mà bạn muốn truy cập trong phương pháp hành động mục tiêu, sau đó bạn có thể vượt qua trong một tham chiếu đến sự kiểm soát. Khi bạn đang thiết lập mục tiêu, hãy thêm dấu hai chấm sau tên phương thức hành động. Ví dụ:
myCustomControl.addTarget(self, action: #selector(touchedDown), forControlEvents: UIControlEvents.TouchDown)
Chú ý rằng nó là touchedDown:
(với một dấu hai chấm) và không touchedDown
(không có dấu hai chấm). Dấu hai chấm có nghĩa là một tham số đang được chuyển tới phương thức hành động. Trong phương thức hành động, hãy chỉ định tham số là tham chiếu đến lớp con UIControl
của bạn. Với tham chiếu đó, bạn có thể lấy dữ liệu từ kiểm soát của mình.
func touchedDown(control: MyCustomControl) {
trackingBeganLabel.text = "Tracking began"
// now you have access to the public properties and methods of your control
print(control.someValue)
}
Cách 2: Ủy Pattern và Override Sự kiện cảm ứng
subclassing UIControl
cho chúng ta tiếp cận với các phương pháp sau:
beginTrackingWithTouch
được gọi khi ngón tay đầu tiên chạm xuống trong giới hạn của kiểm soát.
continueTrackingWithTouch
được gọi nhiều lần khi các ngón tay trượt qua điều khiển và thậm chí nằm ngoài phạm vi kiểm soát.
endTrackingWithTouch
được gọi khi ngón tay nhấc khỏi màn hình.
Nếu bạn cần kiểm soát đặc biệt các sự kiện chạm hoặc nếu bạn có nhiều thông tin liên lạc dữ liệu để làm với cha mẹ, thì phương pháp này có thể hoạt động tốt hơn sau đó thêm mục tiêu.
Sau đây là cách để làm điều đó:
MyCustomControl.swift
import UIKit
// These are out self-defined rules for how we will communicate with other classes
protocol ViewControllerCommunicationDelegate: class {
func myTrackingBegan()
func myTrackingContinuing(location: CGPoint)
func myTrackingEnded()
}
class MyCustomControl: UIControl {
// whichever class wants to be notified of the touch events must set the delegate to itself
weak var delegate: ViewControllerCommunicationDelegate?
override func beginTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool {
// notify the delegate (i.e. the view controller)
delegate?.myTrackingBegan()
// returning true means that future events (like continueTrackingWithTouch and endTrackingWithTouch) will continue to be fired
return true
}
override func continueTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool {
// get the touch location in our custom control's own coordinate system
let point = touch.locationInView(self)
// Update the delegate (i.e. the view controller) with the new coordinate point
delegate?.myTrackingContinuing(point)
// returning true means that future events will continue to be fired
return true
}
override func endTrackingWithTouch(touch: UITouch?, withEvent event: UIEvent?) {
// notify the delegate (i.e. the view controller)
delegate?.myTrackingEnded()
}
}
ViewController.swift
Đây là cách điều khiển xem được thiết lập để được các đại biểu và trả lời các sự kiện chạm từ điều khiển tùy chỉnh của chúng tôi.
import UIKit
class ViewController: UIViewController, ViewControllerCommunicationDelegate {
@IBOutlet weak var myCustomControl: MyCustomControl!
@IBOutlet weak var trackingBeganLabel: UILabel!
@IBOutlet weak var trackingEndedLabel: UILabel!
@IBOutlet weak var xLabel: UILabel!
@IBOutlet weak var yLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
myCustomControl.delegate = self
}
func myTrackingBegan() {
trackingBeganLabel.text = "Tracking began"
}
func myTrackingContinuing(location: CGPoint) {
xLabel.text = "x: \(location.x)"
yLabel.text = "y: \(location.y)"
}
func myTrackingEnded() {
trackingEndedLabel.text = "Tracking ended"
}
}
Ghi chú
- Để tìm hiểu thêm về mô hình đại biểu, xem this answer.
Không nhất thiết phải sử dụng đại biểu với các phương pháp này nếu chúng chỉ được sử dụng trong chính quyền điều khiển tùy chỉnh. Tôi có thể vừa thêm tuyên bố print
để cho biết cách các sự kiện đang được gọi. Trong trường hợp đó, các mã sẽ được đơn giản hóa để
import UIKit
class MyCustomControl: UIControl {
override func beginTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool {
print("Began tracking")
return true
}
override func continueTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool {
let point = touch.locationInView(self)
print("x: \(point.x), y: \(point.y)")
return true
}
override func endTrackingWithTouch(touch: UITouch?, withEvent event: UIEvent?) {
print("Ended tracking")
}
}
Phương pháp 3: Sử dụng một Recognizer Gesture
Thêm một nhận dạng cử chỉ có thể được thực hiện trên bất kỳ quan điểm và nó cũng hoạt động trên một UIControl
. Để có kết quả tương tự với ví dụ ở trên cùng, chúng tôi sẽ sử dụng một số UIPanGestureRecognizer
. Sau đó, bằng cách kiểm tra các trạng thái khác nhau khi một sự kiện được kích hoạt, chúng ta có thể xác định những gì đang xảy ra.
MyCustomControl.swift
import UIKit
class MyCustomControl: UIControl {
// nothing special is required in the control to make it work
}
ViewController.nhanh chóng
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var myCustomControl: MyCustomControl!
@IBOutlet weak var trackingBeganLabel: UILabel!
@IBOutlet weak var trackingEndedLabel: UILabel!
@IBOutlet weak var xLabel: UILabel!
@IBOutlet weak var yLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// add gesture recognizer
let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(gestureRecognized(_:)))
myCustomControl.addGestureRecognizer(gestureRecognizer)
}
// gesture recognizer action method
func gestureRecognized(gesture: UIPanGestureRecognizer) {
if gesture.state == UIGestureRecognizerState.Began {
trackingBeganLabel.text = "Tracking began"
} else if gesture.state == UIGestureRecognizerState.Changed {
let location = gesture.locationInView(myCustomControl)
xLabel.text = "x: \(location.x)"
yLabel.text = "y: \(location.y)"
} else if gesture.state == UIGestureRecognizerState.Ended {
trackingEndedLabel.text = "Tracking ended"
}
}
}
Ghi chú
- Đừng quên để thêm ruột sau tên phương pháp hành động trong
action: "gestureRecognized:"
. Dấu hai chấm có nghĩa là các thông số đang được chuyển.
- Nếu bạn cần lấy dữ liệu từ điều khiển, bạn có thể triển khai mẫu đại biểu như trong phương pháp 2 ở trên.
Bạn chắc chắn có thể phân lớp UIControl, và đó là những phương pháp đúng để ghi đè. Bạn có đang lập tức điều khiển chương trình của mình hay thông qua IB không? Nếu trước đây, bạn có thể đăng mã đó không? – zpasternack
Tôi cũng bị mắc kẹt. Bất cứ ai cũng có một hướng dẫn tốt để thực hiện các điều khiển tùy chỉnh thông qua subclassing UIControl? – bentford
Được xếp thứ ba. Tôi tạo ra một UIControl mà chỉ hoạt động tốt nếu tôi nhanh chóng nó trong phương pháp loadView của bộ điều khiển (nib-ít phong cách). Nhưng nếu tôi khởi tạo một từ một nib, chạm của nóBegan: withEvent: gia đình của các phương pháp vẫn được gọi, nhưng beginTrackingWithTouch: withEvent: những người không bao giờ làm. Baffling. – rgeorge