UIBarButtonItem z niestandardowym obrazem i bez obramowania

89

Chcę utworzyć UIBarButtonItem z niestandardowym obrazem, ale nie chcę obramowania dodawanego przez iPhone'a, ponieważ mój obraz ma specjalną ramkę.

Jest taki sam jak przycisk Wstecz, ale przycisk Dalej.

Ta aplikacja jest przeznaczona do projektu inHouse, więc nie obchodzi mnie, czy Apple ją odrzuci, zatwierdzi lub polubi :-)

Jeśli używam właściwości initWithCustomView: v UIBarButtonItem, mogę to zrobić:

UIImage *image = [UIImage imageNamed:@"right.png"];

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setBackgroundImage: [image stretchableImageWithLeftCapWidth:7.0 topCapHeight:0.0] forState:UIControlStateNormal];
[button setBackgroundImage: [[UIImage imageNamed: @"right_clicked.png"] stretchableImageWithLeftCapWidth:7.0 topCapHeight:0.0] forState:UIControlStateHighlighted];

 button.frame= CGRectMake(0.0, 0.0, image.size.width, image.size.height);

[button addTarget:self action:@selector(AcceptData)    forControlEvents:UIControlEventTouchUpInside];

UIView *v=[[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, image.size.width, image.size.height) ];

[v addSubview:button];

UIBarButtonItem *forward = [[UIBarButtonItem alloc] initWithCustomView:v];

self.navigationItem.rightBarButtonItem= forward;

[v release];
[image release];

To działa, ale jeśli muszę powtórzyć ten proces w 10 widokach, to nie jest SUCHA.

Przypuszczam, że muszę podklasę, ale co?

  • NSView?
  • UIBarButtonItem?

dzięki,

pozdrowienia,

mongeta
źródło
3
Dzięki za udostępnienie kodu, to wszystko, czego potrzebowałem :).
Max
1
Wszyscy, skorzystałem z odpowiedzi udzielonej przez San 6 lutego. Integracja z moim Storyboardem zajęła całe 5 minut i działała idealnie. Właściwość Selector znajduje się w sekcji Connections Inspector of IB. Sterowanie przeciąganiem z UIButton do obiektu ViewController, a metody pojawią się. Wybierz żądaną metodę i prawie gotowe. Pozostało tylko trochę uporządkowania kodu. Użyto btnXXXXX.hidden, aby ukryć i odkryć, aby zastąpić barbuttonitem = nil. Ale ta metoda była łatwa i bardzo czysta.
user589642

Odpowiedzi:

44

Możesz dodać metodę do UIBarButtonItem bez tworzenia podklas przy użyciu kategorii niestandardowej:

@interface UIBarButtonItem(MyCategory)

+ (UIBarButtonItem*)barItemWithImage:(UIImage*)image target:(id)target action:(SEL)action;

@end

@implementation UIBarButtonItem(MyCategory)

+ (UIBarButtonItem*)barItemWithImage:(UIImage*)image target:(id)target action:(SEL)action{
 // Move your item creation code here
}
@end

Tak więc w dowolnym miejscu kodu możesz utworzyć element paska wywołujący tę metodę (pod warunkiem, że dołączysz nagłówek do jego deklaracji).

PS Nie musisz używać „v” UIView, ponieważ możesz utworzyć bezpośrednio UIBarButtonItemza pomocą przycisku widok niestandardowy.
PPS Potrzebujesz również [forward release] w swoim kodzie.

Vladimir
źródło
Kategoria niestandardowa: muszę utworzyć plik nagłówkowy z tymi deklaracjami i plik implementacji, w którym umieszczam kod, do którego się odnosisz? dzięki
mongeta
Jego praca dzięki dużo, ale nie jestem w stanie napisać selektora Nie chcę pisać selektora w kategorii Jak mogę napisać to na mojej klasie
Nilesh Tupe
@NileshTupe co masz na myśli? Zdajesz metodę selektora i cel - więc celem może być dowolny obiekt, który chcesz
Vladimir,
2
BTW - dodałem to do mojego małego repozytorium open source dla wygodnych kategorii UIKit. Dzięki @Vladimirowi za inspirację. (uwaga: wszystkie moje rzeczy są oparte na ARC) github.com/egold/UIKitConvenience/blob/master/UIKitConvenience/ ...
Eric Goldberg
50

