Збереження кнопки UIB вибраною після дотику


90

Після того, як користувач натисне кнопку, я хотів би, щоб ця кнопка залишалася натиснутою протягом часу, коли я виконую мережеву операцію. Коли мережева операція завершиться, я хочу, щоб кнопка повернулася до стану за замовчуванням.

Я спробував зателефонувати - [UIButton setSelected:YES]одразу після натискання кнопки (з відповідним викликом - [UIButton setSelected:NO]після закінчення моєї мережі), але, здається, це нічого не робить. Те саме, якщо я зателефоную setHighlighted:.

Я гадаю, я міг би спробувати поміняти фонове зображення, щоб позначити вибраний стан на час роботи мережі, але це здається хакерством. Будь-які кращі пропозиції?

Ось як виглядає мій код:

- (IBAction)checkInButtonPushed
{
    self.checkInButton.enabled = NO;
    self.checkInButton.selected = YES;
    self.checkInButton.highlighted = YES;
    [self.checkInActivityIndicatorView startAnimating];
    [CheckInOperation startWithPlace:self.place delegate:self];
}

- (void)checkInCompletedWithNewFeedItem:(FeedItem*)newFeedItem wasNewPlace:(BOOL)newPlace possibleError:(NSError*)error;
{
    [self.checkInActivityIndicatorView stopAnimating];
    self.checkInButton.enabled = YES;
    self.checkInButton.selected = NO;
    self.checkInButton.highlighted = NO;
}

Відповіді:


73

Як ви налаштовуєте зображення для різних UIControlStatesна кнопці? Налаштовуєте ви фонове зображення для UIControlStateHighlightedяк UIControlStateSelected?

UIImage *someImage = [UIImage imageNamed:@"SomeResource.png"];
[button setBackgroundImage:someImage forState:UIControlStateHighlighted];
[button setBackgroundImage:someImage forState:UIControlStateSelected];

Якщо ви встановлюєте вибраний стан на події натискання кнопки, а не торкаєтесь всередині, ваша кнопка фактично буде у виділеному + вибраному стані, тому вам потрібно буде встановити і це.

[button setBackgroundImage:someImage forState:(UIControlStateHighlighted|UIControlStateSelected)];

Редагувати:

Щоб підсумувати мої зауваження в коментарях та звернутися до коду, який ви опублікували ... вам потрібно встановити фонові зображення для повного UIControlстану, в якому ви перебуваєте. Відповідно до вашого фрагмента коду, цей стан управління буде вимкнено + вибрано + виділено на час роботи мережі. Це означає, що вам потрібно буде зробити це:

[button setBackgroundImage:someImage forState:(UIControlStateDisabled|UIControlStateHighlighted|UIControlStateSelected)];

Якщо ви видалите highlighted = YES, то вам знадобиться це:

[button setBackgroundImage:someImage forState:(UIControlStateDisabled|UIControlStateSelected)];

Отримати зображення?


По суті, я вважаю, що я роблю те, що ви пропонуєте; Я просто роблю це через Interface Builder. Я додав код, який використовую, до свого вищезазначеного питання ... можливо, це могло б пролити світло на проблему? Я хочу, щоб кнопка залишалася обраною протягом моєї роботи в мережі. Я бачу, що кнопка підсвічує при дотику, а потім виділення зникає, коли торкання закінчено. Буде вибрано кнопку -неколи-. Чому це не спрацює, для мене немає сенсу, тому я відчуваю, що роблю щось дурне. Я перевірив усі свої зв’язки з ІБ, і вони хороші ...
Грег Малетич

Я не вірю, що ви можете встановити фонове зображення для виділеного + вибраного стану у Interface Builder, лише виділених та вибраних станів окремо. Якби ваша кнопка була в такому стані, що для виділеного та вибраного були встановлені обидва, я вважаю, що за замовчуванням це буде звичайне зображення, а не виділене чи вибране зображення. З вашого коду ви встановлюєте стан кнопки таким чином, щоб і вибрані, і виділені були ТАК. CheckInButtonPushed підключено до "Touch Up Inside" чи щось інше?
Брайан Генрі

