문제

사용자가 목록 주문 방법을 선택할 수 있는 분할된 컨트롤이 있습니다.잘 작동합니다.

하지만 이미 선택한 세그먼트를 탭하면 순서가 반전되었으면 좋겠습니다.모든 코드가 제자리에 있지만 해당 세그먼트에 탭을 등록하는 방법을 모르겠습니다.사용할 수 있는 유일한 제어 이벤트는 UIControlEventValueChanged인 것 같지만 작동하지 않습니다(선택한 세그먼트가 실제로 변경되지 않기 때문에).

이에 대한 해결책이 있습니까?그렇다면 그것은 무엇입니까?

미리 감사드립니다!

도움이 되었습니까?

해결책

서브 클래스를 할 수 있습니다 UISegmentedControl, 그리고 override setSelectedSegmentIndex:

- (void) setSelectedSegmentIndex:(NSInteger)toValue {
    if (self.selectedSegmentIndex == toValue) {
        [super setSelectedSegmentIndex:UISegmentedControlNoSegment];
    } else {
        [super setSelectedSegmentIndex:toValue];        
    }
}

IB를 사용하는 경우 클래스를 설정해야합니다. UISegmentedControl 서브 클래스에.

이제 당신은 똑같이들을 수 있습니다 UIControlEventValueChanged 평소와 같이, 사용자가 세그먼트를 선택 해제 한 경우를 제외하고는 selectedSegmentIndex 동일 UISegmentedControlNoSegment:

-(IBAction) valueChanged: (id) sender {
    UISegmentedControl *segmentedControl = (UISegmentedControl*) sender;
    switch ([segmentedControl selectedSegmentIndex]) {
        case 0:
            // do something
            break;
        case 1:
            // do something
            break;
        case UISegmentedControlNoSegment:
            // do something
            break;
        default:
            NSLog(@"No option for: %d", [segmentedControl selectedSegmentIndex]);
    }
}

다른 팁

당신이 사용한다면 조금 더 나은 것 같아요 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event--- 이것은 uisegmentedControl의 동작입니다. 또한 과부하 할 필요가없는 것 같습니다. -(void)setSelectedSegmentIndex:(NSInteger)toValue

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {    
    NSInteger current = self.selectedSegmentIndex;
    [super touchesBegan:touches withEvent:event];
    if (current == self.selectedSegmentIndex) 
        [self sendActionsForControlEvents:UIControlEventValueChanged];
}

이것을 직접 원했습니다. Julian의 해결책을 가져 와서 약간 수정했습니다.

다음 uisegmentedcontrol 서브 클래스는 단순히 트리거합니다 UIControlEventValueChanged 이벤트 값이 바뀌지 않았을 때에도 이벤트는 분명히 조금 이상하게 읽지 만 제 경우에는 잘 작동하며 간단하게 유지합니다.

aksegmentedcontrol.h

#import <UIKit/UIKit.h>

@interface AKSegmentedControl : UISegmentedControl {
}

@end

AksegmentedControl.m

#import "AKSegmentedControl.h"

@implementation AKSegmentedControl

- (void)setSelectedSegmentIndex:(NSInteger)toValue {
  // Trigger UIControlEventValueChanged even when re-tapping the selected segment.
  if (toValue==self.selectedSegmentIndex) {
    [self sendActionsForControlEvents:UIControlEventValueChanged];
  }
  [super setSelectedSegmentIndex:toValue];        
}

@end

이것은 iOS 4와 5에서 작동합니다.

-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
  int oldValue = self.selectedSegmentIndex;
  [super touchesBegan:touches withEvent:event];
  if ( oldValue == self.selectedSegmentIndex )
    [self sendActionsForControlEvents:UIControlEventValueChanged];
}

제시된 현재 솔루션은 여전히 ​​작동하지 않습니다. 실제로 새 세그먼트를 탭하지 않는 한 setSelectedSegmentIndex가 호출되지 않기 때문입니다.적어도 내 경우에는 이것이 작동하지 않았습니다. 하지만 iOS5를 사용하지만 아마도 이 솔루션은 iOS4에서 작동했을 것입니다.어쨌든 이것이 내 해결책입니다.다음과 같은 하나의 추가 하위 클래스 메서드가 필요합니다.

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{    
    [self setSelectedSegmentIndex:self.selectedSegmentIndex];
    [super touchesEnded:touches withEvent:event];
}

행운을 빌어요!

이것은 꽤 오래된 질문 이었으므로 iOS 5+ 앱에서 이것을 실행할 때 사용한 간단한 솔루션을 추가 할 것이라고 생각했습니다.

