Program Tip

사용자 정의보기가있는 UIBarButtonItem이 왼쪽 또는 오른쪽 탐색 모음 항목으로 사용될 때 iOS 7에서 제대로 정렬되지 않음

programtip 2020. 10. 18. 19:01
반응형

사용자 정의보기가있는 UIBarButtonItem이 왼쪽 또는 오른쪽 탐색 모음 항목으로 사용될 때 iOS 7에서 제대로 정렬되지 않음


다음 코드는 iOS 6에서 작동합니다.

UIButton *myButton = nil;
myButton = [UIButton buttonWithType:UIButtonTypeCustom];
myButton.bounds = CGRectMake(0,0,44,30);
// setup myButton's images, etc.

UIBarButtonItem *item = nil;
item = [[UIBarButtonItem alloc] initWithCustomView:customButton];

다음은 버튼이 정렬되는 방식입니다.

정상 위치

그러나 iOS 7에서는 버튼이 너무 많은 픽셀만큼 오른쪽이나 왼쪽에서 오프셋 된 것처럼 보입니다.

iOS 7에서 잘못된 위치

사용자 지정 바 버튼 항목을 올바르게 정렬하려면 어떻게해야합니까?


iOS11까지 작동합니다!

rightBarButtonItem 대신 음의 유동적 공백과 rightBarButtonItems 속성을 사용할 수 있습니다.

UIBarButtonItem *spacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
spacer.width = -10; // for example shift right bar button to the right

self.navigationItem.rightBarButtonItems = @[spacer, yourBarButton];

이 버그를 수정하려면을 재정의 할 수 있도록 UIButton을 하위 클래스로 만들어야합니다 alignmentRectInsets. 내 테스트에서 버튼 위치에 따라 양의 오른쪽 오프셋 또는 양의 왼쪽 오프셋을 사용하여 UIEdgeInsets를 반환해야합니다. 이 숫자는 나에게 의미가 없지만 (상식에 따라 적어도 하나는 음수 여야 함) 실제로 작동하는 것은 다음과 같습니다.

- (UIEdgeInsets)alignmentRectInsets {
    UIEdgeInsets insets;
    if (IF_ITS_A_LEFT_BUTTON) {
        insets = UIEdgeInsetsMake(0, 9.0f, 0, 0);
    } 
    else { // IF_ITS_A_RIGHT_BUTTON
        insets = UIEdgeInsetsMake(0, 0, 0, 9.0f);
    }
    return insets;
}

alignmentRectInsets 조정을 제안 해 주신 @zev에게 특별히 감사드립니다.


위의 모든 답변을 시도했지만 아무것도 효과가 없었습니다. 그리고 누군가 이것을 필요로한다면 작동하는 것은 다음과 같습니다.

(필요한 하위 분류 없음)

// Add your barButtonItem with custom image as the following 
UIBarButtonItem *barButton = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStyleBordered target:self action:@selector(categoryButtonPressed)];
// set your custom image
[barButton setImage:categoryImage];
// finally do the magic
barButton.imageInsets = UIEdgeInsetsMake(0.0, -20, 0, 0);

-결과를보세요.

왼쪽 버튼과 오른쪽 버튼의 공백을 확인합니다 (오른쪽 버튼에는 기본 동작이 있음)

여기에 이미지 설명 입력


좋아, 나는 다른 "방향"으로 갔다. iOS 7의 Storyboard를 통해 모든 것이 제대로 정렬되도록했습니다 (계속 작동한다고 가정). 그런 다음 describe 하위 클래스 접근 방식을 UIButton사용하여 다음 구현으로 하위 클래스 를 만듭니다.

- (UIEdgeInsets)alignmentRectInsets {
    UIEdgeInsets insets;
    if (SYSTEM_VERSION_LESS_THAN(@"7.0")) {
        if ([self isLeftButton]) {
            insets = UIEdgeInsetsMake(0, -10, 0, 0);
        } else {
            insets = UIEdgeInsetsMake(0, 0, 0, -10);
        }
    } else {
        insets = UIEdgeInsetsZero;
    }

    return insets;
}