Так, він підключений до "Touch Up Inside". І якщо я видалю код, пов’язаний зі станом «виділеного», він все одно не працює. "Вибраний" стан ніколи не відображається.
Грег Малетич

Крім того, чому ви відключаєте кнопку? Це насправді означало б, що стан кнопки вимкнено + виділено + вибрано. Якщо ви видалили параметр рядка, виділений YES, то ви вимкнули + вибраний, тому вам потрібно встановити зображення для стану (UIControlStateDisabled | UIControlStateSelected).
Брайан Генрі,

Гаразд, це була проблема. Коли я вимкнув функцію відключення, вона працювала, як очікувалося. Дякую! (Щоб відповісти на ваше запитання, я відключаю цю кнопку, бо не хочу, щоб хтось натискав її ще раз, поки триває робота мережі.)
Грег Малетич

30

У мене простіший спосіб. Просто використовуйте "performSelector" із затримкою 0 для виконання [button setHighlighted:YES]. Це призведе до повторного виділення після закінчення поточного циклу.

- (IBAction)buttonSelected:(UIButton*)sender {
    NSLog(@"selected %@",sender.titleLabel.text);
    [self performSelector:@selector(doHighlight:) withObject:sender afterDelay:0];
}

- (void)doHighlight:(UIButton*)b {
    [b setHighlighted:YES];
}

27

"Усе стає краще, коли ви вмикаєте живлення"

    button.selected = !button.selected;

працює ідеально ... після того, як я підключив розетку до кнопки в Interface Builder.

Вам не потрібно встановлювати BackBackgroundImage: forState :, конструктор дозволяє вказати фон (зображення змінюється за необхідності) або / і зображення переднього плану (не змінюючи розмір).


27

Спробуйте за допомогою NSOperationQueue досягти цього. Спробуйте код наступним чином:

[[NSOperationQueue mainQueue] addOperationWithBlock:^{
    theButton.highlighted = YES;
}];

Сподіваюся, це допомагає.


Це чудове рішення, Roberto & Parth. Однак одна невелика деталь полягає в тому, що ви іноді бачите «мерехтіння», якщо користувач тримає палець на кнопці. Чи є спосіб запобігти мерехтінню?
Скотт Ліберман

8

Використовуйте блок, щоб вам не потрібно було будувати цілком окремий метод:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0), dispatch_get_main_queue(), ^{
    theButton.highlighted = YES;
});

Оновлення

Щоб бути чітким, вам все одно потрібно встановити фон (або звичайне зображення) для станів комбінації, а також звичайних, як це пише sbrocket у прийнятій відповіді. У якийсь момент ваша кнопка буде виділена і виділена, і у вас не буде зображення для цього, якщо ви не зробите щось подібне:

[button setBackgroundImage:someImage forState (UIControlStateHighlighted|UIControlStateSelected)];

В іншому випадку ваша кнопка може повернутися до зображення UIControlStateNormal для короткого вибраного + виділеного стану, і ви побачите спалах.


FYI dispatch_get_current_queue()заявляється як "ненадійний".
Jacob Relkin

1
Де це сказано? Яка альтернатива?
Боб Спрін,

Чи є значення у використанні dispatch_afterна відміну від dispatch_async?
Ілля

Так. dispatch_asyncє кращим вибором.
Боб Спрін,

3

Я швидко роблю це, як показано нижче.

Я створюю підклас UIButtonта реалізую користувацьку властивістьstate

class ActiveButton: UIButton {

