Soru Segmented kontrol düğmesindeki bir segmentin tekrar tıklanıncaya kadar kalıcı olarak nasıl kaldırılır


Benim bir UISegmentedControl 4 segmentli. Seçildiğinde, selected state. Aynı segment tekrar tıklandığında, deselect itself. Bunu nasıl başarabilirim?


29
2017-07-15 11:05


Menşei




Cevaplar:


Dan beri UISegmentedControl seçili olmayan bir segment seçildiğinde sadece bir eylem gönderir, alt sınıfa ihtiyacınız vardır UISegmentedControl Dokunma işleminde küçük bir değişiklik yapmak için. Bu sınıfı kullanıyorum:

@implementation MBSegmentedControl

// this sends a value changed event even if we reselect the currently selected segment
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSInteger current = self.selectedSegmentIndex;
    [super touchesBegan:touches withEvent:event];
    if (current == self.selectedSegmentIndex) {
        [self sendActionsForControlEvents:UIControlEventValueChanged];
    }
}

@end

Şimdi alacaksın UIControlEventValueChanged Segment zaten seçilmiş olsa bile olaylar. Sadece geçerli endeksi bir değişkene kaydedin ve eylemde karşılaştırın. Eğer iki endeks eşleşirse, dokunulan bölümün seçimini kaldırmanız gerekir.

// _selectedSegmentIndex is an instance variable of the view controller

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    _selectedSegmentIndex = self.segment.selectedSegmentIndex;
}

- (IBAction)segmentChanged:(UISegmentedControl *)sender {
    if (sender.selectedSegmentIndex == _selectedSegmentIndex) {
        NSLog(@"Segment %d deselected", sender.selectedSegmentIndex);
        sender.selectedSegmentIndex =  UISegmentedControlNoSegment;
        _selectedSegmentIndex = UISegmentedControlNoSegment;
    }
    else {
        NSLog(@"Segment %d selected", sender.selectedSegmentIndex);
        _selectedSegmentIndex = sender.selectedSegmentIndex;
    }
}

iOS 7, UISegmentedControl için dokunuşların nasıl ele alınacağını değiştirdi. SelectedSegmentIndex şu anda değiştirildi touchesEnded:.

Bu yüzden güncellenmiş Alt Sınıf şöyle görünmelidir:

@implementation MBSegmentedControl

+ (BOOL)isIOS7 {
    static BOOL isIOS7 = NO;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSInteger deviceSystemMajorVersion = [[[[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:@"."] objectAtIndex:0] integerValue];
        if (deviceSystemMajorVersion >= 7) {
            isIOS7 = YES;
        }
        else {
            isIOS7 = NO;
        }
    });
    return isIOS7;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSInteger previousSelectedSegmentIndex = self.selectedSegmentIndex;
    [super touchesBegan:touches withEvent:event];
    if (![[self class] isIOS7]) {
        // before iOS7 the segment is selected in touchesBegan
        if (previousSelectedSegmentIndex == self.selectedSegmentIndex) {
            // if the selectedSegmentIndex before the selection process is equal to the selectedSegmentIndex
            // after the selection process the superclass won't send a UIControlEventValueChanged event.
            // So we have to do this ourselves.
            [self sendActionsForControlEvents:UIControlEventValueChanged];
        }
    }
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    NSInteger previousSelectedSegmentIndex = self.selectedSegmentIndex;
    [super touchesEnded:touches withEvent:event];
    if ([[self class] isIOS7]) {
        // on iOS7 the segment is selected in touchesEnded
        if (previousSelectedSegmentIndex == self.selectedSegmentIndex) {
            [self sendActionsForControlEvents:UIControlEventValueChanged];
        }
    }
}

@end

Swift 2.2 sürümü, sorun Grzegorz sorunu giderildi.

class ReselectableSegmentedControl: UISegmentedControl {
    @IBInspectable var allowReselection: Bool = true

    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        let previousSelectedSegmentIndex = self.selectedSegmentIndex
        super.touchesEnded(touches, withEvent: event)
        if allowReselection && previousSelectedSegmentIndex == self.selectedSegmentIndex {
            if let touch = touches.first {
                let touchLocation = touch.locationInView(self)
                if CGRectContainsPoint(bounds, touchLocation) {
                    self.sendActionsForControlEvents(.ValueChanged)
                }
            }
        }
    }
}

