Como mostro / oculto um UIBarButtonItem?

251

Eu criei uma barra de ferramentas no IB com vários botões. Eu gostaria de poder ocultar / mostrar um dos botões, dependendo do estado dos dados na janela principal.

UIBarButtonItem não possui uma propriedade oculta, e quaisquer exemplos que encontrei até agora para ocultá-los envolvem a configuração de botões da barra de navegação como nulos, o que eu acho que não quero fazer aqui, porque talvez seja necessário exibir o botão novamente (não para mencionar que, se eu conectar meu botão a um IBOutlet, se eu configurá-lo como nulo, não sei como recuperá-lo).

Sasha
fonte
Eu simplesmente o desativei e adicionei um rótulo de acessibilidade dizendo que o recurso do botão não está disponível.
Daniel Springer #

Respostas:

263

Salve seu botão em uma tomada forte (vamos chamá-lo myButton) e faça isso para adicionar / remover:

// Get the reference to the current toolbar buttons
NSMutableArray *toolbarButtons = [self.toolbarItems mutableCopy];

// This is how you remove the button from the toolbar and animate it
[toolbarButtons removeObject:self.myButton];
[self setToolbarItems:toolbarButtons animated:YES];

// This is how you add the button to the toolbar and animate it
if (![toolbarButtons containsObject:self.myButton]) {
    // The following line adds the object to the end of the array.  
    // If you want to add the button somewhere else, use the `insertObject:atIndex:` 
    // method instead of the `addObject` method.
    [toolbarButtons addObject:self.myButton];
    [self setToolbarItems:toolbarButtons animated:YES];
}

Como está armazenado na tomada, você manterá uma referência a ele mesmo quando não estiver na barra de ferramentas.

lnafziger
fonte
73
Para fazer isso funcionar no meu botão direito em um controlador de Navegação, usei self.navigationItem.rightBarButtonItems e [self.navigationItem setRightBarButtonItems <prams>] em vez de toolBarItems e setToolBarItems.
MindSpiker
@MindSpiker: Sim, ele também funciona nos botões de uma barra de navegação.
Lnfziger 12/11/12
1
eu tenho que zero myButton em dealloc?
Van Du Tran
48
Ou a Apple poderia ter adicionado a propriedade .hidden. -_-
GeneCode
217

Eu sei que esta resposta está atrasada para esta pergunta. No entanto, pode ajudar se mais alguém enfrentar uma situação semelhante.

No iOS 7, para ocultar um item do botão de barra, podemos usar as duas técnicas a seguir: -

  • use SetTitleTextAttributes: - Funciona muito bem em itens do botão da barra, como "Concluído", "Salvar" etc. No entanto, não funciona em itens como Adicionar, símbolo da Lixeira etc. (pelo menos não para mim), pois não são textos.
  • use TintColor: - Se eu tiver um item de botão de barra chamado "deleteButton": -

Para ocultar o botão, usei o seguinte código: -

[self.deleteButton setEnabled:NO]; 
[self.deleteButton setTintColor: [UIColor clearColor]];

Para mostrar o botão novamente, usei o seguinte código: -

[self.deleteButton setEnabled:YES];
[self.deleteButton setTintColor:nil];
Máx.
fonte
[self.navigationItem.rightBarButtonItem setEnabled: NO]; [self.navigationItem.rightBarButtonItem setTintColor: [UIColor clearColor]];
Leon
3
Para Swift: deleteButton.enabled = false; deleteButton.tintColor = UIColor.clearColor()para desativar e ocultar, e deleteButton.enabled = true; deleteButton.tintColor = nilpara reativar e mostrar normalmente.
Unixmonkey
1
Eu gosto que essa abordagem me permita colocar a lógica para exibir ou não o UIBarButton dentro dessa classe. O motivo pelo qual ele funciona apenas com um botão não é imediatamente óbvio - porque se você ocultar um botão dessa maneira, ele ainda ocupará espaço, portanto, você poderá ter uma lacuna vazia se tiver vários botões.
SimplGy
Sua primeira abordagem foi perfeita para mim. Eu definir UIColor.clearpara UIControlState.disablede pode mostrar / ocultar o botão com setEnabled. Obviamente, como você afirmou, isso funciona apenas para botões de texto.
Fl034 11/0918
Se eu continuar pressionando até aparecer uma imagem grande (provavelmente para acessibilidade), mesmo com isEnabled definido como false, ainda funcionará.
Daniel Springer
67