- (BOOL)isLeftButton {
    return self.frame.origin.x < (self.superview.frame.size.width / 2);
}

따라서이 코드는 기기가 iOS 7 이전 버전 인 경우에만 실행됩니다.

@jaredsinclair 통찰력에 감사드립니다!


안녕하세요.

다음은 내 코드입니다.

// Create the tweetly button that will show settings
self.tweetlyDisplay = [NavButton buttonWithType:UIButtonTypeCustom];
[self.tweetlyDisplay setFrame:CGRectMake(0, 0, 90, 44)];
[self.tweetlyDisplay setBackgroundColor:[UIColor clearColor]];
[self.tweetlyDisplay setBackgroundImage:[UIImage imageNamed:@"settings.png"] forState:UIControlStateNormal];
[self.tweetlyDisplay setAdjustsImageWhenHighlighted:NO];
[self.tweetlyDisplay addTarget:self action:@selector(tweetlyPressed:) forControlEvents:UIControlEventTouchUpInside];

// Add the Tweetly button as the left bar button item
// This had a glitch that moves the image to the right somewhat
UIBarButtonItem *leftBarButton = [[UIBarButtonItem alloc] initWithCustomView:self.tweetlyDisplay];
self.navigationItem.leftBarButtonItem = leftBarButton;

옳지 않은 것이 보이십니까?

결과는 다음과 같습니다. 두 번째 이미지는 스크린 샷을 찍는 데 시간이 걸렸고 여전히 전환 중이기 때문에 잘 보이지 않지만 어떻게 잘못 오프셋되었는지 명확하게 알 수 있습니다.

좋은 정상적인 이미지 :

이것은 주변을 탐색하기 전에 좋은 이미지입니다.

잘못된 오프셋 이미지 :

제자리에 스냅하기 전에 오프셋이 다시 꺼진 것을 볼 수 있습니다.

약 0.5 초 후에 이미지가 원래 이미지 위치로 다시 스냅됩니다.

다음은 NavButton.h 및 .m에 대한 코드입니다.

/**********************************************

 NavButton.h

 **********************************************/

#import <UIKit/UIKit.h>

@interface NavButton : UIButton

@end






/**********************************************

 NavButton.m

**********************************************/


#import "NavButton.h"

@implementation NavButton {

    int imageHeight;

}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code

        imageHeight = 44;

    }
    return self;
}

/*
 // Only override drawRect: if you perform custom drawing.
 // An empty implementation adversely affects performance during animation.
 - (void)drawRect:(CGRect)rect
 {
 // Drawing code
 }
 */


- (UIEdgeInsets)alignmentRectInsets {
    UIEdgeInsets insets;
    if ([self isLeftButton]) {
        insets = UIEdgeInsetsMake(0, 9.0f, 0, 0);
    }
    else { // IF ITS A RIGHT BUTTON
        insets = UIEdgeInsetsMake(0, 0, 0, 9.0f);
    }
    return insets;
}


- (BOOL)isLeftButton {
    return self.frame.origin.x < (self.superview.frame.size.width / 2);
}


// THIS IS THE TRICK.  We make the height of the background rect match the image.
-(CGRect)backgroundRectForBounds:(CGRect)bounds
{
    CGRect bgRect = bounds;
    bgRect.origin.y = (bounds.size.height - imageHeight)/2.0f;
    bgRect.size.height = imageHeight;

    return bgRect;
}


@end

점프 버튼이없는 더 나은 해결책은 여기에서 찾을 수 있습니다.

iOS7에서 맞춤 UIBarButtonItem 정렬 해제


UIButtonMarius의 답변 : https://stackoverflow.com/a/19317105/287403 에서 서브 클래 싱 또는 메서드 전환 의 열렬한 팬이 아닙니다 .

방금 간단한 래퍼를 사용하고 올바른 위치를 찾을 때까지 버튼의 프레임 x를 음의 방향으로 이동했습니다. 버튼을 두드리는 것도 괜찮은 것처럼 보입니다 (필요한 경우 네거티브 오프셋과 일치하도록 버튼의 너비를 확장 할 수 있음).