내가 한 것은 탭 제스처 인식기를 .xib 파일의 uisegmentedcontrol로 드래그하는 것입니다. 새로운 제스처 인식기 연결을 확인하여 세그먼트 컨트롤이 유일한 제스처 인식 화제 아울렛인지 확인한 다음 컨트롤러에서 발사하려는 메소드에 동작을 연결하십시오.

이 메소드는 세그먼트 된 컨트롤을 터치 할 때마다 시작되므로 인스턴스 변수로 선택한 인덱스를 확인하여 사용자가 이미 선택한 세그먼트를 터치했는지 확인하십시오.

@implementation MyViewController

@synthesize selectedSegment;
@synthesize segmentedControl;

// connected to Tap Gesture Recognizer's action
- (IBAction)segmentedControlTouched:(id)sender
{
    NSLog(@"Segmented Control Touched");
    if (selectedSegment == [segmentedControl selectedSegmentIndex]) {
        // Do some cool stuff
    }

    selectedSegment = [segmentedControl selectedSegmentIndex];

}

@end

iOS8에서 모든 대답은 작동하지 않거나 변경되지 않는 것 같습니다. 나는 매우 간단한 솔루션을 생각해 냈습니다. 그래서 공유하고 싶습니다.

서브 클래스에서는 다음과 같습니다.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesBegan:touches withEvent:event];
    [self setSelectedSegmentIndex:UISegmentedControlNoSegment];
}

그것이하는 일은 세그먼트 된 제어 세그먼트를 변경하기 전에 선택된 세그먼트를 -1로 재설정하는 것입니다. 접촉 된 방법으로 발생합니다.

이것은 작동합니다 :

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    int oldValue = self.selectedSegmentIndex;
    [super touchesBegan:touches withEvent:event];
    if (oldValue == self.selectedSegmentIndex)
    {
        [super setSelectedSegmentIndex:UISegmentedControlNoSegment];
        [self sendActionsForControlEvents:UIControlEventValueChanged];
    }
}

~ 안에 스위프트 3 다음과 같이 적어도 2 개의 솔루션을 상상할 수 있습니다. 특별한 경우에는 선택한 세그먼트가 토글 버튼으로 작동하는 세 번째 솔루션도 게시했습니다.

Solution 1:

힌트 :이 솔루션은 Momentary ControlSegments에서만 작동합니다! 고정식 컨트롤을위한 솔루션이 필요한 경우 솔루션 2를 선택하십시오.

아이디어는 터치 업에 발사되는 두 번째 이벤트를 등록하는 것입니다.

// this solution works only for momentary segment control:
class Solution1ViewController : UIViewController {
    var current:Int = UISegmentedControlNoSegment
    @IBOutlet weak var mySegmentedControl: UISegmentedControl! {
        didSet {
            guard mySegmentedControl != nil else { return }

            self.mySegmentedControl!.addTarget(
                self,
                action:#selector(changeSelection(sender:)),
                for: .valueChanged)

            self.mySegmentedControl!.addTarget(
                self,
                action:#selector(changeSelection(sender:)),
                for: .touchUpInside)
        }
    }

    func changeSelection(sender: UISegmentedControl) {
        if current == sender.selectedSegmentIndex {
            // user hit the same button again!
            print("user hit the same button again!")
        }
        else {
            current = sender.selectedSegmentIndex
            // user selected a new index
             print("user selected a new index")
        }
    }
}

Solution 2:다른 방법은 터치 기능을 무시하는 것입니다. UISegmentedControl 그리고 발사 valueChanged 세그먼트 인덱스가 변경되지 않은 경우에도 그러므로 당신은 그것을 무시할 수 있습니다 UISegmentedControl 다음과 같이 :

// override UISegmentControl to fire event on second hit:
class Solution2SegmentControl : UISegmentedControl
{
    private var current:Int = UISegmentedControlNoSegment
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        current = self.selectedSegmentIndex
        super.touchesBegan(touches, with: event)
    }
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesEnded(touches, with: event)
        if current == self.selectedSegmentIndex {
            self.sendActions(for: .valueChanged)
        }
    }
}

// solution2 works with stationary (default) segment controls
class Solution2ViewController : UIViewController {
    var current:Int = UISegmentedControlNoSegment

    @IBOutlet weak var mySegmentedControl: UISegmentedControl! {
        didSet {
            guard mySegmentedControl != nil else { return }

            self.mySegmentedControl!.addTarget(
                self,
                action:#selector(changeSelection(sender:)),
                for: .valueChanged)
        }
    }

