Giữ một UIButton được chọn sau một lần chạm


90

Sau khi người dùng của tôi nhấp vào một nút, tôi muốn nút đó tiếp tục được đẩy trong thời gian tôi thực hiện thao tác mạng. Khi hoạt động mạng hoàn tất, tôi muốn nút quay lại trạng thái mặc định.

Tôi đã thử gọi - [UIButton setSelected:YES]ngay sau khi nhấn nút (với một cuộc gọi tương ứng tới - [UIButton setSelected:NO]sau khi kết thúc hoạt động mạng của tôi) nhưng dường như không hiệu quả. Điều tương tự nếu tôi gọi setHighlighted:.

Tôi cho rằng tôi có thể thử hoán đổi hình nền để biểu thị trạng thái đã chọn trong suốt thời gian hoạt động của mạng, nhưng điều đó có vẻ giống như một vụ hack. Bất kỳ đề xuất tốt hơn?

Đây là mã của tôi trông như thế nào:

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

Câu trả lời:


73

Bạn thiết lập các hình ảnh khác nhau UIControlStatestrên nút như thế nào? Bạn đang thiết lập một hình nền cho UIControlStateHighlightedcũng như UIControlStateSelected?

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

Nếu bạn đang đặt trạng thái đã chọn trên sự kiện chạm xuống nút thay vì chạm vào bên trong, nút của bạn sẽ thực sự ở trạng thái được đánh dấu + đã chọn, vì vậy bạn cũng muốn đặt điều đó.

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

Biên tập:

Để tổng hợp các nhận xét của tôi trong các nhận xét và để giải quyết mã bạn đã đăng ... bạn cần đặt hình nền của mình cho UIControltrạng thái đầy đủ mà bạn đang ở. Theo đoạn mã của bạn, trạng thái kiểm soát này sẽ bị tắt + được chọn + được đánh dấu trong suốt thời gian hoạt động của mạng. Điều này có nghĩa là bạn sẽ cần phải làm điều này:

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

Nếu bạn xóa highlighted = YES, thì bạn sẽ cần cái này:

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

Lấy tấm hình?


Trên thực tế, tôi tin rằng tôi đang làm những gì bạn đề nghị; Tôi chỉ làm điều đó thông qua Trình tạo giao diện. Tôi đã thêm mã mà tôi đang sử dụng vào câu hỏi của mình ở trên ... có lẽ điều đó sẽ làm sáng tỏ vấn đề? Hành vi tôi muốn là tôi muốn nút vẫn được chọn trong suốt thời gian hoạt động mạng của mình. Những gì tôi thấy là nút sẽ sáng khi chạm vào, sau đó sẽ biến mất khi chạm xong. Nút-bất cứ khi nào- được chọn. Tại sao điều này không có ý nghĩa gì đối với tôi, vì vậy tôi cảm thấy như tôi đang làm điều gì đó ngu ngốc. Tôi đã kiểm tra tất cả các kết nối IB của tôi và họ đang tốt ...
Greg Maletic

Tôi không tin rằng bạn có thể đặt hình nền cho trạng thái được đánh dấu + đã chọn trong Trình tạo giao diện, chỉ các trạng thái được đánh dấu và được chọn riêng biệt. Nếu nút của bạn ở trạng thái được đặt cả hai nút được đánh dấu và được chọn, tôi tin rằng nó sẽ mặc định là hình ảnh bình thường của bạn, không phải là hình ảnh được đánh dấu hoặc đã chọn. Từ mã của bạn, bạn đang thiết lập trạng thái của nút sao cho cả nút được chọn và được đánh dấu đều CÓ. CheckInButtonPushing có được kết nối với "Touch Up Inside" hay thứ gì khác không?
Bryan Henry

Có, nó được kết nối với "Touch Up Inside". Và nếu tôi xóa mã liên quan đến trạng thái 'được đánh dấu', nó vẫn không hoạt động. Trạng thái 'đã chọn' không bao giờ được hiển thị.
Greg Maletic

Ngoài ra, tại sao bạn lại tắt nút này? Điều đó thực sự có nghĩa là trạng thái nút bị tắt + đánh dấu + được chọn. Nếu bạn đã xóa cài đặt dòng được đánh dấu thành CÓ, thì bạn đã tắt + chọn, vì vậy bạn cần đặt hình ảnh cho trạng thái (UIControlStateDisabled | UIControlStateSelected).
Bryan Henry

