Как показать / скрыть UIBarButtonItem?

251

Я создал панель инструментов в IB с несколькими кнопками. Я хотел бы иметь возможность скрыть / показать одну из кнопок в зависимости от состояния данных в главном окне.

UIBarButtonItem не имеет скрытого свойства, и любые примеры, которые я нашел до сих пор для сокрытия их, включают установку кнопок навигационной панели в ноль, что я не думаю, что я хочу здесь делать, потому что мне может понадобиться снова показать кнопку (не упомянуть, что, если я подключу свою кнопку к IBOutlet, если я установлю это на ноль, я не уверен, как я получу это назад).

Саша
источник
Я просто отключил его и добавил метку доступности, сообщающую, что функция кнопки недоступна.
Даниэль Спрингер

Ответы:

263

Сохраните вашу кнопку в надежном магазине (давайте назовем ее myButton) и сделаем это, чтобы добавить / удалить ее:

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

Поскольку он хранится в розетке, вы сохраните ссылку на него, даже если его нет на панели инструментов.

lnafziger
источник
73
Чтобы это работало для моей правой кнопки в контроллере навигации, я использовал self.navigationItem.rightBarButtonItems и [self.navigationItem setRightBarButtonItems <prams>] вместо toolBarItems и setToolBarItems.
MindSpiker
@MindSpiker: Да, та же техника работает и для кнопок на панели навигации.
lnafziger
1
Должен ли я обнулить myButton в dealloc?
Ван Ду Тран
49
Или Apple может просто добавить скрытое свойство. -_-
GeneCode
217

Я знаю, что этот ответ опаздывает на этот вопрос. Тем не менее, это может помочь, если кто-то еще сталкивается с подобной ситуацией.

В iOS 7, чтобы скрыть элемент кнопки панели, мы можем использовать следующие два метода:

  • используйте SetTitleTextAttributes: - Это прекрасно работает с кнопками панели, такими как «Готово», «Сохранить» и т. д. Однако, это не работает с такими элементами, как «Добавить», «Корзина» и т. д. (по крайней мере, не для меня), поскольку они не являются текстами.
  • используйте TintColor: - Если у меня есть элемент кнопки панели под названием «deleteButton»: -

Чтобы скрыть кнопку, я использовал следующий код: -

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

Чтобы снова показать кнопку, я использовал следующий код: -

[self.deleteButton setEnabled:YES];
[self.deleteButton setTintColor:nil];
Максимум
источник
[self.navigationItem.rightBarButtonItem setEnabled: NO]; [self.navigationItem.rightBarButtonItem setTintColor: [UIColor clearColor]];
Леон
3
Для Swift: deleteButton.enabled = false; deleteButton.tintColor = UIColor.clearColor()отключить и скрыть, а deleteButton.enabled = true; deleteButton.tintColor = nilтакже включить и показать как обычно.
Unixmonkey
1
Мне нравится, что этот подход позволяет мне определить, отображать ли UIBarButton внутри этого класса. Причина, по которой она работает только с одной кнопкой, не сразу очевидна - это потому, что если вы скрываете кнопку таким образом, она все равно будет занимать место, поэтому у вас может быть пустой пробел, если у вас несколько кнопок.
SimplGy
Ваш первый подход был идеальным для меня. Я установил UIColor.clearдля UIControlState.disabledи может показать / скрыть кнопку с setEnabled. Конечно, как вы сказали, это работает только для текстовых кнопок.
fl034
Если я долго нажимаю на него, пока он не появится на большом изображении (вероятно, для доступности), то даже если для isEnabled установлено значение false, он все равно работает.
Даниэль Спрингер,
67

Вот простой подход:

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

Я только что запустил его на своем сетчатке iPad, а 0,01 достаточно мал, чтобы он не появлялся.

Дрю Розенберг
источник
13
Из всех решений это было быстрое, грязное и эффективное. Я также добавил barbuttItem.enabled = NO; так как я все еще мог заставить кнопку срабатывать, если бы нажал ее достаточно.
Stickley
1
Не работает для меня Я думал, что это потому, что я использовал кнопку «Добавить» с изображением «+», но я попробовал пользовательскую кнопку с текстом «Новый», и она все еще не исчезает. Активация меняется, поэтому я знаю, что мой код выполняется. Любые идеи? Обратите внимание, что эта кнопка создана в раскадровке и имеет переход, поэтому я не хочу заменять ее программной кнопкой
Rhubarb
19
Кажется, он не работает на панели инструментов контроллера навигации, но он работает для других панелей инструментов.
Дрю Розенберг
3
Это скрывает это, но это все еще отвечает на сигналы. Для меня это действует как невидимая кнопка.
Тибидабо
Если вы установили глобальный цвет оттенка с помощью этой строки self.window?.tintColor = APP_PRIMARY_COLORв appdelegate, то это не сработает
Mehul Thakkar
60