Swift 3.0, aşağıdaki gibi görünmesi için düzeltmeyi değiştirir:

class MyDeselectableSegmentedControl: UISegmentedControl {
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        let previousIndex = selectedSegmentIndex

        super.touchesEnded(touches, with: event)

        if previousIndex == selectedSegmentIndex {
            let touchLocation = touches.first!.location(in: self)

            if bounds.contains(touchLocation) {
                sendActions(for: .valueChanged)
            }
        }
    }
}

84
2017-07-15 11:17



Mükemmel çözüm! - Pradeep Rajkumar
Günümü, bunun için iOS 7 güncellemesiyle kurtardınız. - CommaToast
Bu cevap, iOS7'nin piyasaya sürülmesinden sonra ikinci kez bana yardımcı oldu. Tekrar kışkırtmalıyım. - Alyoshak
Ayrıca, bu alt sınıftaki seçim iptal kodunu ekleyerek de kapsülleyebilirsiniz. self.selectedSegmentIndex = UISegmentedControlNoSegment; önce [self sendActionsForControlEvents:UIControlEventValueChanged]; - Mike Pollard
@MikePollard Bu aslında çok iyi bir fikir. - Matthias Bauch


Burada, UISegmentControl'e dokunarak seçimi iptal etmeyi denediğinizde ve daha sonra dışarıya dokunarak bitirmeyi denediğinizde, yine de seçimin iptal edilmesini sağlayan bir sorun düzeltildi.

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint locationPoint = [[touches anyObject] locationInView:self];
CGPoint viewPoint = [self convertPoint:locationPoint fromView:self];
if ([self pointInside:viewPoint withEvent:event]) {
    int oldValue = self.selectedSegmentIndex;
    [super touchesEnded:touches withEvent:event];
    if (oldValue == self.selectedSegmentIndex)
    {
        [super setSelectedSegmentIndex:UISegmentedControlNoSegment];
        [self sendActionsForControlEvents:UIControlEventValueChanged];
    }
}
}

6
2018-01-30 14:54



[self pointInside:withEvent] bölümlenmiş kontrolün görünür boyutlarını kullanır. Bunu kullanıp içeriye dokunursam serbest bırakmadan önce biraz dışarı doğru sürükleyin, parmağımın hala açık olduğu gibi segmenti açık maviye bırakır ve olayı göndermez. Noktanın içinde olup olmadığını görmek için, kontrol için hitTest bölgesini tanımanın bir yolu var mı? - LavaSlider


Aşağıdaki ile yapabilirsiniz (teşekkür ederim Grzegorz'un cevabı ve Matthias'ın cevabı):

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    NSInteger previousSelectedSegmentIndex = self.selectedSegmentIndex;

    [super touchesEnded:touches withEvent:event];

    CGPoint locationPoint = [[touches anyObject] locationInView:self];
    CGPoint viewPoint = [self convertPoint:locationPoint fromView:self];
    if ([self pointInside:viewPoint withEvent:event] && previousSelectedSegmentIndex == self.selectedSegmentIndex) {
        self.selectedSegmentIndex = UISegmentedControlNoSegment;
        [self sendActionsForControlEvents:UIControlEventValueChanged];
    }
}

