Tetap memilih UIButton setelah satu sentuhan

90

Setelah pengguna saya mengklik sebuah tombol, saya ingin tombol tersebut tetap ditekan selama saya melakukan operasi jaringan. Ketika operasi jaringan selesai, saya ingin tombol tersebut kembali ke keadaan defaultnya.

Saya sudah mencoba menelepon - [UIButton setSelected:YES]tepat setelah tombol ditekan (dengan panggilan yang sesuai ke - [UIButton setSelected:NO]setelah operasi jaringan saya selesai) tetapi sepertinya tidak melakukan apa-apa. Hal yang sama jika saya menelepon setHighlighted:.

Saya kira saya bisa mencoba menukar gambar latar belakang untuk menunjukkan status yang dipilih selama operasi jaringan, tetapi itu sepertinya hack. Ada saran yang lebih baik?

Inilah tampilan kode saya:

- (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;
}
Greg Maletic
sumber

Jawaban:

73

Bagaimana Anda mengatur gambar untuk perbedaan UIControlStatespada tombol? Anda menetapkan gambar latar belakang untuk UIControlStateHighlightedserta UIControlStateSelected?

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

Jika Anda mengatur status yang dipilih pada acara touch down tombol daripada menyentuh di dalam, tombol Anda akan benar-benar dalam status yang disorot + dipilih, jadi Anda juga ingin mengaturnya.

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

Edit:

Untuk meringkas komentar saya di komentar dan untuk mengatasi kode yang Anda posting ... Anda perlu mengatur gambar latar belakang Anda untuk UIControlkeadaan penuh Anda saat ini. Menurut potongan kode Anda, status kontrol ini akan dinonaktifkan + dipilih + disorot selama operasi jaringan. Ini berarti Anda perlu melakukan ini:

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

Jika Anda menghapus highlighted = YES, maka Anda akan membutuhkan ini:

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

Dapatkan fotonya?

Bryan Henry
sumber
Akibatnya, saya yakin saya melakukan apa yang Anda sarankan; Saya hanya melakukannya melalui Interface Builder. Saya menambahkan kode yang saya gunakan untuk pertanyaan saya di atas ... mungkin itu akan menjelaskan masalah ini? Perilaku yang saya inginkan adalah saya ingin tombol tetap dipilih selama operasi jaringan saya. Yang saya lihat adalah tombolnya menyorot saat disentuh, lalu sorotan hilang saat disentuh. Tombol -tidak pernah- dipilih. Mengapa ini tidak berhasil tidak masuk akal bagi saya, jadi saya merasa seperti melakukan sesuatu yang bodoh. Saya sudah memeriksa semua koneksi IB saya dan mereka bagus ...
Greg Maletic
Saya tidak yakin Anda dapat menyetel gambar latar belakang untuk status yang disorot + dipilih di Interface Builder, hanya status yang disorot dan dipilih secara terpisah. Jika tombol Anda dalam keadaan yang disorot dan dipilih sama-sama disetel, saya yakin itu akan default ke gambar normal Anda, bukan gambar yang disorot atau dipilih. Dari kode Anda, Anda menyetel status tombol sedemikian rupa sehingga baik yang dipilih maupun yang disorot adalah YA. Apakah checkInButtonPushed terhubung ke "Touch Up Inside" atau yang lainnya?
Bryan Henry
Ya, itu terhubung ke "Touch Up Inside". Dan jika saya menghapus kode yang terkait dengan status 'disorot', itu masih tidak berfungsi. Status 'terpilih' tidak pernah ditampilkan.
Greg Maletic
Juga, mengapa Anda menonaktifkan tombolnya? Itu sebenarnya berarti bahwa status tombol dinonaktifkan + disorot + dipilih. Jika Anda menghapus pengaturan garis yang disorot ke YES, maka Anda telah menonaktifkan + dipilih, jadi Anda perlu mengatur gambar untuk status (UIControlStateDisabled | UIControlStateSelected).
Bryan Henry
Oke, itulah masalahnya. Ketika saya mengeluarkan fungsionalitas penonaktifan, itu berfungsi seperti yang diharapkan. Terima kasih! (Untuk menjawab pertanyaan Anda, saya menonaktifkan tombol karena saya tidak ingin ada yang menekannya lagi saat operasi jaringan sedang berlangsung.)
Greg Maletic
30