Можно скрыть кнопку на месте, не меняя ее ширину и не удаляя ее с панели. Если вы установите простой стиль, удалите заголовок и отключите кнопку, он исчезнет. Чтобы восстановить его, просто отмените ваши изменения.

-(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;
    }
}
Эли Берк
источник
2
Это сработало для меня, просто установив btn.title = nil. Я также включил настройку = НЕТ, на всякий случай ...
Pork 'n' Bunny
3
Установка для buttonItem.title значения nil у меня не работала в iOS7. Кнопка не появилась снова при ее установке. Однако, что работало, так это установив buttonItem.title = @ "";
Марк Knopper
42

Ниже мое решение, хотя я искал его для панели навигации.

navBar.topItem.rightBarButtonItem = nil;

Здесь «navBar» - это IBOutlet для NavigationBar в представлении в XIB. Здесь я хотел скрыть кнопку или показать ее в зависимости от некоторых условий. Так что я проверяю условие в «Если» и если true, я устанавливаю кнопку в ноль в методе viewDidLoad целевого представления.

Это может не относиться к вашей проблеме, но что-то похожее, если вы хотите скрыть кнопки на панели навигации

вишал дхаранкар
источник
Если вы хотите , чтобы позже установить rightBarButtonItemснова, убедитесь , что пункт кнопки сохраняется в сильном IBOutlet так , что он не освобожден , когда вы берете его на панели навигации.
конец
30

Для Swift 3 и Swift 4 вы можете сделать это, чтобы скрыть UIBarButtomItem:

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

И показать UIBarButtonItem:

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

На tintColorвы должны указать цвет происхождения , который вы используете дляUIBarButtomItem

pableiros
источник
2
Но это все равно займет место для этой кнопки.
Макале
22

В настоящее время я использую OS X Yosemite Developer Preview 7 и Xcode 6 beta 6 для iOS 7.1, и мне подходит следующее решение:

  • Создать аутлет для UINavigationItemи UIBarButtonItemс
  • Запустите следующий код, чтобы удалить

    [self.navItem setRightBarButtonItem:nil];
    [self.navItem setLeftBarButtonItem:nil];
  • Запустите следующие коды, чтобы снова добавить кнопки

    [self.navItem setRightBarButtonItem:deleteItem];
    [self.navItem setLeftBarButtonItem:addItem];
Олкай Эрташ
источник
Спасибо, это лучший метод, который я нашел. Просто убедитесь, что ваши ссылки на ваши кнопки сильны.
jyoung
Кроме того, имейте в виду, что это работает, только если у вас есть только одна кнопка. Пример удалит ВСЕ кнопки на этой стороне.
lnafziger
@jyoung Это сработало для меня, но почему это важно, если ссылка сильна? Я не пробовал другой способ, но обычно не устанавливал его таким образом, поскольку он не используется по умолчанию.
Роберт
@ Роберт Вы хотите использовать объект позже, поэтому вам нужно убедиться, что объект не будет собирать мусор, когда вы установите его на ноль. Если ничто иное не удерживало объект, когда вы сказали элементу панели кнопок, можно избавиться от него, то счетчик ссылок будет равен 0, и это будет сбор мусора.
15:27
14

Я использовал IBOutlets в своем проекте. Итак, мое решение было:

@IBOutlet weak var addBarButton: UIBarButtonItem!

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

И когда вам нужно будет снова показать эту панель, просто установите обратные свойства.

В Swift 3 вместо этого enableиспользуйте isEnableсвойство.

логово
источник
13

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

Дмитрий Семенюк
источник
12

iOS 8. UIBarButtonItem с пользовательским изображением. Пробовал много разных способов, большинство из них не помогало. Решение Макса setTintColorне меняло цвет. Я сам разобрался с этим, подумал, что он кому-нибудь пригодится.

Для сокрытия:

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

Для показа:

[self.navigationItem.rightBarButtonItem setEnabled:YES];
[self.navigationItem.rightBarButtonItem setImage:image];
Ринто Рафеил
источник
9

Попробуйте в Swift , не обновляйте, tintColorесли у вас есть какой-то дизайн для вашего UIBarButtonItem, например, размер шрифта в AppDelegate, он полностью изменит внешний вид вашей кнопки при отображении.

В случае текстовой кнопки, изменение заголовка может позволить вашей кнопке «исчезнуть».

