2017-02-11 2 views
0

In meiner Anwendung habe ich eine UIButton, die ziemlich klein ist, also dachte ich über die Erhöhung der Trefferfläche davon.Wie kann ich den Trefferbereich eines bestimmten UIButton in Swift erweitern?

fand ich eine Erweiterung für das:

fileprivate let minimumHitArea = CGSize(width: 100, height: 100) 

extension UIButton { 
    open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { 
     // if the button is hidden/disabled/transparent it can't be hit 
     if self.isHidden || !self.isUserInteractionEnabled || self.alpha < 0.01 { return nil } 

     // increase the hit frame to be at least as big as `minimumHitArea` 
     let buttonSize = self.bounds.size 
     let widthToAdd = max(minimumHitArea.width - buttonSize.width, 0) 
     let heightToAdd = max(minimumHitArea.height - buttonSize.height, 0) 
     let largerFrame = self.bounds.insetBy(dx: -widthToAdd/2, dy: -heightToAdd/2) 

     // perform hit test on larger frame 
     return (largerFrame.contains(point)) ? self : nil 
    } 
} 

aber wenn ich es verwenden, hat jede Taste in meiner app eine größere Trefferfläche. Ich möchte es auf nur eine specialButton erhöhen - wie kann ich es tun?

+0

Eine Alternative zu @ ronatory's Antwort ist (1) Unterklasse UIButton als, sagen wir, 'SpecialButton', und dann erweitern, dass anstelle von UIButton. – dfd

+0

Beachten Sie, dass das Überschreiben von Funktionen aus einer Erweiterung eine schlechte Idee ist und nicht in "pure" swift, nur in Objective-C NSObject-Klassen zulässig ist. Um das Apple Swift iBook zu zitieren: "Erweiterungen können einem Typ neue Funktionen hinzufügen, aber sie können vorhandene Funktionalität nicht überschreiben." Auszug aus: Apple Inc. "Die Swift-Programmiersprache (Swift 3.0.1)." IBooks. https://itun.es/us/jEUH0.l –

+0

Aktualisierte meine Antwort. Aber leider funktioniert die Methode nicht wie erwartet. Ich denke, dass Sie die Antwort von matt versuchen sollten http://stackoverflow.com/a/42182054/5327882 – ronatory

Antwort

0

Sie können eine computed property zu Ihrer Erweiterung hinzufügen, die Sie in Ihrem Controller einstellen können, wenn Sie die Hit-Bereich wie folgt aktivieren möchten:

fileprivate let minimumHitArea = CGSize(width: 100, height: 100) 

extension UIButton { 

    var isIncreasedHitAreaEnabled: Bool { 
    get { 
     // default value is false, so you can easily handle from outside when to enable the increased hit area of your specific button 
     return false 
    } 
    set { 

    } 
    } 

    open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { 
    // if the button is hidden/disabled/transparent it can't be hit 
    if self.isHidden || !self.isUserInteractionEnabled || self.alpha < 0.01 { return nil } 

    // only if it's true the hit area can be increased 
    if isIncreasedHitAreaEnabled { 
     // increase the hit frame to be at least as big as `minimumHitArea` 
     let buttonSize = self.bounds.size 
     let widthToAdd = max(minimumHitArea.width - buttonSize.width, 0) 
     let heightToAdd = max(minimumHitArea.height - buttonSize.height, 0) 
     let largerFrame = self.bounds.insetBy(dx: -widthToAdd/2, dy: -heightToAdd/2) 

     // perform hit test on larger frame 
     return (largerFrame.contains(point)) ? self : nil 
    } 
    return self 
    } 
} 

Und dann in Ihrem View-Controller setzen nur isIncreasedHitAreaEnabled zu true, wenn Sie wollen sie für eine bestimmte Taste erhöhen (zB in Ihrem viewDidLoad):

override func viewDidLoad() { 
    super.viewDidLoad() 
    specialButton.isIncreasedHitAreaEnabled = true 
} 

Update:

Zunächst funktioniert die Methode, die Sie verwenden, nicht wie erwartet. Und auch mein Ansatz mit der computed property funktionierte nicht so, wie ich dachte. Auch wenn die Methode nicht wie erwartet funktioniert, möchte ich nur meinen Ansatz mit der computed property aktualisieren. Um die Eigenschaft von außerhalb festzulegen, können Sie Associated Objects verwenden. Schauen Sie auch here. Mit dieser Lösung jetzt wäre es möglich, die Bool Eigenschaft isIncreasedHitAreaEnabled von dem Controller zu handhaben:

fileprivate let minimumHitArea = CGSize(width: 100, height: 100) 
private var xoAssociationKey: UInt8 = 0 

extension UIButton { 

    var isIncreasedHitAreaEnabled: Bool { 
    get { 
     return (objc_getAssociatedObject(self, &xoAssociationKey) != nil) 
    } 
    set(newValue) { 
     objc_setAssociatedObject(self, &xoAssociationKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) 
    } 
    } 

    open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { 
    // if the button is hidden/disabled/transparent it can't be hit 
    if self.isHidden || !self.isUserInteractionEnabled || self.alpha < 0.01 { return nil } 

    if isIncreasedHitAreaEnabled { 
     // increase the hit frame to be at least as big as `minimumHitArea` 
     let buttonSize = self.bounds.size 
     let widthToAdd = max(minimumHitArea.width - buttonSize.width, 0) 
     let heightToAdd = max(minimumHitArea.height - buttonSize.height, 0) 
     let largerFrame = self.bounds.insetBy(dx: -widthToAdd/2, dy: -heightToAdd/2) 

     // perform hit test on larger frame 
     return (largerFrame.contains(point)) ? self : nil 
    } 
    return self 
    } 
} 
+0

so lassen Sie mich das richtig machen - wenn ich nicht die Flagge setzen "isincreasedHitAreaEnabled", dann wird es standardmäßig falsch sein? Ich meine - ich muss es nicht auf jeder anderen Taste in meiner App auf false setzen, oder? – user3766930

+0

genau, Code-Kommentare hinzugefügt, um es klarer zu machen – ronatory

+0

hmm, @ronatory, ich denke, dass dieser Code alle Schaltflächen in meiner App betroffen, obwohl ich 'isIncreased ...' nur auf einer von ihnen gesetzt ... Was ist mehr? selbst wenn ich den 'minimumHitArea' in' width: 10, height: 10' ändere, scheint es so, als ob der Trefferbereich die gesamte Ansicht abdeckt - weißt du, was hier falsch sein könnte? – user3766930

0

Sie den Hit-Bereich nicht erweitern; verkleinere den Zeichenbereich. Machen Sie die Taste, um eine Unterklasse von UIButton, und in dieser Unterklasse, implementieren rect Methoden, entlang dieser Linien:

class MyButton : UIButton { 
    override func contentRect(forBounds bounds: CGRect) -> CGRect { 
     return bounds.insetBy(dx: 30, dy: 30) 
    } 
    override func backgroundRect(forBounds bounds: CGRect) -> CGRect { 
     return bounds.insetBy(dx: 30, dy: 30) 
    } 
} 

Nun ist die Taste 30 Punkte außerhalb des sichtbaren Hintergrund abgreifbar ist.

enter image description here

+0

Derzeit hat meine Schaltfläche Bedingungen wie folgt festgelegt: http://imgur.com/a/T3p8x, wenn ich den Touch-Bereich für z. 5 von jeder Seite, wie soll ich es tun? Muss ich die "width" und "height" in den Constraints ändern (indem ich ihnen jeweils 5 hinzufüge) und wie kann ich dann die "contentEdgeInsets" ändern? – user3766930

+0

Tut mir leid, meine erste Antwort hat nicht funktioniert, aber meine zweite Antwort tut es. – matt

+0

hmm @matt, ich habe versucht, diese Klasse als Outlet-Verbindung zu verwenden und sie auch im Storyboard für meine Schaltfläche einzurichten, aber es funktioniert nicht gut - derzeit ist das Bild von meiner Schaltfläche verschwunden ... die Schaltfläche selbst ist anklickbar, aber der Bereich ist nicht sicher für 30px mehr auf jeder Seite erweitert :( – user3766930

0

eine benutzerdefinierte UIButton Klasse erstellen und pointInside außer Kraft setzen: (CGPoint) Punkt-Methode wie unten. Setzen Sie dann diesen Eigenschaftenwert von viewController.

Verwandte Themen