    private var _active = false
    var active:Bool {
        set{
            _active = newValue
            updateState()
        }
        get{
            return _active
        }
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.addTarget(self, action: #selector(ActiveButton.touchUpInside(_:)), forControlEvents: .TouchUpInside)
    }

    func touchUpInside(sender:UIButton) {
        active = !active
    }

    private func updateState() {
        NSOperationQueue.mainQueue().addOperationWithBlock {
            self.highlighted = self.active
        }
    }

}

Мені чудово підходить.


1

У мене була подібна проблема, коли я хотів, щоб кнопка зберегла її виділення після натискання. Проблема полягає в тому, що якщо ви спробуєте використовувати setHighlighted:YESвсередині дії натискання, вона скинеться відразу після натискання,- (IBAction)checkInButtonPushed

Я вирішив це, використовуючи такий NSTimer

NSTimer *timer;
timer = [NSTimer scheduledTimerWithTimeInterval: 0.01
                                         target: self
                                       selector: @selector(selectCurrentIndex)
                                       userInfo: nil
                                        repeats: NO];

а потім зателефонувати setHighlighted:YESз мого selectCurrentIndexметоду. Я використовую звичайні UIButtonTypeRoundedRectкнопки.


0

У мене є інший спосіб ... якщо ви не хочете використовувати зображення, і вам потрібен ефект натиснутої кнопки, ви можете підкласувати кнопку, і ось мій код:

у файлі .h:

@interface reservasButton : UIButton {

BOOL isPressed;
}
 @end

У файлі .m:

#import <QuartzCore/QuartzCore.h>


 @implementation reservasButton

 -(void)setupView {  //This is for Shadow

    self.layer.shadowColor = [UIColor blackColor].CGColor;
    self.layer.shadowOpacity = 0.5; 
    self.layer.shadowRadius = 1;    
    self.layer.shadowOffset = CGSizeMake(2.0f, 2.0f); //comment
    //   self.layer.borderWidth = 1;
    self.contentVerticalAlignment   = UIControlContentVerticalAlignmentCenter;
    self.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;

    // [self setBackgroundColor:[UIColor whiteColor]];

    //  self.opaque = YES;


}

-(id)initWithFrame:(CGRect)frame{
    if((self = [super initWithFrame:frame])){
        [self setupView];
    }

    return self;
}

-(id)initWithCoder:(NSCoder *)aDecoder{
    if((self = [super initWithCoder:aDecoder])){
        [self setupView];
    }

    return self;
}

//Here is the important code

 -(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{


  if (isPressed == FALSE) {

      self.contentEdgeInsets = UIEdgeInsetsMake(1.0,1.0,-1.0,-1.0);
      self.layer.shadowOffset = CGSizeMake(1.0f, 1.0f);
      self.layer.shadowOpacity = 0.8;

      [super touchesBegan:touches withEvent:event];

      isPressed = TRUE;

     }
     else {

         self.contentEdgeInsets = UIEdgeInsetsMake(0.0,0.0,0.0,0.0);
         self.layer.shadowOffset = CGSizeMake(2.0f, 2.0f);
         self.layer.shadowOpacity = 0.5;

         [super touchesEnded:touches withEvent:event];

         isPressed = FALSE;

     }


 } `

0

Ось реалізація C # / MonoTouch (Xamarin.iOS) з використанням підходів, представлених вище. Передбачається, що ви вже встановили стан виділеного зображення та налаштовуєте вибрані та виділені | виділені стани на використання одного і того ж зображення.

var selected = button.BackgroundImageForState(UIControlState.Highlighted);
button.SetBackgroundImage(selected, UIControlState.Selected);
button.SetBackgroundImage(selected, UIControlState.Selected | UIControlState.Highlighted);
button.TouchUpInside += delegate
{
    NSTimer.CreateScheduledTimer(TimeSpan.FromMilliseconds(0), delegate
    {
        button.Highlighted = true;
        NSTimer.CreateScheduledTimer(TimeSpan.FromMilliseconds(200), delegate
        {
            button.Highlighted = false;
        });
    });
};
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.