    func changeSelection(sender: UISegmentedControl) {
        if current == sender.selectedSegmentIndex {
            // user hit the same button again!
            print("user hit the same button again!")
        }
        else {
            current = sender.selectedSegmentIndex
            // user selected a new index
            print("user selected a new index")
        }
    }
}

솔루션 3 :접근 방식이 선택한 세그먼트를 토글 버튼으로 만드는 경우 솔루션 2보다 다음과 같이 코드를 정리할 수 있습니다.

class MyToggleSegmentControl : UISegmentedControl {
    /// you could enable or disable the toggle behaviour here
    var shouldToggle:Bool = true

    private var current:Int = UISegmentedControlNoSegment
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        current = self.selectedSegmentIndex
        super.touchesBegan(touches, with: event)
    }
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesEnded(touches, with: event)
        if shouldToggle, current == self.selectedSegmentIndex {
            self.selectedSegmentIndex = UISegmentedControlNoSegment
        }
    }
}

이제 우리는 정리할 수 있습니다 changeSelection 다음과 같이 기능 :

func changeSelection(sender: UISegmentedControl) {
    switch sender.selectedSegmentIndex {
    case UISegmentedControlNoSegment:
        print("none")
    default:
        print("selected: \(sender.selectedSegmentIndex)")
    }
}

여기 내 해결책이 있습니다. 가장 우아한 것은 Valuechanged 이벤트가 모든 터치에서 발사되기를 원한다면 ...

.시간

@interface UISegmentedControlAllChanges : UISegmentedControl
@end

.중

@implementation UISegmentedControlAllChanges

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

@end

내가 가진 첫 번째 아이디어는 Touch Up Inside 또는 Touch Down 정렬 방법에 대한 조치이지만 이것은 작동하지 않는 것 같습니다.

두 번째 아이디어는 주변의 작업에 더 가깝습니다. Momentary 세그먼트 된 제어의 속성. 이것은 해고 될 것입니다 Value Did Change 액션이 두드릴 때마다.

큰 도움이! 내가하고 싶은 것은 버튼이 하나 또는 전혀없는 옵션을 갖는 것입니다. 버튼이 설정되면 두 번째 탭을 설정하지 않습니다. 이것은 내 수정입니다.

- (void)setSelectedSegmentIndex:(NSInteger)toValue
{
  // Trigger UIControlEventValueChanged even when re-tapping the selected segment.
  if (toValue==self.selectedSegmentIndex) {
    [super setSelectedSegmentIndex:UISegmentedControlNoSegment]; // notify first
    [self sendActionsForControlEvents:UIControlEventValueChanged]; // then unset
  } else {
    [super setSelectedSegmentIndex:toValue]; 
  }
}

알림 먼저 컨트롤을 읽으려면 현재 설정이 재설정되기 전에 현재 설정을 찾을 수 있습니다.

Bob de Graaf의 답변을 바탕으로 :

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

사용에 유의하십시오 UIControlEventAllTouchEvents 대신에 UIControlEventValueChanged.

또한 전화 할 필요가 없습니다 -(void)setSelectedSegmentIndex:.

저에게 효과가있는 코드 아래. 동일한 세그먼트를 반복 탭하면 선택 해제됩니다.

@implementation WUUnselectableSegmentedControl
{
    NSUInteger _selectedIndexBeforeTouches;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    _selectedIndexBeforeTouches = self.selectedSegmentIndex;
    [super touchesBegan:touches withEvent:event];
}

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

    if (_selectedIndexBeforeTouches == self.selectedSegmentIndex)
    {
        // Selection didn't change after touch - deselect
        self.selectedSegmentIndex = UISegmentedControlNoSegment;
        [self sendActionsForControlEvents:UIControlEventValueChanged];
    }
}

@end

iOS 9 솔루션. 이러한 클래스로 UISEGMENDEDCOTROL을 무시합니다.

@interface SegmentedControl()

@property (nonatomic) NSInteger previousCurrent;

@end

@implementation SegmentedControl

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.previousCurrent = self.selectedSegmentIndex;
    [super touchesBegan:touches withEvent:event];
}

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

    if (self.selectedSegmentIndex == self.previousCurrent) {
        [self sendActionsForControlEvents:UIControlEventValueChanged];
    }

    self.previousCurrent = NSNotFound;
}

@end

대답하기에 재미있는 질문인 것 같습니다.이 계획은 Steve E와 Yershuachu의 솔루션을 확장합니다.이 버전은 UITapGestureRecognizer를 사용하여 모든 터치를 캡처하고 selectedSegmentIndex를 -1로 설정합니다.하지만 모든 터치를 UISegmentedControl에 전달하므로 일반적인 터치도 처리할 수 있습니다.서브클래싱이 필요하지 않습니다.