Được rồi, đó là vấn đề. Khi tôi gỡ bỏ chức năng tắt, nó hoạt động như mong đợi. Cảm ơn! (Để trả lời câu hỏi của bạn, tôi đang vô hiệu hóa nút này vì tôi không muốn bất kỳ ai nhấn nó lần nữa trong khi hoạt động mạng đang diễn ra.)
Greg Maletic

30

Tôi có một cách dễ dàng hơn. Chỉ cần sử dụng "performanceSelector" với độ trễ 0 để thực hiện [button setHighlighted:YES]. Thao tác này sẽ thực hiện đánh dấu lại sau khi vòng chạy hiện tại kết thúc.

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

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

28

"Mọi thứ trở nên tốt hơn khi bạn bật nguồn"

    button.selected = !button.selected;

hoạt động hoàn hảo ... sau khi tôi kết nối ổ cắm với nút trong Trình tạo giao diện.

Bạn không cần setBackgroundImage: forState :, trình tạo cho phép bạn chỉ định hình ảnh nền (được thay đổi kích thước nếu cần) hoặc / và nền trước (không thay đổi kích thước).


27

Hãy thử sử dụng NSOperationQueue để đạt được điều này. Hãy thử mã như sau:

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

Hi vọng điêu nay co ich.


Đây là một giải pháp tuyệt vời, Roberto & Parth. Tuy nhiên, có một chi tiết nhỏ là bạn sẽ thỉnh thoảng thấy "nhấp nháy" nếu người dùng giữ ngón tay của mình trên nút. Có cách nào để ngăn chặn hiện tượng nhấp nháy?
Scott Lieberman

8

Sử dụng một khối để bạn không phải xây dựng một phương pháp hoàn toàn riêng biệt:

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

Cập nhật

Để rõ ràng, bạn vẫn cần phải đặt nền (hoặc hình ảnh bình thường) cho các trạng thái kết hợp cũng như các trạng thái thông thường như sbrocket đã nói trong câu trả lời được chấp nhận. Tại một thời điểm nào đó, nút của bạn sẽ được chọn và đánh dấu, và bạn sẽ không có hình ảnh cho điều đó trừ khi bạn làm điều gì đó như sau:

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

Nếu không, nút của bạn có thể quay trở lại hình ảnh UIControlStateNormal cho trạng thái được chọn ngắn + đánh dấu và bạn sẽ thấy một đèn flash.


FYI dispatch_get_current_queue()được cho là "không đáng tin cậy".
Jacob Relkin

1
Điều đó được nêu ở đâu? Giải pháp thay thế là gì?
Bob Spryn 14/09/12

Có ý nghĩa trong việc sử dụng dispatch_aftertrái ngược với dispatch_async?
Ilya

Vâng. dispatch_asynclà một lựa chọn tốt hơn.
Bob Spryn

4

Trong thời gian nhanh chóng, tôi đang làm như sau.

Tôi tạo một Lớp con UIButtonvà triển khai một thuộc tính tùy chỉnhstate

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
        }
    }

}

Hoạt động hoàn hảo cho tôi.


1

Tôi đã gặp sự cố tương tự trong đó tôi muốn có một nút để giữ cho nó nổi bật sau khi nhấp. Vấn đề là nếu bạn cố gắng sử dụng setHighlighted:YEShành động bên trong của bạn, nó sẽ đặt lại ngay sau khi bạn nhấp vào hành động,- (IBAction)checkInButtonPushed

Tôi đã giải quyết vấn đề này bằng cách sử dụng NSTimer như thế này

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

và sau đó gọi setHighlighted:YEStừ selectCurrentIndexphương thức của tôi . Tôi sử dụng các UIButtonTypeRoundedRectnút thông thường .


0

Tôi có một cách khác ... nếu bạn không muốn sử dụng hình ảnh và bạn muốn hiệu ứng của một nút được nhấn, Bạn có thể phân lớp Nút và đây là mã của tôi:

trong tệp .h:

@interface reservasButton : UIButton {

BOOL isPressed;
}
 @end

Trong tệp .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

Đây là một triển khai C # / MonoTouch (Xamarin.iOS) sử dụng các phương pháp được trình bày ở trên. Nó giả định rằng bạn đã thiết lập trạng thái hình ảnh Đánh dấu rồi, và định cấu hình các trạng thái đã chọn và đã chọn | được đánh dấu để sử dụng cùng một hình ảnh.

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;
        });
    });
};
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.