Aqui está uma abordagem simples:

hide:  barbuttonItem.width = 0.01;
show:  barbuttonItem.width = 0; //(0 defaults to normal button width, which is the width of the text)

Acabei de executá-lo no meu iPad de retina e .01 é pequeno o suficiente para não aparecer.

Drew Rosenberg
fonte
13
De todas as soluções, essa foi rápida, suja e eficaz. Eu também adicionei barbuttItem.enabled = NO; já que eu ainda poderia acionar o botão se eu apertasse o suficiente.
26512 Stickley
1
Não funciona para mim. Eu pensei que era porque estava usando um botão Adicionar com a imagem '+', mas tentei um botão Personalizado com o texto "Novo" e ele ainda não desapareceu. A ativação muda, então eu sei que meu código está sendo executado. Alguma ideia? Note que este botão é criado em um storyboard e tem um segue então eu não quero mudar para um botão programático vez
ruibarbo
19
Parece não funcionar em uma barra de ferramentas do controlador de navegação, mas funciona com outras barras de ferramentas.
de Drew Rosenberg
3
Esconde-o, mas ainda responde a torneiras. Para mim, funciona como um botão invisível.
Tibidabo
Se tiver definido cor da tonalidade global usando esta linha self.window?.tintColor = APP_PRIMARY_COLORem AppDelegate, então isso não vai funcionar
Mehul Thakkar
60

É possível ocultar um botão no lugar sem alterar sua largura ou removê-lo da barra. Se você definir o estilo para simples, remover o título e desativar o botão, ele desaparecerá. Para restaurá-lo, basta reverter suas alterações.

-(void)toggleBarButton:(bool)show
{
    if (show) {
        btn.style = UIBarButtonItemStyleBordered;
        btn.enabled = true;
        btn.title = @"MyTitle";
    } else {
        btn.style = UIBarButtonItemStylePlain;
        btn.enabled = false;
        btn.title = nil;
    }
}
Eli Burke
fonte
2
Isso funcionou para mim, basta definir btn.title = nil. Eu também estou definindo habilitado = NO, apenas no caso ...
Pork 'n' Bunny
3
Definir o buttonItem.title como nulo não funcionou para mim no iOS7. O botão não reapareceu ao colocá-lo de volta. No entanto, o que funcionou foi definir buttonItem.title = @ "";
precisa
42

Abaixo está minha solução, embora eu estivesse procurando pela Barra de Navegação.

navBar.topItem.rightBarButtonItem = nil;

Aqui "navBar" é um IBOutlet para o NavigationBar na exibição em XIB. Aqui eu queria ocultar o botão ou mostrá-lo com base em alguma condição. Então, estou testando a condição em "If" e se true, estou definindo o botão como nulo no método viewDidLoad da exibição de destino.

Isso pode não ser relevante para o seu problema exatamente, mas existe algo semelhante se você deseja ocultar os botões no NavigationBar

vishal dharankar
fonte
Se desejar definir rightBarButtonItemnovamente mais tarde , verifique se o item do botão está armazenado em um IBOutlet forte, para que não seja liberado quando você o retirar da barra de navegação.
Nate
30

Para Swift 3 e Swift 4, você pode fazer isso para ocultar UIBarButtomItem:

self.deleteButton.isEnabled = false
self.deleteButton.tintColor = UIColor.clear

E para mostrar o UIBarButtonItem:

self.deleteButton.isEnabled = true
self.deleteButton.tintColor = UIColor.blue

No, tintColorvocê deve especificar a cor de origem que está usando para oUIBarButtomItem

pableiros
fonte
2
Mas isso ainda terá espaço para este botão.
Makalele
22

Atualmente, estou executando o OS X Yosemite Developer Preview 7 e o Xcode 6 beta 6 visando o iOS 7.1 e a seguinte solução funciona bem para mim:

  • Criar saída para UINavigationIteme UIBarButtonItems
  • Execute o código a seguir para remover

    [self.navItem setRightBarButtonItem:nil];
    [self.navItem setLeftBarButtonItem:nil];
  • Execute os seguintes códigos para adicionar botões novamente

    [self.navItem setRightBarButtonItem:deleteItem];
    [self.navItem setLeftBarButtonItem:addItem];