if WANT_TO_SHOW {
    myBarButtonItem.enabled = true
    myBarButtonItem.title = "BUTTON_NAME"
}else{
    myBarButtonItem.enabled = false
    myBarButtonItem.title = ""
}
Джеффри Нео
источник
7

Я обнаружил еще одну морщинку в tintColorи isEnabledподход , предложенный Макс и другие - когда функция VoiceOver включена для обеспечения доступности и кнопка логически скрыты, доступность курсор будет по- прежнему сосредоточены на панели кнопок, и заявить , что он «серым» (то есть , потому что isEnabledЭТО установить в ложь). Подход в принятом ответе не страдает от этого побочного эффекта, но я обнаружил, что isAccessibilityElementпри работе с «сокрытием» кнопки было установлено значение false:

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

И затем, isAccessibilityElementвозвращаясь к значению true, когда «показывает» кнопку:

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

В моем случае не было проблем с тем, чтобы элемент панели кнопок занимал пространство, поскольку мы скрывали / отображали крайний левый элемент панели справа.

Эван Кирквуд
источник
6
@IBDesignable class AttributedBarButtonItem: UIBarButtonItem {

    var isHidden: Bool = false {

        didSet {

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

А теперь просто поменяйте isHiddenсобственность.

Бартломей Семанчик
источник
5

Совершенствование От @lnafziger ответ

Сохраните ваши кнопки в надежной розетке и сделайте это, чтобы скрыть / показать это:

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

При необходимости используйте ниже функцию.

[self showBarButtonItem:self.rightBarBtn1];
[self hideBarButtonItem:self.rightBarBtn1];
umakanta
источник
5

Просто установите barButton.customView = UIView()и увидите трюк

Джефф Аян
источник
Что делает этот ответ, так это позволяет всем гибким настройкам работать. Это на самом деле очень эффективный ответ. Вероятно, в сочетании с расширением было бы идеально.
Adrian_H
4

Нет способа «спрятать» UIBarButtonItem, вы должны удалить его из superView и добавить его обратно, когда вы захотите отобразить его снова.

Кайл Рихтер
источник
На самом деле это не так - метод, описанный Максом, работает хорошо.
северянин
1
nothernman - Макс на самом деле не правильно. На самом деле он не скрывает кнопку так, как большинство людей определяет «скрытие». Он просто делает его невидимым и отключает взаимодействие с пользователем. Кнопка все еще там и занимает место. Все сводится к тому, как вы хотите определить «скрыть», я верю, что дух первоначального вопроса заключался в том, чтобы фактически удалить / добавить его, а не просто сделать его невидимым.
Майкл Петерсон
4

Это длинный путь вниз по списку ответов, но на всякий случай, если кто-то захочет легко скопировать и вставить для быстрого решения, вот оно

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
источник
Неплохо, но вы должны указать UINavigationItem в качестве параметра, а не UIToolbar, потому что он просит скрыть UIBarButtonItem. Я изменил вашу функцию следующим образом: func hideToolbarItem (кнопка: UIBarButtonItem, с панелью инструментов Toolbar: UINavigationItem) {var toolbarButtons: [UIBarButtonItem] = toolbar.rightBarButtonItems! toolbarButtons.removeAtIndex (toolbarButtons.indexOf (button)!) toolbar.setRightBarButtonItems (toolbarButtons, animated: true)}, и это прекрасно работает
Kingalione
3

Один из способов сделать это - использовать initWithCustomView:(UIView *)свойство при выделении UIBarButtonItem. У подкласса UIViewбудет свойство скрывать / отображать.

Например:

1. Имейте то, UIButtonчто вы хотите скрыть / показать.

2. Сделайте UIButtonкак пользовательский вид. Подобно :

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

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

3. Вы можете скрыть / показать myButtonсозданное вами.[myButton setHidden:YES];

iNoob
источник
Тем не менее, он не будет закрывать промежуток между другими кнопками: когда он «скрыт», на панели инструментов будет пустая область.
lnafziger
@ lnafziger Да, это правда, но я не читал упоминание ОП о сокращении разрыва между кнопками, но это хороший момент, чтобы отметить, хотя.
iNoob
1
Спасибо, ваш ответ тоже полезен, но я думаю, что большинство людей, когда хотят скрыть кнопку на панели инструментов, хотят, чтобы она выглядела так, как будто ее там нет (без пустой области). Если это левый или правый, это не будет иметь большого значения.
lnafziger
Хорошие моменты, iNoob и Inafziger - я не упомянул об этом в любом случае, но да, я бы предпочел, чтобы не было пустого места.
Саша
3

Для версии Swift, вот код:

Для UINavigationBar:

self.navigationItem.rightBarButtonItem = nil

self.navigationItem.leftBarButtonItem = nil
Сохил Р. Мемон
источник
2

Установка цвета текста в прозрачный цвет, когда элемент панели кнопок отключен, вероятно, более чистый вариант. Там нет странностей, которые вы должны объяснить в комментарии. Также вы не уничтожаете кнопку, поэтому сохраняете все связанные с ней раскадровки.

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

Затем, когда вы захотите скрыть элемент панели кнопок, вы можете просто сделать:

self.navigationItem.rightBarButton.enabled = NO;

Жаль, что нет скрытых свойств, но это дает тот же результат.

puppybits
источник
1
У меня была кнопка внутри RightBarButtonItem. Поэтому я установил для его разрешения значение NO и изменил его изображение в отключенном состоянии на ноль. Работал как шарм ... Спасибо
Скайуокер
отличная идея, однако установка нулевого изображения для меня не сработала, мне пришлось поместить маленький прозрачный квадрат 20х20 как изображение
Лена Брю,
2

Если в UIBarButtonItem вместо текста есть изображение, вы можете сделать это, чтобы скрыть его: navigationBar.topItem.rightBarButtonItem.customView.alpha = 0.0;

Артем Горяев
источник
2

Некоторые вспомогательные методы, которыми я поделился, основываясь на принятом ответе lnafziger, так как у меня есть несколько панелей инструментов и несколько кнопок на каждой:

-(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];
    }
}
Гай Лоу
источник
2

Вы можете легко получить вид и скрыть это таким образом

let view: UIView = barButtonItem.valueForKey("view") as! UIView
view.hidden = true
Титуан де Байеул
источник
2

Если вы используете Swift 3

if (ShowCondition){
   self.navigationItem.rightBarButtonItem = self.addAsset_btn 
 } 
else {
   self.navigationItem.rightBarButtonItem = nil
 }
Музей Ахамад Ансари
источник
2

Вот расширение, которое справится с этим.

extension UIBarButtonItem {

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

}

ИСПОЛЬЗОВАНИЕ:

myBarButtonItem.isHidden = true
Харрис
источник
1

В дополнение к ответу Эли Бурка, если у вас UIBarButtonItemесть фоновое изображение вместо заголовка, вы можете использовать код:

-(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];
    }
}
Ренато Лохетти
источник
0

