titlelabel que color buttons ios cocoa-touch uibutton uikit

ios - color - UIButton: hacer que el área de golpe sea más grande que el área de golpe predeterminada



uikit ios (30)

Acabo de hacer el puerto de la solution @Chase en veloz 2.2

import Foundation import ObjectiveC private var hitTestEdgeInsetsKey: UIEdgeInsets = UIEdgeInsetsZero extension UIButton { var hitTestEdgeInsets:UIEdgeInsets { get { let inset = objc_getAssociatedObject(self, &hitTestEdgeInsetsKey) as? NSValue ?? NSValue(UIEdgeInsets: UIEdgeInsetsZero) return inset.UIEdgeInsetsValue() } set { let inset = NSValue(UIEdgeInsets: newValue) objc_setAssociatedObject(self, &hitTestEdgeInsetsKey, inset, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } public override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool { guard !UIEdgeInsetsEqualToEdgeInsets(hitTestEdgeInsets, UIEdgeInsetsZero) && self.enabled == true && self.hidden == false else { return super.pointInside(point, withEvent: event) } let relativeFrame = self.bounds let hitFrame = UIEdgeInsetsInsetRect(relativeFrame, hitTestEdgeInsets) return CGRectContainsPoint(hitFrame, point) } }

una puede usar de esta manera

button.hitTestEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10)

Para cualquier otra referencia, consulte solution

Tengo una pregunta relacionada con UIButton y su área de aciertos. Estoy usando el botón de Información oscura en el constructor de interfaz, pero estoy descubriendo que el área de impacto no es lo suficientemente grande para los dedos de algunas personas.

¿Hay alguna manera de aumentar el área de aciertos de un botón, ya sea programáticamente o en Interface Builder sin cambiar el tamaño del gráfico InfoButton?


Aquí están las Extensiones UIButton + de Chase en Swift 3.0.

import UIKit private var pTouchAreaEdgeInsets: UIEdgeInsets = .zero extension UIButton { var touchAreaEdgeInsets: UIEdgeInsets { get { if let value = objc_getAssociatedObject(self, &pTouchAreaEdgeInsets) as? NSValue { var edgeInsets: UIEdgeInsets = .zero value.getValue(&edgeInsets) return edgeInsets } else { return .zero } } set(newValue) { var newValueCopy = newValue let objCType = NSValue(uiEdgeInsets: .zero).objCType let value = NSValue(&newValueCopy, withObjCType: objCType) objc_setAssociatedObject(self, &pTouchAreaEdgeInsets, value, .OBJC_ASSOCIATION_RETAIN) } } open override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { if UIEdgeInsetsEqualToEdgeInsets(self.touchAreaEdgeInsets, .zero) || !self.isEnabled || self.isHidden { return super.point(inside: point, with: event) } let relativeFrame = self.bounds let hitFrame = UIEdgeInsetsInsetRect(relativeFrame, self.touchAreaEdgeInsets) return hitFrame.contains(point) } }

Para usarlo, puedes:

button.touchAreaEdgeInsets = UIEdgeInsets(top: -10, left: -10, bottom: -10, right: -10)


Aquí hay una solución elegante que usa Extensions en Swift. Le da a todos los UIButtons un área de éxito de al menos 44x44 puntos, según las pautas de interfaz humana de Apple ( https://developer.apple.com/ios/human-interface-guidelines/visual-design/layout/ )

Swift 2:

private let minimumHitArea = CGSizeMake(44, 44) extension UIButton { public override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? { // if the button is hidden/disabled/transparent it can''t be hit if self.hidden || !self.userInteractionEnabled || 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 = CGRectInset(self.bounds, -widthToAdd / 2, -heightToAdd / 2) // perform hit test on larger frame return (CGRectContainsPoint(largerFrame, point)) ? self : nil } }

Swift 3:

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


Bueno, puedes colocar tu UIButton dentro de una UIView transparente y ligeramente más grande, y luego capturar los eventos táctiles en la instancia de UIView como en el UIButton. De esa manera, todavía tendrá su botón, pero con un área táctil más grande. Deberá lidiar manualmente con estados seleccionados y resaltados con el botón si el usuario toca la vista en lugar del botón.

Otra posibilidad implica usar un UIImage en lugar de un UIButton.


Como uso una imagen de fondo, ninguna de estas soluciones funcionó bien para mí. Aquí hay una solución que hace un poco de magia objetiva c y ofrece una solución con un código mínimo.

Primero, agregue una categoría a UIButton que anule la prueba de aciertos y también agrega una propiedad para expandir el marco de prueba de aciertos.

UIButton + Extensions.h

@interface UIButton (Extensions) @property(nonatomic, assign) UIEdgeInsets hitTestEdgeInsets; @end

UIButton + Extensions.m

#import "UIButton+Extensions.h" #import <objc/runtime.h> @implementation UIButton (Extensions) @dynamic hitTestEdgeInsets; static const NSString *KEY_HIT_TEST_EDGE_INSETS = @"HitTestEdgeInsets"; -(void)setHitTestEdgeInsets:(UIEdgeInsets)hitTestEdgeInsets { NSValue *value = [NSValue value:&hitTestEdgeInsets withObjCType:@encode(UIEdgeInsets)]; objc_setAssociatedObject(self, &KEY_HIT_TEST_EDGE_INSETS, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -(UIEdgeInsets)hitTestEdgeInsets { NSValue *value = objc_getAssociatedObject(self, &KEY_HIT_TEST_EDGE_INSETS); if(value) { UIEdgeInsets edgeInsets; [value getValue:&edgeInsets]; return edgeInsets; }else { return UIEdgeInsetsZero; } } - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { if(UIEdgeInsetsEqualToEdgeInsets(self.hitTestEdgeInsets, UIEdgeInsetsZero) || !self.enabled || self.hidden) { return [super pointInside:point withEvent:event]; } CGRect relativeFrame = self.bounds; CGRect hitFrame = UIEdgeInsetsInsetRect(relativeFrame, self.hitTestEdgeInsets); return CGRectContainsPoint(hitFrame, point); } @end

Una vez que se agrega esta clase, todo lo que necesita hacer es establecer las inserciones de borde de su botón. Tenga en cuenta que elegí agregar las inserciones, por lo que si desea aumentar el área de aciertos, debe usar números negativos.

[button setHitTestEdgeInsets:UIEdgeInsetsMake(-10, -10, -10, -10)];

Nota: Recuerde importar la categoría ( #import "UIButton+Extensions.h" ) en sus clases.


En base a la respuesta de giaset anterior (que encontré la solución más elegante), aquí está la versión rápida 3:

import UIKit fileprivate let minimumHitArea = CGSize(width: 44, height: 44) 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 isHidden || !isUserInteractionEnabled || alpha < 0.01 { return nil } // increase the hit frame to be at least as big as `minimumHitArea` let buttonSize = bounds.size let widthToAdd = max(minimumHitArea.width - buttonSize.width, 0) let heightToAdd = max(minimumHitArea.height - buttonSize.height, 0) let largerFrame = bounds.insetBy(dx: -widthToAdd / 2, dy: -heightToAdd / 2) // perform hit test on larger frame return (largerFrame.contains(point)) ? self : nil } }


Esta es mi solución Swift 3 (basada en esta entrada de blog: http://bdunagan.com/2010/03/01/iphone-tip-larger-hit-area-for-uibutton/ )

class ExtendedHitAreaButton: UIButton { @IBInspectable var hitAreaExtensionSize: CGSize = CGSize(width: -10, height: -10) override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { let extendedFrame: CGRect = bounds.insetBy(dx: hitAreaExtensionSize.width, dy: hitAreaExtensionSize.height) return extendedFrame.contains(point) ? self : nil } }


Esta versión de Swift te permite definir un tamaño de hit mínimo para todos los UIButtons. Fundamentalmente, también maneja el caso cuando los UIButtons están ocultos, lo que muchas respuestas descuidan.

extension UIButton { public override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? { // Ignore if button hidden if self.hidden { return nil } // If here, button visible so expand hit area let hitSize = CGFloat(56.0) let buttonSize = self.frame.size let widthToAdd = (hitSize - buttonSize.width > 0) ? hitSize - buttonSize.width : 0 let heightToAdd = (hitSize - buttonSize.height > 0) ? hitSize - buttonSize.height : 0 let largerFrame = CGRect(x: 0-(widthToAdd/2), y: 0-(heightToAdd/2), width: buttonSize.width+widthToAdd, height: buttonSize.height+heightToAdd) return (CGRectContainsPoint(largerFrame, point)) ? self : nil } }


Esto funciona para mí:

UIButton *button = [UIButton buttonWithType: UIButtonTypeCustom]; // set the image (here with a size of 32 x 32) [button setImage: [UIImage imageNamed: @"myimage.png"] forState: UIControlStateNormal]; // just set the frame of the button (here 64 x 64) [button setFrame: CGRectMake(xPositionOfMyButton, yPositionOfMyButton, 64, 64)];


Estoy usando la siguiente clase en Swift, para habilitar también una propiedad de Interface Builder para ajustar el margen:

@IBDesignable class ALExtendedButton: UIButton { @IBInspectable var touchMargin:CGFloat = 20.0 override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool { var extendedArea = CGRectInset(self.bounds, -touchMargin, -touchMargin) return CGRectContainsPoint(extendedArea, point) } }


Estoy usando un enfoque más genérico al swizzling -[UIView pointInside:withEvent:] . Esto me permite modificar el comportamiento de prueba de golpe en cualquier UIView , no solo en UIButton .

A menudo, se coloca un botón dentro de una vista de contenedor que también limita la prueba de impacto. Por ejemplo, cuando un botón está en la parte superior de una vista de contenedor y desea extender el objetivo táctil hacia arriba, también debe extender el objetivo táctil de la vista de contenedor.

@interface UIView(Additions) @property(nonatomic) UIEdgeInsets hitTestEdgeInsets; @end @implementation UIView(Additions) + (void)load { Swizzle(self, @selector(pointInside:withEvent:), @selector(myPointInside:withEvent:)); } - (BOOL)myPointInside:(CGPoint)point withEvent:(UIEvent *)event { if(UIEdgeInsetsEqualToEdgeInsets(self.hitTestEdgeInsets, UIEdgeInsetsZero) || self.hidden || ([self isKindOfClass:UIControl.class] && !((UIControl*)self).enabled)) { return [self myPointInside:point withEvent:event]; // original implementation } CGRect hitFrame = UIEdgeInsetsInsetRect(self.bounds, self.hitTestEdgeInsets); hitFrame.size.width = MAX(hitFrame.size.width, 0); // don''t allow negative sizes hitFrame.size.height = MAX(hitFrame.size.height, 0); return CGRectContainsPoint(hitFrame, point); } static char hitTestEdgeInsetsKey; - (void)setHitTestEdgeInsets:(UIEdgeInsets)hitTestEdgeInsets { objc_setAssociatedObject(self, &hitTestEdgeInsetsKey, [NSValue valueWithUIEdgeInsets:hitTestEdgeInsets], OBJC_ASSOCIATION_RETAIN); } - (UIEdgeInsets)hitTestEdgeInsets { return [objc_getAssociatedObject(self, &hitTestEdgeInsetsKey) UIEdgeInsetsValue]; } void Swizzle(Class c, SEL orig, SEL new) { Method origMethod = class_getInstanceMethod(c, orig); Method newMethod = class_getInstanceMethod(c, new); if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); else method_exchangeImplementations(origMethod, newMethod); } @end

Lo bueno de este enfoque es que puede usarlo incluso en Storyboards agregando un atributo de tiempo de ejecución definido por el usuario. Lamentablemente, UIEdgeInsets no está directamente disponible como un tipo allí, pero dado que CGRect también consiste en una estructura con cuatro CGFloat , funciona perfectamente eligiendo "Rect" y completando los valores de esta manera: {{top, left}, {bottom, right}} .


He seguido la respuesta de Chase y funciona genial, un solo problema cuando creas el arrea demasiado grande, más grande que la zona donde el botón se deselecciona (si la zona no era más grande) no llama al selector para el evento UIControlEventTouchUpInside .

Creo que el tamaño es más de 200 en cualquier dirección o algo así.


Hice una library para este propósito.

Puede optar por utilizar una categoría UIView , sin necesidad de subclases :

@interface UIView (KGHitTesting) - (void)setMinimumHitTestWidth:(CGFloat)width height:(CGFloat)height; @end

O puede subclasificar su UIView o UIButton y establecer el minimumHitTestWidth y / o minimumHitTestHeight . El área de prueba de golpe de tu botón se representará con estos 2 valores.

Al igual que otras soluciones, utiliza el método de - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event . El método se llama cuando iOS realiza pruebas de aciertos. This publicación de blog tiene una buena descripción de cómo funciona la prueba de éxito de iOS.

library

@interface KGHitTestingButton : UIButton <KGHitTesting> @property (nonatomic) CGFloat minimumHitTestHeight; @property (nonatomic) CGFloat minimumHitTestWidth; @end

También puede simplemente crear una subclase y usar el Interface Builder sin escribir ningún código:


Implementación al anular el UIButton heredado.

Swift 2.2 :

// don''t forget that negative values are for outset _button.hitOffset = UIEdgeInsets(top: -10, left: -10, bottom: -10, right: -10) ... class UICustomButton: UIButton { var hitOffset = UIEdgeInsets() override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool { guard hitOffset != UIEdgeInsetsZero && enabled && !hidden else { return super.pointInside(point, withEvent: event) } return UIEdgeInsetsInsetRect(bounds, hitOffset).contains(point) } }


La respuesta de @jlajlar arriba parecía buena y directa, pero no coincide con Xamarin.iOS, así que la convertí en Xamarin. Si buscas una solución en un Xamarin iOS, aquí va:

public override bool PointInside (CoreGraphics.CGPoint point, UIEvent uievent) { var margin = -10f; var area = this.Bounds; var expandedArea = area.Inset(margin, margin); return expandedArea.Contains(point); }

Puede agregar este método a la clase en la que está anulando UIView o UIImageView. Esto funcionó bien :)


Llego tan tarde a este juego, pero quería analizar una técnica simple que podría resolver tus problemas. Aquí hay un fragmento de UIButton programático típico para mí:

UIImage *arrowImage = [UIImage imageNamed:@"leftarrow"]; arrowButton = [[UIButton alloc] initWithFrame:CGRectMake(15.0, self.frame.size.height-35.0, arrowImage.size.width/2, arrowImage.size.height/2)]; [arrowButton setBackgroundImage:arrowImage forState:UIControlStateNormal]; [arrowButton addTarget:self action:@selector(onTouchUp:) forControlEvents:UIControlEventTouchUpOutside]; [arrowButton addTarget:self action:@selector(onTouchDown:) forControlEvents:UIControlEventTouchDown]; [arrowButton addTarget:self action:@selector(onTap:) forControlEvents:UIControlEventTouchUpInside]; [arrowButton addTarget:self action:@selector(onTouchUp:) forControlEvents:UIControlEventTouchDragExit]; [arrowButton setUserInteractionEnabled:TRUE]; [arrowButton setAdjustsImageWhenHighlighted:NO]; [arrowButton setTag:1]; [self addSubview:arrowButton];

Estoy cargando una imagen png transparente para mi botón y configurando la imagen de fondo. Estoy configurando el marco basado en el UIImage y la escala en un 50% para la retina. OK, tal vez usted está de acuerdo con lo anterior o no, PERO si desea hacer que el área de aciertos sea MÁS GRANDE y ahórrese un dolor de cabeza:

Lo que hago, abra la imagen en photoshop y simplemente aumente el tamaño del lienzo al 120% y guárdelo. De hecho, acabas de agrandar la imagen con píxeles transparentes.

Solo un enfoque.


Mi solución en Swift 3:

class MyButton: UIButton { override open func point(inside point: CGPoint, with event: UIEvent?) -> Bool { let relativeFrame = self.bounds let hitTestEdgeInsets = UIEdgeInsetsMake(-25, -25, -25, -25) let hitFrame = UIEdgeInsetsInsetRect(relativeFrame, hitTestEdgeInsets) return hitFrame.contains(point) } }


Ninguna de las respuestas funciona para mí, porque uso una imagen de fondo y un título en ese botón. Además, el botón cambiará de tamaño a medida que cambie el tamaño de la pantalla.

En cambio, agrando el área del grifo haciendo que el área transparente del png sea más grande.


No establezca la propiedad backgroundImage con su imagen, configure la propiedad imageView . Además, asegúrese de tener imageView.contentMode configurado en UIViewContentModeCenter .


No hay nada malo con las respuestas presentadas; sin embargo, quería extender la respuesta de jlarjlar ya que contiene un potencial increíble que puede agregar valor al mismo problema con otros controles (por ejemplo, SearchBar). Esto se debe a que pointInside está conectado a un UIView, uno puede subclasificar cualquier control para mejorar el área táctil. Esta respuesta también muestra una muestra completa de cómo implementar la solución completa.

Crea una nueva subclase para tu botón (o cualquier control)

#import <UIKit/UIKit.h> @interface MNGButton : UIButton @end

A continuación, anule el método pointInside en la implementación de su subclase

@implementation MNGButton -(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { //increase touch area for control in all directions by 20 CGFloat margin = 20.0; CGRect area = CGRectInset(self.bounds, -margin, -margin); return CGRectContainsPoint(area, point); } @end

En su archivo storyboard / xib seleccione el control en cuestión y abra el inspector de identidad y escriba el nombre de su clase personalizada.

En su clase UIViewController para la escena que contiene el botón, cambie el tipo de clase para el botón al nombre de su subclase.

@property (weak, nonatomic) IBOutlet MNGButton *helpButton;

Vincule su storyboard / botón xib a la propiedad IBOutlet y su área táctil se expandirá para ajustarse al área definida en la subclase.

Además de anular el método pointInside junto con los métodos CGRectInset y CGRectContainsPoint , se debe tomar un tiempo para examinar el CGGeometry para ampliar el área táctil rectangular de cualquier subclase UIView. También puede encontrar algunos buenos consejos sobre los casos de uso de NSHipster en NSHipster .

Por ejemplo, uno puede hacer que el área táctil sea irregular usando los métodos mencionados anteriormente o simplemente elegir que el área táctil del ancho sea dos veces más grande que el área táctil horizontal:

CGRect area = CGRectInset(self.bounds, -(2*margin), -margin);

NB: Sustituir cualquier control de Clase UI debería producir resultados similares al extender el área táctil para diferentes controles (o cualquier subclase UIView, como UIImageView, etc.).


No modifique el comportamiento de UIButton.

@interface ExtendedHitButton: UIButton + (instancetype) extendedHitButton; - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event; @end @implementation ExtendedHitButton + (instancetype) extendedHitButton { return (ExtendedHitButton *) [ExtendedHitButton buttonWithType:UIButtonTypeCustom]; } - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { CGRect relativeFrame = self.bounds; UIEdgeInsets hitTestEdgeInsets = UIEdgeInsetsMake(-44, -44, -44, -44); CGRect hitFrame = UIEdgeInsetsInsetRect(relativeFrame, hitTestEdgeInsets); return CGRectContainsPoint(hitFrame, point); } @end


Nunca anule el método en la categoría. Botón de subclase y anulación - pointInside:withEvent: Por ejemplo, si el lado de su botón es más pequeño que 44 px (que se recomienda como área mínima para tocar), use esto:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { return (ABS(point.x - CGRectGetMidX(self.bounds)) <= MAX(CGRectGetMidX(self.bounds), 22)) && (ABS(point.y - CGRectGetMidY(self.bounds)) <= MAX(CGRectGetMidY(self.bounds), 22)); }


Prueba personalizada de Chase implementada como una subclase de UIButton. Escrito en Objective-C.

Parece funcionar tanto para init como para buttonWithType: constructores. Para mis necesidades, es perfecto, pero como la subclase de UIButton puede ser peluda, me interesaría saber si alguien tiene un fallo al respecto.

CustomeHitAreaButton.h

#import <UIKit/UIKit.h> @interface CustomHitAreaButton : UIButton - (void)setHitTestEdgeInsets:(UIEdgeInsets)hitTestEdgeInsets; @end

CustomHitAreaButton.m

#import "CustomHitAreaButton.h" @interface CustomHitAreaButton() @property (nonatomic, assign) UIEdgeInsets hitTestEdgeInsets; @end @implementation CustomHitAreaButton - (instancetype)initWithFrame:(CGRect)frame { if(self = [super initWithFrame:frame]) { self.hitTestEdgeInsets = UIEdgeInsetsZero; } return self; } -(void)setHitTestEdgeInsets:(UIEdgeInsets)hitTestEdgeInsets { self->_hitTestEdgeInsets = hitTestEdgeInsets; } - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { if(UIEdgeInsetsEqualToEdgeInsets(self.hitTestEdgeInsets, UIEdgeInsetsZero) || !self.enabled || self.hidden) { return [super pointInside:point withEvent:event]; } CGRect relativeFrame = self.bounds; CGRect hitFrame = UIEdgeInsetsInsetRect(relativeFrame, self.hitTestEdgeInsets); return CGRectContainsPoint(hitFrame, point); } @end


Pude aumentar el área de impacto del botón de información mediante programación. El gráfico "i" no cambia de escala y permanece centrado en el nuevo marco de botón.

El tamaño del botón de información parece estar fijado a 18x19 [*] en Interface Builder. Al conectarlo a un IBOutlet, pude cambiar el tamaño de cuadro en el código sin ningún problema.

static void _resizeButton( UIButton *button ) { const CGRect oldFrame = infoButton.frame; const CGFloat desiredWidth = 44.f; const CGFloat margin = ( desiredWidth - CGRectGetWidth( oldFrame ) ) / 2.f; infoButton.frame = CGRectInset( oldFrame, -margin, -margin ); }

[*]: Versiones posteriores de iOS parecen haber aumentado el área de impacto del botón de información.


Rápido:

override func viewWillAppear(animated: Bool) { self.sampleButton.frame = CGRectInset(self.sampleButton.frame, -10, -10); }


Recomiendo colocar un UIButton con tipo personalizado centrado sobre su botón de información. Cambie el tamaño del botón personalizado al tamaño que desea que sea el área afectada. Desde allí tienes dos opciones:

  1. Marque la opción ''Mostrar toque en resaltado'' del botón personalizado. El brillo blanco aparecerá sobre el botón de información, pero en la mayoría de los casos el dedo del usuario lo cubrirá y todo lo que verán será el brillo alrededor del exterior.

  2. Configure un IBOutlet para el botón de información y dos IBActions para el botón personalizado uno para ''Touch Down'' y otro para ''Touch Up Inside''. Luego, en Xcode, el evento de toma de contacto establece la propiedad resaltada del botón de información en SÍ y el evento touchupinside establece la propiedad resaltada en NO.


Simplemente configure los valores de inserción del borde de la imagen en el constructor de interfaz.


También podría subclase UIButton o un UIView personalizado y un point(inside:with:) anulación point(inside:with:) con algo como:

Swift 3

override func point(inside point: CGPoint, with _: UIEvent?) -> Bool { let margin: CGFloat = 5 let area = self.bounds.insetBy(dx: -margin, dy: -margin) return area.contains(point) }

C objetivo

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { CGFloat margin = 5.0; CGRect area = CGRectInset(self.bounds, -margin, -margin); return CGRectContainsPoint(area, point); }


Usaré este truco para el botón dentro de tableviewcell.accessoryView para ampliar su área táctil

#pragma mark - Touches - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint location = [touch locationInView:self]; CGRect accessoryViewTouchRect = CGRectInset(self.accessoryView.frame, -15, -15); if(!CGRectContainsPoint(accessoryViewTouchRect, location)) [super touchesBegan:touches withEvent:event]; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint location = [touch locationInView:self]; CGRect accessoryViewTouchRect = CGRectInset(self.accessoryView.frame, -15, -15); if(CGRectContainsPoint(accessoryViewTouchRect, location) && [self.accessoryView isKindOfClass:[UIButton class]]) { [(UIButton *)self.accessoryView sendActionsForControlEvents:UIControlEventTouchUpInside]; } else [super touchesEnded:touches withEvent:event]; }


WJBackgroundInsetButton.h

#import <UIKit/UIKit.h> @interface WJBackgroundInsetButton : UIButton { UIEdgeInsets backgroundEdgeInsets_; } @property (nonatomic) UIEdgeInsets backgroundEdgeInsets; @end

WJBackgroundInsetButton.m

#import "WJBackgroundInsetButton.h" @implementation WJBackgroundInsetButton @synthesize backgroundEdgeInsets = backgroundEdgeInsets_; -(CGRect) backgroundRectForBounds:(CGRect)bounds { CGRect sup = [super backgroundRectForBounds:bounds]; UIEdgeInsets insets = self.backgroundEdgeInsets; CGRect r = UIEdgeInsetsInsetRect(sup, insets); return r; } @end