2017-02-11 15 views
0

В моем приложении у меня есть UIButton, что довольно мало, поэтому я подумал об увеличении его области поражения.Как я могу расширить область хитов определенного UIButton в Swift?

Я нашел расширение для этого:

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 
    } 
} 

, но когда я использую его, каждая кнопка в мое приложение имеет больший удар области. Я хочу увеличить его до одного только specialButton - как я могу это сделать?

+0

Альтернативой ответу @ ronatory является (1) подкласс UIButton как, скажем, 'SpecialButton', а затем расширять его вместо UIButton. – dfd

+0

Обратите внимание, что переопределение функций из расширения является плохой идеей и не допускается в «чистом» быстром, только в классах Objective-C NSObject. Чтобы процитировать Apple Swift iBook: «Расширения могут добавлять новые функции к типу, но они не могут переопределять существующие функции» Выдержка из: Apple Inc. «Язык Swift Programming (Swift 3.0.1)». IBooks. https://itun.es/us/jEUH0.l –

+0

Обновлен мой ответ. Но, к сожалению, метод работает не так, как ожидалось. Я думаю, что вы должны попробовать ответить матом. Http://stackoverflow.com/a/42182054/5327882 – ronatory

ответ

0

Вы можете добавить computed property на ваш добавочный номер, который вы можете установить в контроллере, если вы хотите включить в хит область, как это:

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 
    } 
} 

, а затем в контроллере представления просто установите isIncreasedHitAreaEnabled в true если вы хотят, чтобы увеличить его для определенной кнопки (например, в вашем viewDidLoad):

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

Обновление:

Прежде всего метод, который вы используете, не работает, как ожидалось. А также мой подход с computed property не работал, как я думал. Поэтому, даже если метод не работает, как ожидалось, я просто хочу обновить свой подход с помощью computed property. Чтобы установить свойство снаружи, вы можете использовать Associated Objects. Также посмотрите here. С помощью этого решения в настоящее время можно было бы обрабатывать Bool свойство isIncreasedHitAreaEnabled от контроллера:

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

, так что позвольте мне получить это право - если я не установил флаг 'isincreasedHitAreaEnabled', то он по умолчанию будет false? Я имею в виду - мне не нужно устанавливать его на false на каждой другой кнопке в моем приложении, верно? – user3766930

+0

точно, добавил комментарии коментария, чтобы сделать его более понятным – ronatory

+0

hmm, @ronatory, я думаю, что этот код повлиял на все кнопки в моем приложении, хотя я установил 'isIncreased ...' только на одном из них ... Более того, даже если я изменяю 'minimumHitArea' на' width: 10, height: 10', кажется, что область хитов охватывает весь вид - знаете ли вы, что здесь может быть неправильно? – user3766930

0

Не расширять хит области; сжимайте область рисования. Сделать кнопку подкласс UIButton, и в этом подклассе реализовать rect методы, вдоль этих линий:

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) 
    } 
} 

Теперь кнопка tappable 30 очков за пределами ее видимого фона.

enter image description here

+0

В настоящее время моя кнопка имеет ограничения, установленные следующим образом: http://imgur.com/a/T3p8x, если я хочу расширить зону касания, например. 5 с каждой стороны, как мне это сделать? Должен ли я изменять ширину 'width' и' height' в ограничениях (добавляя по 5 к каждому из них), а затем как я могу изменить 'contentEdgeInsets'? – user3766930

+0

Извините, мой первый ответ не сработал, но мой второй ответ. – matt

+0

hmm @matt, я пробовал ваш подход, ставил этот класс в качестве выходного соединения, а также настраивал его в раскадровке для моей кнопки, но это не сработало - в настоящее время изображение с моей кнопки исчезло ... сама кнопка клик можно использовать, но область не увеличивается на 30px больше с каждой стороны :( – user3766930

0

Создание пользовательского класса UIButton и переопределить pointInside: (CGPoint) метод точки, как показано ниже. Затем установите значение этих свойств из viewController.

#import <UIKit/UIKit.h> 
@interface CustomButton : UIButton 
    @property (nonatomic) CGFloat leftArea; 
    @property (nonatomic) CGFloat rightArea; 
@property (nonatomic) CGFloat topArea; 
@property (nonatomic) CGFloat bottomArea; 
@end 




#import "CustomButton.h 
@implementation CustomButton 

-(BOOL) pointInside:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    CGRect newArea = CGRectMake(self.bounds.origin.x - _leftArea, self.bounds.origin.y - _topArea, self.bounds.size.width + _leftArea + _rightArea, self.bounds.size.height + _bottomArea + _topArea); 

    return CGRectContainsPoint(newArea, point); 
} 
@end