UISegmentedControl *mySegControl;

- (void)viewDidLoad
{
    [super viewDidLoad];

    [mySegControl addTarget:self action:@selector(segmentAction:)
           forControlEvents:UIControlEventValueChanged];
    // allow the a seg button tap to be seen even if already selected
    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]
                                          initWithTarget:self action:@selector(unitsSegTap:)];
    tapGesture.cancelsTouchesInView = NO; // pass touches through for normal taps
    [mySegControl addGestureRecognizer:tapGesture];

    // continue setup ...
}

- (void)segTap:(UITapGestureRecognizer *)sender
{
    mySegControl.selectedSegmentIndex = -1;
}

// called for UIControlEventValueChanged
- (void)segmentAction:(UISegmentedControl *)sender
{
    NSInteger index = sender.selectedSegmentIndex;
    NSLog(@"unitsSegmentAction %d",(int)index);
    // process the segment
}

KVO를 사용하여 iOS8에 대해 이미 선택한 세그먼트를 반전하고 있습니다.

#import "QCSegmentedControl.h"

static void *QCSegmentedControlContext = &QCSegmentedControlContext;

@implementation QCSegmentedControl

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

    return self;
}

- (void)dealloc {
    [self removeObserver:self forKeyPath:@"selectedSegmentIndex"];
}

#pragma mark -

- (void)registerKVO {
    [self addObserver:self
           forKeyPath:@"selectedSegmentIndex"
              options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
              context:QCSegmentedControlContext];
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {
    if (context == QCSegmentedControlContext) {
        NSNumber *new = change[NSKeyValueChangeNewKey];
        NSNumber *old = change[NSKeyValueChangeOldKey];
        if (new.integerValue == old.integerValue) {
            self.selectedSegmentIndex = UISegmentedControlNoSegment;
        }
    }
}

@end

선택된 답변의 솔루션은 현재 iOS v8.x에서 나에게 효과가 없었습니다. 그러나 @andy는 해결책을 제공하면 다음을 완료 할 것입니다.

서브 클래스 UISegmentedControl, 그리고 덮어 쓰기 touchesEnded 서브 클래스의 메소드 :

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

UiseGmentedControl을 사용하려는 클래스에서 IVAR CurrentSelectedSegindex를 만듭니다. UIControleventAltouchevents를 UicontroleventValuechanged 조치 방법 옆에 추가하십시오.

NSInteger currentSelectedSegIndex;

[aSegmentedController addTarget:self action:@selector(aSegmentedControllerSelection:) forControlEvents:UIControlEventValueChanged];
[aSegmentedController addTarget:self action:@selector(aSegmentedControllerAllTouchEvent:) forControlEvents:UIControlEventAllTouchEvents];

두 가지 동작 방법을 구현하십시오.

-(void)aSegmentedControllerAllTouchEvent:(MyUISegmentedControl *)seg
{
    seg.selectedSegmentIndex = UISegmentedControlNoSegment;
}
-(void)aSegmentedControllerSelection:(MyUISegmentedControl *)seg
{
    if (currentSelectedSegIndex == seg.selectedSegmentIndex)
    {
        seg.selectedSegmentIndex = UISegmentedControlNoSegment;
        currentSelectedSegIndex = NSIntegerMax;
        NSLog(@"%s Deselected.", __PRETTY_FUNCTION__);
        // do your stuff if deselected
        return;
    }
    NSLog(@"%s Selected index:%u", __PRETTY_FUNCTION__, seg.selectedSegmentIndex);
    currentSelectedSegIndex = seg.selectedSegmentIndex;
    //do your stuff if selected index
}

이것은 작동해야합니다 :

- (IBAction)segmentedControlValueChanged:(id)sender
{
    UISegmentedControl *sc = (UISegmentedControl*) sender;
    switch ([sc selectedSegmentIndex])
    {
       case 0:
            NSLog(@"First option!");
            break;
       case 1:
            NSLog(@"Second option!");
            break;
       case UISegmentedControlNoSegment:
            NSLog(@"No option...");
            break;
        default:
            NSLog(@"No selected option :( ");
    }

    //this resets the segmented control (mySC) value to act as a button.
    [self.mySC setSelectedSegmentIndex:UISegmentedControlNoSegment];
}

이것을 연결하십시오 IBAction 세분화 된 제어 콘센트에 Value Changed 에서 연결 검사관.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top