Збереження кнопки 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.