Innym prostym rozwiązaniem jest

  1. Przeciągnij standardowy przycisk UIButton
  2. Ustaw niestandardowy styl przycisku i ustaw obraz dla tego przycisku
  3. Przeciągnij go na UINavigationBar
  4. Ustaw selektor
san
źródło
1
Prawdopodobnie najłatwiejsze rozwiązanie. Dzięki!
Prine
1
Znakomity! Jedyne dziwactwo - nie zadziała, jeśli przeciągniesz przycisk prosto do paska nawigacji. Przycisk musi być ustawiony jako niestandardowy, zanim zostanie dodany do paska nawigacyjnego. Nie wiem dlaczego, ale tak właśnie jest. Więc krok 1 - oznacza przeciągnięcie UIBatton gdzieś na twoim interfejsie użytkownika innym niż pasek nawigacyjny.
Andrei Tchijov
1
trudno jest być prostym i skutecznym.
Dobra
37

To było dla mnie łatwe. Jest zasugerowany na wierzchu. „random.png” musi być w projekcie. Po prostu przeciągnij i upuść dowolny obraz.

 UIButton *a1 = [UIButton buttonWithType:UIButtonTypeCustom];
        [a1 setFrame:CGRectMake(0.0f, 0.0f, 25.0f, 25.0f)];
        [a1 addTarget:self action:@selector(randomMsg) forControlEvents:UIControlEventTouchUpInside];
        [a1 setImage:[UIImage imageNamed:@"config.png"] forState:UIControlStateNormal];
        UIBarButtonItem *random = [[UIBarButtonItem alloc] initWithCustomView:a1];

 //? line incomplete ?//   imageNamed:@"random.png"] style:UIBarButtonItemStylePlain target:self action:@selector(randomMsg)];

    self.navigationItem.rightBarButtonItem = random;
m-farhan
źródło
6

Alternatywą jest podklasa UIBarButtonItem. Czemu? Aby akcja została wywołana na celu z odpowiednim nadawcą. W powyższym kodzie argument nadawcy w komunikacie dotyczącym akcji to instancja UIButton, a nie instancja UIBarButtonItem. Byłoby to ważne, na przykład, jeśli chcesz przedstawić kontroler UIPopoverController z elementu przycisku paska. Podklasując UIBarButtonItem, możesz dodać ivar, który zachowuje oryginalny cel, umożliwiając naszym instancjom podklasy przechwytywanie, modyfikowanie i przekazywanie komunikatu akcji z odpowiednim nadawcą.

Tak więc CCFBarButtonItem.h:

#import <uIKit/UIBarButtonItem.h>

@interface CCFBarButtonItem : UIBarButtonItem
{
@protected
    id _originalTarget;
}
- (id)initWithImage:(UIImage *)image target:(id)target action:(SEL)action;
@end

i CCFBarButtonItem.m

#import "CCFBarButtonItem.h"
#import <UIKit/UIButton.h>
#import <UIKit/UIView.h>
#import <UIKit/UIImage.h>

@implementation CCFBarButtonItem

#pragma mark - Object life cycle

- (id)initWithImage:(UIImage *)image target:(id)target action:(SEL)action;
{
    _ASSIGN( _originalTarget, target );

    UIButton *imgButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [imgButton setImage:image forState:UIControlStateNormal];
    imgButton.frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height);
    [imgButton addTarget:self action:action forControlEvents:UIControlEventTouchUpInside];

    self = [super initWithCustomView:imgButton];

    return self;
}