다음은 새 뒤로 버튼을 생성하는 데 사용하는 코드입니다.

- (UIBarButtonItem *) newBackButton {
    // a macro for the weak strong dance
    @weakify(self);
    UIButton *backButton = [[UIButton alloc] init];
    [backButton setTitle:@"Back" forState:UIControlStateNormal];
    backButton.titleLabel.font = [UIFont systemFontOfSize:17];
    CGFloat width = [@"Back" boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesFontLeading|NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:17]} context:nil].size.width + 27;
    backButton.frame = CGRectMake(-17.5, 0, width + 17.5, 44);
    [backButton setImage:[UIImage imageNamed:@"UINavigationBarBackIndicatorDefault"] forState:UIControlStateNormal];
    [backButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 14, 0, 0)];
    [backButton setTitleColor:mTCOrangeColor forState:UIControlStateNormal];
    backButton.contentEdgeInsets = UIEdgeInsetsZero;
    backButton.imageEdgeInsets = UIEdgeInsetsZero;
    [backButton addEventHandler:^(id sender) {
        // a macro for the weak strong dance
        @strongify(self);
        // do stuff here
    } forControlEvents:UIControlEventTouchUpInside];
    UIView *buttonWrapper = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, 44)];
    [buttonWrapper addSubview:backButton];
    return [[UIBarButtonItem alloc] initWithCustomView:buttonWrapper];
}

내비게이션 버튼에 텍스트 및 / 또는 이미지가있는 사람들에게 아래의 재정의 방법에 대해 @jaredsinclair 확인 답변을 추가하고 싶습니다. 그렇지 않으면 텍스트와 이미지가 정렬되지 않습니다 (배경 이미지 만 해당).

- (UIEdgeInsets) titleEdgeInsets {
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0"))
{
    if (IF_ITS_A_LEFT_BUTTON) {
    {
        return UIEdgeInsetsMake(0, 0, 0, 9.0f);
    }
    else
    { // IF_ITS_A_RIGHT_BUTTON
        return UIEdgeInsetsMake(0, 9.0f, 0, 0);
    }
}
return [super titleEdgeInsets];
}

- (UIEdgeInsets)imageEdgeInsets {
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0"))
{
    if (IF_ITS_A_LEFT_BUTTON)
    {
        return UIEdgeInsetsMake(0, 0, 0, 9.0f);
    }
    else
    { // IF_ITS_A_RIGHT_BUTTON
        return UIEdgeInsetsMake(0, 9.0f, 0, 0);
    }
}

return [super imageEdgeInsets];
}

추신 매크로는 다음과 같습니다.

#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)

* 해결책을 찾았습니다. 답의 끝에 읽으십시오. *

안녕하세요.

Kyle Begeman과 비슷한 경우가 있습니다.

이것은 버튼입니다

 - (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
    }
    return self;
}

- (UIEdgeInsets)alignmentRectInsets {
    UIEdgeInsets insets;

    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")){
        if ([self isLeftButton]) {
            insets = UIEdgeInsetsMake(0, 9.0f, 0, 0);
        } else {
            insets = UIEdgeInsetsMake(0, 0, 0, 9.0f);
        }
    }else{
        insets = UIEdgeInsetsZero;
    }

    return insets;
}

- (BOOL)isLeftButton {
    return self.frame.origin.x < (self.superview.frame.size.width / 2);
}

이 경우에 사용합니다

PBNavigationBarButton *dashboardButton = [PBNavigationBarButton buttonWithType:UIButtonTypeCustom];
    UIImage *dashboardImage = [UIImage imageNamed:@"btn_dashboard.png"];
    UIImage *dashboardImageHighlighted = [UIImage imageNamed:@"btn_dashboard_pressed.png"];

    NSInteger halfImageWidth = ceilf([dashboardImage size].width/2.0f);

    [dashboardButton setBackgroundImage:[dashboardImage stretchableImageWithLeftCapWidth:halfImageWidth topCapHeight:0] forState:UIControlStateNormal];
    [dashboardButton setBackgroundImage:[dashboardImageHighlighted stretchableImageWithLeftCapWidth:halfImageWidth topCapHeight:0] forState:UIControlStateHighlighted];
    [dashboardButton addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
    [dashboardButton sizeToFit];

    UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc]  initWithCustomView:dashboardButton];