Olcay Ertaş
fonte
Obrigado, este é o melhor método que encontrei também. Apenas certifique-se de que suas referências aos botões sejam fortes.
jyoung
Além disso, lembre-se de que isso funciona apenas se você tiver apenas um botão lá. O exemplo removerá TODOS os botões desse lado.
lnafziger
@jyoung Isso funcionou para mim, mas por que importa se a referência é forte? Eu não tentei de outra maneira, mas geralmente não a configuro dessa maneira, pois não é o padrão.
Robert
@ Robert Você deseja usar o objeto posteriormente, portanto, certifique-se de que o objeto não seja coletado como lixo quando o definir como nulo. Se nada mais estivesse retendo o objeto quando você disse ao item do botão de barra que não há problema em se livrar dele, sua contagem de referência seria 0 e seria coletado de lixo.
jyoung
14

Eu usei o IBOutlets no meu projeto. Então, minha solução foi:

@IBOutlet weak var addBarButton: UIBarButtonItem!

addBarButton.enabled = false
addBarButton.tintColor = UIColor.clearColor()

E quando precisar mostrar essa barra novamente, basta definir propriedades invertidas.

Em Swift 3 em vez enableusar isEnablepropriedade.

Den
fonte
13

self.dismissButton.customView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];

Dmitry Semenyuk
fonte
12

iOS 8. UIBarButtonItem com imagem personalizada. Tentou muitas maneiras diferentes, a maioria delas não estava ajudando. A solução de Max setTintColornão estava mudando para nenhuma cor. Eu mesmo descobri este, pensei que seria útil para alguém.

Para esconder:

[self.navigationItem.rightBarButtonItem setEnabled:NO];
[self.navigationItem.rightBarButtonItem setImage:nil];

Para mostrar:

[self.navigationItem.rightBarButtonItem setEnabled:YES];
[self.navigationItem.rightBarButtonItem setImage:image];
Rinto Rapheal
fonte
9

Experimente no Swift , não atualize o tintColorse você tiver algum design para o seu UIBarButtonItem, como o tamanho da fonte no AppDelegate, isso mudará totalmente a aparência do seu botão ao aparecer.

No caso de um botão de texto, a alteração do título pode deixar o botão 'desaparecer'.

if WANT_TO_SHOW {
    myBarButtonItem.enabled = true
    myBarButtonItem.title = "BUTTON_NAME"
}else{
    myBarButtonItem.enabled = false
    myBarButtonItem.title = ""
}
Jeffrey Neo
fonte
7

Descobri outra ruga na abordagem tintColore isEnabledsugerida por Max e outros - quando o VoiceOver está ativado para acessibilidade e o botão está logicamente oculto, o cursor de acessibilidade ainda focaliza o botão da barra e afirma que está "esmaecido" (ou seja, porque isEnabledestá definido como falso). A abordagem na resposta aceita não sofre esse efeito colateral, mas outro trabalho que encontrei foi definir isAccessibilityElementfalso quando "ocultando" o botão:

deleteButton.tintColor = UIColor.clear
deleteButton.isEnabled = false
deleteButton.isAccessibilityElement = false

E, em seguida, isAccessibilityElementvoltando a true quando "mostrando" o botão:

deleteButton.tintColor = UIColor.blue
deleteButton.isEnabled = true
deleteButton.isAccessibilityElement = true

Ter o item do botão da barra ainda ocupando espaço não era um problema no meu caso, pois estávamos ocultando / mostrando a parte mais à esquerda dos itens do botão da barra à direita.

Evan Kirkwood
fonte
6
@IBDesignable class AttributedBarButtonItem: UIBarButtonItem {

    var isHidden: Bool = false {

        didSet {

            isEnabled = !isHidden
            tintColor = isHidden ? UIColor.clear : UIColor.black
        }
    }
}

E agora simplesmente mude de isHiddenpropriedade.

Bartłomiej Semańczyk
fonte
5

Melhorando de @lnafziger answer

Salve seus Barbuttons em uma tomada forte e faça isso para ocultar / mostrar:

-(void) hideBarButtonItem :(UIBarButtonItem *)myButton {
    // Get the reference to the current toolbar buttons
    NSMutableArray *navBarBtns = [self.navigationItem.rightBarButtonItems mutableCopy];

    // This is how you remove the button from the toolbar and animate it
    [navBarBtns removeObject:myButton];
    [self.navigationItem setRightBarButtonItems:navBarBtns animated:YES];
}


-(void) showBarButtonItem :(UIBarButtonItem *)myButton {
    // Get the reference to the current toolbar buttons
    NSMutableArray *navBarBtns = [self.navigationItem.rightBarButtonItems mutableCopy];

    // This is how you add the button to the toolbar and animate it
    if (![navBarBtns containsObject:myButton]) {
        [navBarBtns addObject:myButton];
        [self.navigationItem setRightBarButtonItems:navBarBtns animated:YES];
    }
}

Sempre que necessário, use abaixo da Função.

[self showBarButtonItem:self.rightBarBtn1];
[self hideBarButtonItem:self.rightBarBtn1];
umakanta
fonte
5

Basta definir barButton.customView = UIView()e ver o truque

jeff ayan
fonte
O que essa resposta faz é permitir que todo o dimensionamento flexível funcione. Na verdade, é uma resposta super eficiente. Provavelmente acoplado a uma extensão, seria perfeito.
Adrian_H
4

Não há como "ocultar" um UIBarButtonItem. Você deve removê-lo do superView e adicioná-lo novamente quando desejar exibi-lo novamente.

Kyle Richter
fonte
Na verdade, isso não é verdade - o método descrito por Max funciona bem.
northernman
1
nothernman - Max não está realmente correto. Na verdade, ele não está escondendo o botão da maneira que a maioria das pessoas definiria "esconder". Ele está simplesmente tornando-o não visível e desativando a interação do usuário. O botão ainda está lá e ocupa espaço. Tudo se resume a como você deseja definir "esconder", acredito que o espírito da pergunta original estava realmente querendo removê-lo / adicioná-lo, e não apenas torná-lo invisível.
22715 Michael Michael
4

Este é um longo caminho até a lista de respostas, mas, caso alguém queira copiar e colar com facilidade a solução rápida, aqui está

func hideToolbarItem(button: UIBarButtonItem, withToolbar toolbar: UIToolbar) {
    var toolbarButtons: [UIBarButtonItem] = toolbar.items!
    toolbarButtons.removeAtIndex(toolbarButtons.indexOf(button)!)
    toolbar.setItems(toolbarButtons, animated: true)
}

func showToolbarItem(button: UIBarButtonItem, inToolbar toolbar: UIToolbar, atIndex index: Int) {
    var toolbarButtons: [UIBarButtonItem] = toolbar.items!
    if !toolbarButtons.contains(button) {
        toolbarButtons.insert(button, atIndex: index)
        toolbar.setItems(toolbarButtons, animated:true);
    }
}
maninvan
fonte
Nada mal, mas você deve fornecer um UINavigationItem como parâmetro e não UIToolbar porque ele pede para ocultar um UIBarButtonItem. Modifiquei sua função para: func hideToolbarItem (botão: UIBarButtonItem, com barra de ferramentas da barra de ferramentas: UINavigationItem) {var toolbarButtons: [UIBarButtonItem] = toolbar.rightBarButtonItems! toolbarButtons.removeAtIndex (toolbarButtons.indexOf (botão)!) toolbar.setRightBarButtonItems (toolbarbuttons, animado: true)} e que funciona muito bem
Kingalione
3

Uma maneira de fazer isso é usar a initWithCustomView:(UIView *)propriedade de quando alocar o UIBarButtonItem. Subclasse paraUIView terá propriedade de ocultar / mostrar.

Por exemplo:

1. Tenha uma UIButtonque você deseja ocultar / mostrar.

2. Faça UIButtoncomo a visualização personalizada. Gostar :

UIButton*myButton=[UIButton buttonWithType:UIButtonTypeRoundedRect];//your button

UIBarButtonItem*yourBarButton=[[UIBarButtonItem alloc] initWithCustomView:myButton];

3. Você pode ocultar / mostrar o myButtonque você criou.[myButton setHidden:YES];