- (void)dealloc;
{
    MCRelease(_originalTarget);
    [super dealloc];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
{
    if( [_originalTarget respondsToSelector:aSelector] )
    {
        return [_originalTarget methodSignatureForSelector:aSelector];
    }
    else
    {
        return [super methodSignatureForSelector:aSelector];
    }
}

- (void)forwardInvocation:(NSInvocation *)anInvocation;
{
    SEL aSelector = [anInvocation selector];
    if( [_originalTarget respondsToSelector:aSelector] )
    {
        //  modify the 'sender' argument so that it points to self
        [anInvocation setArgument:&self atIndex:2];
        [anInvocation invokeWithTarget:_originalTarget];
    }
    else
    {
        [self doesNotRecognizeSelector:aSelector];
    }
}
@end
FluffulousChimp
źródło
5
UIBarButtonItem *menuItem = [[UIBarButtonItem alloc] initWithImage: [UIImage imageNamed:@"icon-menu.png"]
                                                                    style:UIBarButtonItemStylePlain
                                                                   target:self
                                                                   action:@selector(showMenu)];
alexmorhun
źródło
3

Można to również zrobić programowo (oczywiście):

Najpierw utwórz widok niestandardowy. Ten niestandardowy widok może zawierać obraz, przycisk lub cokolwiek innego, co chcesz. Widok niestandardowy można wykonać programowo lub w IB:

UIImage *customImage = [UIImage imageNamed:@"imageName"];
UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, customImage.size.width, customImage.size.height)];
customView.backgroundColor = [UIColor colorWithPatternImage:customImage];

Następnie utwórz UIBarButtonItem i zainicjuj go za pomocą widoku niestandardowego.

UIBarButtonItem *customBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:customView];

Teraz po prostu dodaj niestandardowy UIBarButton do leftBarButtonItem:

self.navigationItem.leftBarButtonItem = customBarButtonItem;
abriggs
źródło
1

Ok, ta kategoria działa bardzo dobrze, ponieważ nie ma problemów z kontrolerem Popover :-)

#import <UIKit/UIKit.h>

@interface UIBarButtonItem (BarButtonItemExtended)
+ (UIBarButtonItem*)barItemWithImage:(UIImage*)image target:(id)target action:(SEL)action;
-(void)performBarButtonAction:(id)sender;
@end



#import "UIBarButtonItem+BarButtonItemExtended.h"

@implementation UIBarButtonItem (BarButtonItemExtended)

+ (UIBarButtonItem*)barItemWithImage:(UIImage*)image target:(id)target action:(SEL)action
{    
    UIButton *imgButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [imgButton setImage:image forState:UIControlStateNormal];
    imgButton.frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height);

    UIBarButtonItem *b = [[UIBarButtonItem alloc]initWithCustomView:imgButton];

    [imgButton addTarget:b action:@selector(performBarButtonAction:) forControlEvents:UIControlEventTouchUpInside];

    [b setAction:action];
    [b setTarget:target];

    return b;
}

-(void)performBarButtonAction:(UIButton*)sender
{
    [[self target] performSelector:self.action withObject:self];
}
@end
Raegtime
źródło
1

Sprawdź to proste rozwiązanie.

- (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController
{
barButtonItem.image = [UIImage imageNamed:@"navButton.png"];
barButtonItem.style = UIBarButtonItemStylePlain;

[barButtonItem setBackgroundImage:[UIImage imageNamed:@"1x1.png"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES];
self.masterPopoverController = popoverController;
}

Tutaj 1x1.png jest 1-pikselowym przezroczystym obrazem png, który można pobrać z linku poniżej

http://commons.wikimedia.org/wiki/File:1x1.png

Fremy Jose
źródło
Możesz po prostu użyć [UIImage new] zamiast używać przezroczystego obrazu.
James Campbell
0

Jeszcze jedno rozwiązanie, myślę, że jest prostsze w przypadku tworzenia przycisku programowo:

UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithImage:defaultImage
                                             landscapeImagePhone:landscapeImage
                                                           style:UIBarButtonItemStylePlain
                                                          target:self
                                                          action:@selector(someSelector)];
[button setBackgroundImage:[UIImage new] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[button setBackgroundImage:[UIImage new] forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone];
Michaił
źródło