Pertanyaan UIBarButtonItem dengan tampilan kustom tidak selaras dengan benar pada iOS 7 saat digunakan sebagai item bilah navigasi kiri atau kanan


Kode berikut ini bekerja melalui 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];

Ini adalah bagaimana tombol seharusnya disejajarkan:

Normal positioning

Namun, pada iOS 7, tombol tampak diimbangi dari kanan atau kiri oleh terlalu banyak piksel:

Incorrect positioning on iOS 7

Bagaimana saya bisa mendapatkan item tombol bar kustom saya untuk disejajarkan dengan benar?


75
2017-09-17 22:54


asal


Jawaban:


Bekerja hingga iOS11!

Anda dapat menggunakan ruang fleksibel negatif dan properti rightBarButtonItems bukannya rightBarButtonItem:

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];

66
2018-04-04 16:23



Untuk memperbaiki bug ini, Anda harus subkelas UIButton sehingga Anda dapat menimpa alignmentRectInsets. Dari pengujian saya, Anda harus mengembalikan UIEdgeInsets dengan offset kanan positif atau offset kiri positif, tergantung pada posisi tombol. Angka-angka ini tidak masuk akal bagi saya (setidaknya salah satu dari mereka harus negatif, menurut akal sehat), tetapi inilah yang benar-benar berfungsi:

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

Terima kasih khusus kepada @zev karena menyarankan saya mencoba menyesuaikan alignmentRectInsets.


57
2017-09-17 22:54



Saya telah mencoba semua jawaban di atas dan tidak ada yang berhasil untuk saya. Dan inilah yang berhasil, jika ada yang membutuhkan ini:

(Tidak perlu subclassing)

// 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);

-Ambil melihat hasilnya.

Perhatikan ruang ke tombol kiri dan dari tombol kanan (tombol)   tombol kanan memiliki perilaku default)

enter image description here


28
2017-11-13 10:16



Ok, saya pergi ke "arah" lainnya. Saya membuat semuanya berbaris dengan benar melalui Storyboard dengan iOS 7 (dengan asumsi ini adalah bagaimana itu akan terus bekerja). Dan kemudian menggunakan pendekatan mendeskripsikan sub-kelas, saya sub-kelas UIButton dengan implementasi berikut.

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

Jadi kode ini hanya berjalan jika perangkat sudah pra-iOS 7.

Terima kasih atas wawasan @jaredsinclair!


10
2017-09-19 22:55



@jaredsinclair

Berikut ini lihat kode saya.

// 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;

Lihat apa pun yang tidak benar?

Inilah hasilnya. Gambar kedua tidak begitu terlihat karena saya harus mengambil gambar layar dan masih dalam masa transisi, tetapi Anda dapat dengan jelas melihat bagaimana gambar itu diimbangi secara tidak benar.

Gambar normal baik:

This is the good image, before navigating around

Gambar Offset Buruk:

You can see the offset is now off again before snapping into place

Setelah sekitar setengah detik, gambar kemudian kembali ke lokasi gambar aslinya.

Berikut ini adalah kode saya untuk NavButton.h dan .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

3
2017-10-11 19:44



Solusi yang lebih baik tanpa melompati tombol-tombol di sekitar dapat ditemukan di sini:

Kustom UIBarButtonItem alignment off dengan iOS7


2
2017-10-29 18:29



Bukan penggemar berat subclassing UIButton atau metode mendesis dari jawaban Marius: https://stackoverflow.com/a/19317105/287403

Saya hanya menggunakan pembungkus sederhana, dan memindahkan tombol x tombol itu dalam arah negatif sampai saya menemukan posisi yang benar. Tombol mengetuk tampaknya baik juga (meskipun Anda dapat memperpanjang lebar tombol untuk mencocokkan offset negatif jika Anda membutuhkan).

Inilah kode yang saya gunakan untuk membuat tombol kembali baru:

- (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];
}

1
2018-01-09 19:57



Saya ingin menambahkan ke @jaredsinclair mengkonfirmasi jawaban di bawah ini menimpa metode untuk mereka yang memiliki teks dan / atau gambar di tombol navigasi mereka, jika teks dan gambar tidak akan selaras (hanya gambar latar belakang):

- (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];
}

p.s. makro adalah:

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

1
2018-01-26 20:50



*Solusi ditemukan, baca di akhir jawaban.*

@jaredsinclair

Saya memiliki kasus serupa seperti Kyle Begeman

Ini tombolnya

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

dan saya menggunakannya dalam kasus ini

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];

Semuanya tampak hebat kecuali itu, ketika saya kembali ke VC sebelumnya, tombol itu mereposisi dirinya. Seperti lompatan kecil. Bagi saya itu melompat segera setelah satu detik. Dan itu terjadi setelah saya melakukan popVC dari NavigationViewController.

Edit: Jawabannya di bawah, metode swizzling dari Marius juga membantu saya. 


0
2017-10-15 07:40



Saya datang dengan versi singkat pendekatan 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);
}

Bekerja seperti pesona.


0
2018-02-05 15:15



di ios7 Anda bisa menambahkan barbuttonitem dummy untuk memperbaiki ruang yang tersisa, Anda harus menambahkan boneka sebagai yang pertama, untuk yang terakhir seperti yang terakhir

contoh untuk kiri, Anda harus menambahkan ini setelah mengatur item asli Anda atau di viewdidload jika Anda mengatur tombol menggunakan storyboard.

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];

0
2018-02-26 16:45