UISegmentedControl 레지스터가 선택한 세그먼트를 탭합니다.
-
06-07-2019 - |
문제
사용자가 목록 주문 방법을 선택할 수 있는 분할된 컨트롤이 있습니다.잘 작동합니다.
하지만 이미 선택한 세그먼트를 탭하면 순서가 반전되었으면 좋겠습니다.모든 코드가 제자리에 있지만 해당 세그먼트에 탭을 등록하는 방법을 모르겠습니다.사용할 수 있는 유일한 제어 이벤트는 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
에서 연결 검사관.