Вам нужно манипулировать массивом toolbar.items.

Вот код, который я использую, чтобы скрыть и отобразить кнопку Готово. Если ваша кнопка находится на крайнем краю панели инструментов или между другими кнопками, другие ваши кнопки будут перемещаться, поэтому, если вы хотите, чтобы ваша кнопка просто исчезла, поместите эту кнопку как последнюю кнопку к центру. Я оживляю движение кнопки для эффекта, мне это очень нравится.

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

}

так что теперь можете использовать следующий код, чтобы показать свою кнопку

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

или скрыть свою кнопку

[self.libraryToolbar setItems:libraryToolbarDocumentManagementDisabled animated:YES];
trashCan.enabled = NO;
mail.enabled = NO;
Грэхем
источник
0

В IB, если вы оставите название кнопки пустым, оно не появится (никогда не инициализируется?). Я делаю это часто во время разработки во время обновлений пользовательского интерфейса, если я хочу, чтобы элемент панели кнопок временно исчезал для сборки, не удаляя ее и не удаляя все ссылки на выходы.

Это не дает того же эффекта во время выполнения, установка названия кнопки на ноль не приведет к исчезновению всей кнопки. Извините, на самом деле не отвечает на ваш вопрос, но может быть полезным для некоторых.

Редактировать: этот трюк работает, только если стиль кнопки установлен равным

pretzels1337
источник
0

Я добавлю свое решение здесь, так как я еще не нашел упомянутое здесь. У меня есть динамическая кнопка, изображение которой зависит от состояния одного элемента управления. Самым простым решением для меня было установить изображение, nilесли элемент управления отсутствует. Изображение обновлялось каждый раз, когда обновлялся элемент управления, и, таким образом, это было оптимальным для меня. Просто чтобы убедиться , что я также установить enabledв NO.

Установка ширины в минимальное значение не работает на iOS 7.

mkko
источник
0

С благодарностью @lnafziger, @MindSpiker, @vishal, et. аль,

Простейший вкладыш, к которому я пришел для одной правой (или левой) кнопки панели:

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

Как в:

@interface MyClass()

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

@end

@implementation

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

@end

Я проверил это, и оно работает для меня (с элементом кнопки сильной панели, подключенным через IB).

Крис Коновер
источник
Это будет работать, если у вас есть только одна кнопка, но если у вас есть несколько кнопок, вам нужно будет использовать метод больше в соответствии с моим ответом.
lnafziger