iNoob
fonte
No entanto, não fechará a lacuna entre os outros botões: quando estiver "oculto", haverá uma área vazia na barra de ferramentas.
precisa saber é o seguinte
@lnafziger Sim, isso é verdade, mas eu não li a menção do OP sobre como fechar o espaço entre os botões, mas é um bom ponto a ser observado.
iNoob
1
Obrigado, sua resposta também é útil, mas acho que a maioria das pessoas quando desejam ocultar um botão em uma barra de ferramentas deseja que pareça que não existe (sem a área em branco). Se é a esquerda ou a direita, isso realmente não importa.
precisa saber é o seguinte
Bons pontos, iNoob e Inafziger - eu não mencionei de nenhuma maneira, mas sim, eu preferiria que não houvesse um espaço em branco.
Sasha
3

Para a versão Swift, aqui está o código:

Para UINavigationBar:

self.navigationItem.rightBarButtonItem = nil

self.navigationItem.leftBarButtonItem = nil
Sohil R. Memon
fonte
2

Definir a cor do texto para uma cor clara quando o item do botão da barra estiver desativado é provavelmente uma opção mais limpa. Não há esquisitices que você precise explicar em um comentário. Além disso, você não destrói o botão para manter os seguimentos do storyboard associado.

[self.navigationItem.rightBarButtonItem setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor clearColor]}
                                                      forState:UIControlStateDisabled];

Então, sempre que quiser ocultar o item do botão da barra, você pode:

self.navigationItem.rightBarButton.enabled = NO;

É coxo não há propriedade oculta, mas isso oferece o mesmo resultado.

filhotes
fonte
1
Eu tinha um botão dentro do rightBarButtonItem. Então, defino seu ativado como NÃO e alterei sua imagem no estado desativado para zero. Trabalhou como um encanto ... Obrigado
Skywalker
excelente ideia, no entanto definir a imagem como nulo não funcionava para mim, eu tive que colocar um pequeno quadrado transparente de 20x20 como a imagem
Lena Bru
2

Caso o UIBarButtonItem tenha uma imagem em vez do texto, você pode fazer isso para ocultá-la: navigationBar.topItem.rightBarButtonItem.customView.alpha = 0.0;

Artem Goryaev
fonte
2

Alguns métodos auxiliares que pensei em compartilhar com base na resposta aceita pelo lnafziger, pois tenho várias barras de ferramentas e vários botões em cada um:

-(void) hideToolbarItem:(UIBarButtonItem*) button inToolbar:(UIToolbar*) toolbar{
    NSMutableArray *toolbarButtons = [toolbar.items mutableCopy];
    [toolbarButtons removeObject:button];
    [toolbar setItems:toolbarButtons animated:NO];
}

-(void) showToolbarItem:(UIBarButtonItem*) button inToolbar:(UIToolbar*) toolbar atIndex:(int) index{
    NSMutableArray *toolbarButtons = [toolbar.items mutableCopy];
    if (![toolbarButtons containsObject:button]){
        [toolbarButtons insertObject:button atIndex:index];
        [self setToolbarItems:toolbarButtons animated:YES];
    }
}
Guy Lowe
fonte
2

Você pode facilmente obter a visualização e ocultá-la dessa maneira

let view: UIView = barButtonItem.valueForKey("view") as! UIView
view.hidden = true
Titouan de Bailleul
fonte
2

Se você estiver usando o Swift 3

if (ShowCondition){
   self.navigationItem.rightBarButtonItem = self.addAsset_btn 
 } 
else {
   self.navigationItem.rightBarButtonItem = nil
 }
Museer Ahamad Ansari
fonte
2

Aqui está uma extensão que irá lidar com isso.

extension UIBarButtonItem {

    var isHidden: Bool {
        get {
            return tintColor == .clear
        }
        set {
            tintColor = newValue ? .clear : .white //or whatever color you want
            isEnabled = !newValue
            isAccessibilityElement = !newValue
        }
    }

}

USO:

myBarButtonItem.isHidden = true
Harris
fonte
1

Complementando a resposta de Eli Burke, se você UIBarButtonItemtiver uma imagem de plano de fundo em vez de um título, você pode usar o código:

-(void)toggleLogoutButton:(bool)show{
    if (show) {
        self.tabButton.style = UIBarButtonItemStyleBordered;
        self.tabButton.enabled = true;
        UIImage* imageMap = [UIImage imageNamed:@"btn_img.png"];
        [((UIButton *)[self.tabButton customView]) setBackgroundImage:imageMap forState:UIControlStateNormal];
    } else {
        self.tabButton.style = UIBarButtonItemStylePlain;
        self.tabButton.enabled = false;
        [((UIButton *)[self.tabButton customView]) setBackgroundImage:nil forState:UIControlStateNormal];
    }
}
Renato Lochetti
fonte
0

Você precisa manipular a matriz toolbar.items.

Aqui está um código que eu uso para ocultar e exibir um botão Concluído. Se o botão estiver na extremidade da barra de ferramentas ou entre outros botões, os outros botões se moverão; portanto, se você quiser que ele desapareça, coloque-o como o último botão em direção ao centro. Eu animar o botão mover para efeito, eu gosto bastante.

-(void)initLibraryToolbar {

    libraryToolbarDocumentManagementEnabled = [NSMutableArray   arrayWithCapacity:self.libraryToolbar.items.count];
    libraryToolbarDocumentManagementDisabled = [NSMutableArray arrayWithCapacity:self.libraryToolbar.items.count];
    [libraryToolbarDocumentManagementEnabled addObjectsFromArray:self.libraryToolbar.items];
    [libraryToolbarDocumentManagementDisabled addObjectsFromArray:self.libraryToolbar.items];
    trashCan = [libraryToolbarDocumentManagementDisabled objectAtIndex:3];
    mail = [libraryToolbarDocumentManagementDisabled objectAtIndex:5];
    [libraryToolbarDocumentManagementDisabled removeObjectAtIndex:1];
    trashCan.enabled = NO;
    mail.enabled = NO;
    [self.libraryToolbar setItems:libraryToolbarDocumentManagementDisabled animated:NO];

}

agora você pode usar o código a seguir para mostrar seu botão

[self.libraryToolbar setItems:libraryToolbarDocumentManagementEnabled animated:YES];
trashCan.enabled = YES;
mail.enabled = YES; 

ou ocultar seu botão

[self.libraryToolbar setItems:libraryToolbarDocumentManagementDisabled animated:YES];
trashCan.enabled = NO;
mail.enabled = NO;
Graham
fonte
0

No IB, se você deixar o título do botão em branco, ele não aparecerá (nunca inicializado?). Faço isso frequentemente durante o desenvolvimento durante as atualizações da interface do usuário, se quiser que um item do botão de barra temporariamente desapareça para uma compilação sem excluí-lo e descartar todas as referências de saída.

Isso não tem o mesmo efeito durante o tempo de execução, definir o título do botão como nulo não fará com que o botão inteiro desapareça. Desculpe, na verdade, não responde à sua pergunta, mas pode ser útil para alguns.

Editar: Este truque só funciona se o estilo do botão estiver definido como simples

pretzels1337
fonte
0

Vou adicionar minha solução aqui, pois ainda não a encontrei mencionada aqui. Eu tenho um botão dinâmico cuja imagem depende do estado de um controle. A solução mais simples para mim foi definir a imagem como nilse o controle não estivesse presente. A imagem era atualizada sempre que o controle era atualizado e, portanto, era ideal para mim. Só para ter certeza que eu também definir o enabledqueNO .

Definir a largura para um valor mínimo não funcionou no iOS 7.

mkko
fonte
0

Com crédito para @lnafziger, @MindSpiker, @vishal, et. al

O liner mais simples que cheguei para um único botão da barra direita (ou esquerda) é:

self.navigationItem.rightBarButtonItem = <#StateExpression#>
    ? <#StrongPropertyButton#> : nil;

Como em:

@interface MyClass()

@property (strong, nonatomic) IBOutlet UIBarButtonItem *<#StrongPropertyButton#>;

@end

@implementation

- (void) updateState
{
    self.navigationItem.rightBarButtonItem = <#StateExpression#>
        ? <#StrongPropertyButton#> : nil;
}

@end

Testei isso e funciona para mim (com o item do botão de barra forte conectado via IB).

Chris Conover
fonte
Isso funcionará se você tiver apenas um botão, mas se você tiver vários botões, precisará usar um método mais ao longo das linhas da minha resposta.
Lnfziger 26/04