이전 VC로 돌아 가면 버튼의 위치가 변경된다는 점을 제외하면 모든 것이 멋지게 보입니다. 작은 점프처럼. 나를 위해 그것은 1 초 후에 바로 점프합니다. 그리고 NavigationViewController에서 popVC를 수행 한 후에 발생합니다.

편집 : 아래 답변, Marius의 swizzling 방법도 저에게 도움이되었습니다.


나는 jaredsinclair의 접근 방식의 단축 버전을 생각해 냈습니다.

- (UIEdgeInsets)alignmentRectInsets {
    return [self isLeftButton] ? UIEdgeInsetsMake(0, 9.0f, 0, 0) : UIEdgeInsetsMake(0, 0, 0, 9.0f); 
}

- (BOOL)isLeftButton {
    return self.frame.origin.x < (self.superview.frame.size.width / 2);
}

매력처럼 작동합니다.


ios7에서는 왼쪽 공간을 고정하기 위해 더미 barbuttonitem을 추가 할 수 있습니다. 먼저 더미를 추가해야합니다.

예를 들어 왼쪽의 경우 원본 항목을 설정 한 후 또는 스토리 보드를 사용하여 버튼을 설정하는 경우 viewdidload에 추가해야합니다.

NSMutableArray *buttons = [[NSMutableArray alloc] init];
UIBarButtonItem *spacerItem = [[UIBarButtonItem alloc] init];
[buttons addObject:spacerItem];
for(UIBarButtonItem *item in self.leftBarButtonItems){
    [buttons addObject:item];
}
[self setLeftBarButtonItems:[NSArray arrayWithArray:buttons] animated:NO];

다음을 변경하십시오. UIButton

제어-> 정렬-> 수평을 오른쪽 정렬


imageEdgeInsets이 버그를 수정하기 위해 조정 하기 만하면 됩니다.

이 시도.

    UIButton *actionBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
    [actionBtn setImage:[UIImage imageNamed:@"arrow.png"] forState:UIControlStateNormal];
    [actionBtn addTarget:self action:@selector(goToSetting) forControlEvents:UIControlEventTouchUpInside];
    actionBtn.imageEdgeInsets = UIEdgeInsetsMake(0, 9, 0, -9);

    UIBarButtonItem *profileBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:actionBtn];
    self.topViewController.navigationItem.rightBarButtonItems = @[profileBarButtonItem];

iOS 11에서 테스트 됨

 public lazy var navigationBackBarButton : UIBarButtonItem = {

        let backBarButtonIcon = <Image Literal here>
        let backBarButton = UIBarButtonItem(image: backBarButtonIcon, style: .plain, target: self, action: #selector(self.backBarButtonTouched(_:)))
        backBarButton.imageInsets = UIEdgeInsets(top: 0.0, left: -9.0, bottom: 0.0, right: 0.0)
        return backBarButton

    }()

2018, iOS 11+, Swift 4.x, 이것은 나를 위해 일했습니다.

상위 답변 결합 :

특성

internal lazy var button_Favorite: UIButton = {
    let button = UIButton(type: .custom)
    button.setImage(.favNormal, for: .normal)
    button.contentHorizontalAlignment = .right
    button.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, -9.0)
    return button
}()

에서 viewDidLoad:

    let barButton = UIBarButtonItem(customView: self.button_Favorite)
    self.button_Favorite.frame = CGRect(x: 0, y: 0, width: 40.0, height: 44.0)
    let negativeSpacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil)
    negativeSpacer.width = -10.0
    self.navigationItem.rightBarButtonItems = [negativeSpacer, barButton]

참고 URL : https://stackoverflow.com/questions/18861201/uibarbuttonitem-with-custom-view-not-properly-aligned-on-ios-7-when-used-as-left

반응형