UIButton:적중 영역을 기본 적중 영역보다 크게 만들기
UIButton과 히트 지역에 대한 질문이 있습니다.인터페이스 작성기에서 Info Dark 버튼을 사용하고 있지만 일부 사용자가 손가락을 사용할 수 있을 정도로 히트 영역이 크지 않습니다.
InfoButton 그래픽의 크기를 변경하지 않고 프로그래밍 방식으로 또는 Interface Builder에서 버튼의 적중 영역을 늘릴 수 있는 방법이 있습니까?
배경 이미지를 사용하고 있기 때문에 이러한 솔루션 중 어느 것도 제대로 작동하지 않았습니다.여기 재미있는 목적-c 마술을 하고 최소한의 코드로 솔루션을 떨어뜨리는 솔루션이 있습니다.
를 먼범를에추니다에 합니다.UIButton
히트 테스트를 재정의하고 히트 테스트 프레임을 확장하기 위한 속성을 추가합니다.
UIButton+확장자.h
@interface UIButton (Extensions)
@property(nonatomic, assign) UIEdgeInsets hitTestEdgeInsets;
@end
UIButton+확장자.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
이 클래스가 추가되면 단추의 집합에 가장자리를 설정하기만 하면 됩니다.히트 영역을 더 크게 만들려면 음수를 사용해야 합니다.
[button setHitTestEdgeInsets:UIEdgeInsetsMake(-10, -10, -10, -10)];
: 범주참()를 가져오는 것을 마십시오.#import "UIButton+Extensions.h"
에서. 당신의 수업에서.
인터페이스 작성기에서 이미지 가장자리 설정 값을 설정하기만 하면 됩니다.
Swift에서 Extensions를 사용하는 우아한 솔루션이 있습니다.Apple의 휴먼 인터페이스 지침(https://developer.apple.com/ios/human-interface-guidelines/visual-design/layout/) 에 따라 모든 UI 버튼에 최소 44x44 포인트의 적중 영역을 제공합니다.
스위프트 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
}
}
스위프트 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
}
}
서브클래스도 가능합니다.UIButton
지정 는또관UIView
및오라드이버드를 재정의합니다.point(inside:with:)
다음과 같은 것으로:
스위프트 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
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
CGFloat margin = 5.0;
CGRect area = CGRectInset(self.bounds, -margin, -margin);
return CGRectContainsPoint(area, point);
}
Chase의 UIButton+입니다.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)
}
}
사용 방법은 다음을 수행할 수 있습니다.
button.touchAreaEdgeInsets = UIEdgeInsets(top: -10, left: -10, bottom: -10, right: -10)
사용자 지정 유형의 UI 버튼을 정보 버튼 중앙에 배치하는 것이 좋습니다.사용자 지정 버튼의 크기를 히트 영역에 적용할 크기로 조정합니다.여기서 두 가지 옵션을 사용할 수 있습니다.
사용자 지정 버튼의 'Show touch on highlight' 옵션을 선택합니다.정보 버튼 위에 흰색 빛이 나타나지만 대부분의 경우 사용자 손가락이 이 부분을 가리므로 외부의 빛만 볼 수 있습니다.
정보 버튼용 IBO 아울렛과 사용자 지정 버튼용 2개의 IBA 조치를 설정합니다. 하나는 '터치 다운'용이고 다른 하나는 '터치 업 인사이드'용입니다.그런 다음 Xcode에서 터치다운 이벤트가 정보 버튼의 강조 표시된 속성을 YES로 설정하고 터치업 내부 이벤트가 강조 표시된 속성을 NO로 설정하도록 합니다.
을 backgroundImage
이미지로 하세요.imageView
소유물.또한, 당신이 가지고 있는 것을 확인하세요.imageView.contentMode
을 겨냥한.UIViewContentModeCenter
.
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)
}
}
제시된 답변에는 아무런 문제가 없지만, 다른 컨트롤(예: SearchBar)과 동일한 문제에 가치를 더할 수 있는 놀라운 잠재력을 가지고 있기 때문에 jlarjlar의 답변을 확장하고 싶었습니다.그 이유는 그 이후로내부는 UI 뷰에 부착되어 있으며, 터치 영역을 개선하기 위해 모든 컨트롤을 하위 분류할 수 있습니다.이 답변에는 전체 솔루션을 구현하는 방법에 대한 전체 샘플도 나와 있습니다.
단추(또는 모든 컨트롤)에 대한 새 하위 클래스 만들기
#import <UIKit/UIKit.h>
@interface MNGButton : UIButton
@end
다음은 점을 재정의합니다.하위 클래스 구현의 내부 메서드
@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
스토리보드/xib 파일에서 문제의 컨트롤을 선택하고 ID 검사기를 열고 사용자 지정 클래스의 이름을 입력합니다.
버튼이 포함된 장면의 UIViewController 클래스에서 버튼의 클래스 유형을 하위 클래스의 이름으로 변경합니다.
@property (weak, nonatomic) IBOutlet MNGButton *helpButton;
스토리보드/xib 버튼을 속성 IO Butlet에 연결하면 하위 클래스에 정의된 영역에 맞게 터치 영역이 확장됩니다.
점을 무시하는 것 외에도내부 방법은 CGRectInset 및 CGRectContainsPoint 방법과 함께 UIView 하위 클래스의 직사각형 터치 영역을 확장하기 위한 CGeometry를 검토하는 데 시간을 할애해야 합니다.NSHipster에서는 CG 기하학 사용 사례에 대한 몇 가지 유용한 팁도 찾을 수 있습니다.
예를 들어 위에서 언급한 방법을 사용하여 터치 영역을 불규칙하게 만들거나 단순히 폭 터치 영역을 수평 터치 영역보다 두 배 더 크게 만들 수 있습니다.
CGRect area = CGRectInset(self.bounds, -(2*margin), -margin);
NB: UI 클래스 컨트롤을 대체하면 다른 컨트롤(또는 UIImageView 등의 UIView 하위 클래스)에 대한 터치 영역을 확장할 때 유사한 결과를 얻을 수 있습니다.
이것은 나에게 도움이 됩니다.
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)];
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
좀 더 일반적인 접근법을 사용하고 있습니다.-[UIView pointInside:withEvent:]
이를 통해 모든 데이터에 대한 히트 테스트 동작을 수정할 수 있습니다.UIView
,뿐만 아니라.UIButton
.
종종 버튼이 용기 뷰 내에 배치되어 적중 테스트를 제한하기도 합니다.예를 들어 버튼이 컨테이너 뷰의 맨 위에 있고 터치 대상을 위쪽으로 확장하려는 경우 컨테이너 뷰의 터치 대상도 확장해야 합니다.
@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
이 접근 방식의 좋은 점은 사용자 정의 런타임 속성을 추가하여 스토리보드에서도 사용할 수 있다는 것입니다. 슬게프,UIEdgeInsets
유형으로 직접 사용할 수는 없지만 이후CGRect
또한 4개의 구조로 구성됩니다.CGFloat
"Rect"를 선택하고 다음과 같은 값을 입력하면 완벽하게 작동합니다.{{top, left}, {bottom, right}}
.
Swift에서 다음 클래스를 사용하여 Interface Builder 속성을 사용하여 마진을 조정합니다.
@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)
}
}
UIButton을 투명하고 약간 큰 UIView 안에 배치한 다음 UIButton에서처럼 UIView 인스턴스에서 터치 이벤트를 캡처할 수 있습니다.이렇게 하면 버튼은 그대로 유지되지만 터치 영역은 더 넓어집니다.사용자가 버튼 대신 보기를 누르면 버튼에서 선택되고 강조 표시된 상태를 수동으로 처리해야 합니다.
다른 방법으로는 UI 단추 대신 UI 이미지를 사용할 수 있습니다.
프로그램적으로 정보 버튼의 적중 영역을 늘릴 수 있었습니다."i" 그래픽은 축척을 변경하지 않고 새 단추 프레임의 중앙에 유지됩니다.
info 버튼의 크기는 Interface Builder에서 18x19[*]로 고정되어 있는 것 같습니다.IBO 아울렛에 연결하여 코드로 프레임 크기를 문제없이 변경할 수 있었습니다.
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 );
}
[*]: 이후 버전의 iOS에서는 정보 버튼의 적중 영역이 증가한 것으로 보입니다.
이것은 저의 Swift 3 솔루션입니다(이 블로그 게시물에 기반: 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
}
}
솔직히.2023년의 올바른 코드:
class ChubbyButton: UIButton {
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return bounds.insetBy(dx: -20, dy: -20).contains(point)
}
}
이것은 모든 유형의 UIView에서 완벽하게 작동합니다.
class YourEasyToTouchView: UIView {
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return bounds.insetBy(dx: -20, dy: -20).contains(point)
}
}
그게 전부야.
UIButton의 하위 클래스로 구현된 Chase의 맞춤형 적중 테스트입니다.목표-C로 작성됨.
두 가지 모두에 효과가 있는 것 같습니다.init
그리고.buttonWithType:
건설업자내가 필요로 하는 것은 완벽하지만, 하위 분류 이후로.UIButton
털이 많을 수 있습니다. 누구든 그것에 대해 잘못이 있는지 알고 싶습니다.
사용자 지정 적중 영역 버튼.h
#import <UIKit/UIKit.h>
@interface CustomHitAreaButton : UIButton
- (void)setHitTestEdgeInsets:(UIEdgeInsets)hitTestEdgeInsets;
@end
사용자 지정 적중 영역 단추
#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
상속된 UIButton을 재정의하여 구현합니다.
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)
}
}
위의 giaset의 답변을 바탕으로 (가장 우아한 솔루션을 찾은) swift 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
}
}
WJB 배경삽입 단추.h
#import <UIKit/UIKit.h>
@interface WJBackgroundInsetButton : UIButton {
UIEdgeInsets backgroundEdgeInsets_;
}
@property (nonatomic) UIEdgeInsets backgroundEdgeInsets;
@end
WJB 배경삽입 단추
#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
범주의 메서드를 재정의하지 마십시오.하위 클래스 버튼 및 재정의- pointInside:withEvent:
예를 들어 버튼 측면이 44px(최소 탭 가능 영역으로 권장됨)보다 작은 경우 다음을 사용합니다.
- (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));
}
바로 이 목적을 위해 도서관을 만들었습니다.
사용하도록 선택할 수 있습니다.UIView
범주, 하위 분류가 필요하지 않습니다.
@interface UIView (KGHitTesting)
- (void)setMinimumHitTestWidth:(CGFloat)width height:(CGFloat)height;
@end
또는 하고 "UIView " UIButton"을 할 수 있습니다.minimumHitTestWidth
및/는minimumHitTestHeight
그러면 버튼 히트 테스트 영역이 이 두 값으로 표시됩니다.
다른 솔루션과 마찬가지로 다음을 사용합니다.- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
방법.이 메소드는 iOS가 히트 테스트를 수행할 때 호출됩니다.이 블로그 게시물은 iOS 히트 테스트가 어떻게 작동하는지에 대한 좋은 설명을 담고 있습니다.
https://github.com/kgaidis/KGHitTestingViews
@interface KGHitTestingButton : UIButton <KGHitTesting>
@property (nonatomic) CGFloat minimumHitTestHeight;
@property (nonatomic) CGFloat minimumHitTestWidth;
@end
하지 않고 .
tableviewcell.accessory 터치 영역을 확대하기 위해 이 트릭을 사용합니다.
#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];
}
방금 swift 2.2에서 @Chase 솔루션의 포트를 수행했습니다.
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)
}
}
이렇게 사용할 수 있는 an
button.hitTestEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10)
기타 참고 자료는 https://stackoverflow.com/a/13067285/1728552 를 참조하십시오.
저는 정확하지 않거나 추가할 고정 삽입물을 지정해야 하는 솔루션을 많이 보고 있습니다.간단한 솔루션은 다음과 같습니다.UIView
뷰의 적중 직선을 44 x 44 이상으로 확장하는 하위 클래스입니다. 두 차원 중 하나가 이미 그보다 클 경우 해당 차원은 인위적으로 패딩되지 않습니다.
이렇게 하면 수동 구성, 계산 또는 이미지 패딩 없이 버튼의 최소 터치 크기가 항상 44 x 44로 권장됩니다.
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
let minimumTouchSize: CGFloat = 44.0
let center: CGPoint = .init(x: self.bounds.midX, y: self.bounds.midY)
let minimumHitRect: CGRect =
.init(center: center, size: .zero)
.insetBy(
dx: -minimumTouchSize / 2.0,
dy: -minimumTouchSize / 2.0
)
let fullHitRect = self.bounds.union(minimumHitRect)
return fullHitRect.contains(point)
}
나는 Chase의 반응을 따라왔고 그것은 잘 작동합니다. 단 하나의 문제는 당신이 버튼이 선택 해제되는 구역보다 너무 크고, 버튼이 선택 해제되는 구역보다 클 때(구역이 더 크지 않은 경우) 그것은 UIControlEvent의 셀렉터를 호출하지 않습니다.TouchUpInside 이벤트를 누릅니다.
어떤 방향이든 크기는 200이 넘는 것 같습니다.
저는 이 게임에 너무 늦었지만, 당신의 문제를 해결할 수 있는 간단한 기술에 대해 생각해보고 싶었습니다.다음은 일반적인 프로그래밍 방식의 UIButton 스니펫입니다.
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];
버튼에 사용할 투명 png 이미지를 로드하고 배경 이미지를 설정하고 있습니다.저는 UI 이미지를 기반으로 프레임을 설정하고 망막에 대해 50% 스케일링을 하고 있습니다.좋아요, 아마도 당신은 위의 것에 동의하거나 동의하지 않을지도 모르지만, 만약 당신이 히트 지역을 더 크게 만들고 당신 자신을 두통거리로 만들고 싶다면:
제가 하는 일은, 포토샵으로 이미지를 열고 캔버스 크기를 120%로 늘리고 절약하는 것입니다.효과적으로 투명 픽셀로 이미지를 더 크게 만들었습니다.
하나의 접근법입니다.
@jlajlar의 위의 대답은 좋고 직설적으로 보였지만 Xamarin과 일치하지 않습니다.iOS, 그래서 저는 그것을 사마린으로 변환했습니다.Xamarin iOS에서 솔루션을 찾는다면 다음과 같습니다.
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);
}
이 메서드를 UIView 또는 UIImageView를 재정의하는 클래스에 추가할 수 있습니다.이것은 잘 작동했습니다 :)
배경 이미지와 제목을 단추에 사용하기 때문에 어떤 대답도 완벽하게 맞지 않습니다.또한 화면 크기가 변경되면 버튼의 크기가 조정됩니다.
대신, 저는 png 투명 영역을 크게 하여 탭 영역을 확대합니다.
언급URL : https://stackoverflow.com/questions/808503/uibutton-making-the-hit-area-larger-than-the-default-hit-area
'source' 카테고리의 다른 글
D3로 처리하기 위해 Nuxt.js 프레임워크에서 CSV 파일 가져오기 (0) | 2023.07.19 |
---|---|
TypeScript의 개인 정적 속성 (0) | 2023.07.19 |
SQL Server 케이스 문(IS NULL인 경우) (0) | 2023.07.19 |
다시 삽입하지 않고 PyMongo의 MongoDB 문서 배열에 항목 추가 (0) | 2023.07.19 |
숫자를 특정 범위로 클램프(클립, 제한)하려면 어떻게 해야 합니까? (0) | 2023.07.19 |