Açık kaynaklı (MIT Lisanslı) bir sınıf yaptım STASegmentedControl (ve iOS 7+'yi destekler), bu işleve (ve daha fazlasına) sahip olan bu işlevselliğe sahiptir.


2
2018-04-28 05:17





Çok yararlı! Teşekkür ederim! Projem için etkinlikler üzerinde biraz daha fazla kontrol istedim, bu yüzden Matthias'ın cevabını "Değer değiştirilmemiş" bir olay göndermek için uyarladım. Bir örnek koydum GitHub.

Ayrıca @ Grzegorz'un düzeltmesini de ekledim, böylece kullanıcı parmağını parçalı kontrolün dışına sürüklerse düzgün davranır.


1
2018-04-02 01:10





İşte IOS Sürümünden bağımsız bir çözüm. Davranışın kendisini seçiyor.

@interface CustomSegmentedControl : UISegmentedControl
@end




@implementation CustomSegmentedControl{


BOOL _touchBegan;
BOOL _reactOnTouchBegan;
}



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

    _touchBegan = YES;

    NSInteger previousSelectedSegmentIndex = self.selectedSegmentIndex;
    [super touchesBegan:touches withEvent:event];
    if (_reactOnTouchBegan) {
        // before iOS7 the segment is selected in touchesBegan
        if (previousSelectedSegmentIndex == self.selectedSegmentIndex) {
            [self sendActionsForControlEvents:UIControlEventValueChanged];
        }
    }
}


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

    _touchBegan = NO;

    NSInteger previousSelectedSegmentIndex = self.selectedSegmentIndex;
    [super touchesEnded:touches withEvent:event];
    if (!_reactOnTouchBegan) {
        CGPoint locationPoint = [[touches anyObject] locationInView:self];
        CGPoint viewPoint = [self convertPoint:locationPoint fromView:self];
        if ([self pointInside:viewPoint withEvent:event]) {
            // on iOS7 the segment is selected in touchesEnded
            if (previousSelectedSegmentIndex == self.selectedSegmentIndex) {
                [self sendActionsForControlEvents:UIControlEventValueChanged];
            }
        }
    }
}


- (void)sendActionsForControlEvents:(UIControlEvents)controlEvents {
    if(controlEvents == UIControlEventValueChanged){
        _reactOnTouchBegan = _touchBegan;
    }
    [super sendActionsForControlEvents:controlEvents];
}


@end

1
2017-07-30 11:27





@Matthias Bauch tarafından yayınlanan cevaba referans olarak. Bende küçük değişiklikler yapmalıydım Swift 2.2 Xcode'ta 7.3:

class ReselectableSegmentedControl: UISegmentedControl {
    @IBInspectable var allowReselection: Bool = true
    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        let previousSelectedSegmentIndex = self.selectedSegmentIndex
        super.touchesEnded(touches, withEvent: event)
        if allowReselection && previousSelectedSegmentIndex == self.selectedSegmentIndex {
            if let touch = touches.first {
                let touchLocation = touch.locationInView(self)
                if CGRectContainsPoint(bounds, touchLocation) {
                    self.sendActionsForControlEvents(.ValueChanged)
                }
            }
        }
    }
}

1
2017-08-11 14:37





hızlı 3.1 versiyon @Kushal Ashok tarafından yayınlanmıştır

class ReselectableSegmentedControl: UISegmentedControl {
    @IBInspectable var allowReselection: Bool = true

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        let previousSelectedSegmentIndex = self.selectedSegmentIndex
        super.touchesEnded(touches, with: event)
        if allowReselection && previousSelectedSegmentIndex == self.selectedSegmentIndex {
            if let touch = touches.first {
                let touchLocation = touch.location(in: self)
                if bounds.contains(touchLocation) {
                    self.sendActions(for: .valueChanged)
                }
            }
        }
    }
}

1
2018-01-13 16:23





@Stunner'a atfen, bu hedefe ulaşmak için benim katkıdır. Bir şeyi değiştirdim ve _previousSelectedSegmentIndex özelliğini ekledim; @Stunner kodunda previousSelectedSegmentIndex değişkeni işe yaramazdı:

@implementation STASegmentedControl
{
    NSInteger _previousSelectedSegmentIndex;
}

- (void)setSelectedSegmentIndex:(NSInteger)selectedSegmentIndex
{
    [super setSelectedSegmentIndex: selectedSegmentIndex];

    _previousSelectedSegmentIndex = self.selectedSegmentIndex;
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesEnded:touches withEvent:event];

    CGPoint locationPoint = [[touches anyObject] locationInView:self];
    CGPoint viewPoint = [self convertPoint:locationPoint fromView:self];
    if (self.toggleableSegments) { // toggle selected segment on/off
        if ([self pointInside:viewPoint withEvent:event] && _previousSelectedSegmentIndex == self.selectedSegmentIndex) {
            self.selectedSegmentIndex = UISegmentedControlNoSegment;
            [self sendActionsForControlEvents:UIControlEventValueChanged];
        }
    }
    _previousSelectedSegmentIndex = self.selectedSegmentIndex;
}

0
2018-04-21 14:45