如何在分段控制button中永久取消select一个段,直到再次点击
我有一个UISegmentedControl
4段。 当它被选中时,它应该保持selected state
。 当再次点击同一个段时,应该deselect itself
。 如何做到这一点?
由于UISegmentedControl
仅在未select段的情况下才会发送操作,所以必须对UISegmentedControl
进行子类化,以便对触摸操作进行细微的更改。 我使用这个类:
@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
现在,即使段已被选中,您也将获得UIControlEventValueChanged
事件。 只需将当前索引保存在一个variables中,并在动作中进行比较。 如果两个索引匹配,则必须取消select触摸的段。
// _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的触摸。 selectedSegmentIndex现在在touchesEnded:
更改。
所以更新的子类应该是这样的:
@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版本,解决了Grzegorz注意到的问题。
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将此修正更改为如下所示:
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) } } } }
这里是一个问题的解决办法,当你尝试通过开始点击UISegmentControl取消select,然后你完成外部触摸 – 它仍然取消select。
- (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]; } } }
你可以这样做(感谢Grzegorz的回答和Matthias的回答 ):
- (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]; } }
我已经开发了一个开放源代码(麻省理工学院许可)类STASegmentedControl (支持iOS 7+),它具有此function(以及更多)。
很有帮助! 谢谢! 我想要更多的控制我的项目的事件,所以我改编@ Matthias的答案发送一个自定义的“价值不变”事件。 我在GitHub上做了一个例子。
我还join了@ Grzegorz的修复,所以如果用户在分段控制之外拖动她的手指,它的行为是正确的。
这是一个独立于IOS版本的解决scheme。 这是select行为本身。
@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
参考@Matthias Bauch发表的答案。 我不得不根据Xcode 7.3中的Swift 2.2做一些改变:
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) } } } } }
快速3.1版本发布@ Kushal Ashok
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) } } } } }
提到@Stunner,这是我实现这个目标的贡献。 我改变了一些东西,并添加了属性_previousSelectedSegmentIndex; 在@Stunner代码中,variablespreviousSelectedSegmentIndex是无用的:
@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; }
- tableView:cellForRowAtIndexPath:调用不仅为可见的单元格?
- “这个程序是不允许查询计划cydia”IOS9错误
- alamofire multipartformdata使用urlrequest
- 适用于iOS 10和Swift 4的Square Region Geofencing
- Xcode开发人员预览:无法在设备上运行
- 在UITableView-XMLparsing中混合了图像
- 在iOS上使用animation旋转UIImageView 180度以上
- UIStatusBar在Facebook新的iOS7应用程序
- 如何隐藏SafariViewController中的完成button和search栏