Saya memiliki cara yang lebih mudah. Cukup gunakan "performSelector" dengan 0 penundaan untuk melakukan [button setHighlighted:YES]. Ini akan melakukan penyorotan ulang setelah runloop saat ini berakhir.

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

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

"Semuanya menjadi lebih baik saat Anda menyalakan"

    button.selected = !button.selected;

bekerja dengan sempurna ... setelah saya menghubungkan stopkontak ke tombol di Interface Builder.

Anda tidak perlu setBackgroundImage: forState :, pembuat memungkinkan Anda menentukan gambar latar belakang (diubah ukurannya jika perlu) atau / dan latar depan (tidak diubah ukurannya).

18446744073709551615
sumber
27

Coba gunakan NSOperationQueue untuk mencapai ini. Coba kode sebagai berikut:

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

Semoga ini membantu.

roberto.buratti
sumber
Ini adalah solusi yang bagus, Roberto & Parth. Namun, satu detail kecil, adalah sesekali Anda akan melihat "kedipan" jika pengguna menekan tombol dengan jarinya. Apakah ada cara untuk mencegah flicker?
Scott Lieberman
8

Gunakan satu blok sehingga Anda tidak perlu membuat metode terpisah secara keseluruhan:

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

Memperbarui

Untuk lebih jelasnya Anda masih perlu mengatur latar belakang (atau gambar normal) untuk status kombinasi serta yang biasa seperti kata sbrocket dalam jawaban yang diterima. Pada titik tertentu tombol Anda akan dipilih dan disorot, dan Anda tidak akan memiliki gambar untuk itu kecuali Anda melakukan sesuatu seperti ini:

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

Jika tidak, tombol Anda dapat kembali ke gambar UIControlStateNormal untuk status singkat yang dipilih + disorot dan Anda akan melihat flash.

Bob Spryn
sumber
FYI dispatch_get_current_queue()dinyatakan sebagai "tidak dapat diandalkan".
Jacob Relkin
1
Dimanakah itu dinyatakan? Apa alternatifnya?
Bob Spryn
Apakah ada signifikansi dalam menggunakan dispatch_aftersebagai lawan dispatch_async?
Ilya
Ya. dispatch_asyncadalah pilihan yang lebih baik.
Bob Spryn
4

Dengan cepat saya melakukannya seperti berikut ini.

Saya membuat Subkelas UIButtondan menerapkan properti khususstate

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

}

Bekerja dengan sempurna untuk saya.

Eike
sumber
1

Saya memiliki masalah serupa di mana saya menginginkan tombol untuk tetap menyorotnya setelah diklik. Masalahnya adalah jika Anda mencoba menggunakan setHighlighted:YEStindakan klik di dalam Anda, tindakan itu akan disetel ulang tepat setelah Anda mengklik tindakan,- (IBAction)checkInButtonPushed

Saya menyelesaikan ini dengan menggunakan NSTimer seperti ini

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

dan kemudian memanggil setHighlighted:YESdari selectCurrentIndexmetode saya . Saya menggunakan UIButtonTypeRoundedRecttombol biasa .

fredrik
sumber
0

Saya punya cara lain ... jika Anda tidak ingin menggunakan gambar, dan Anda ingin efek tombol yang ditekan, Anda dapat membuat subkelas Tombol dan inilah kode saya:

di File .h:

@interface reservasButton : UIButton {

BOOL isPressed;
}
 @end

Di File .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;

     }


 } `
Pach
sumber
0

Berikut adalah implementasi C # / MonoTouch (Xamarin.iOS) menggunakan pendekatan yang disajikan di atas. Ini mengasumsikan Anda telah menyetel status gambar yang Disorot, dan mengkonfigurasi status yang dipilih dan dipilih | yang disorot untuk menggunakan gambar yang sama.

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;
        });
    });
};
t9mike
sumber