سؤال

لدي السيطرة مجزأة حيث يمكن للمستخدم تحديد كيفية ترتيب قائمة.يعمل بشكل جيد.

بيد أني أود أن تكون محددة مسبقا الجزء هو استغلالها ، يحصل مقلوب.لدي كل رمز في مكانه, ولكن أنا لا أعرف كيفية التسجيل الصنابير على تلك الشرائح.يبدو فقط السيطرة على الحدث يمكنك استخدام 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];
}

أراد هذا بنفسي.أخذ جوليان الحل (شكرا) و تعديل طفيف.

التالية UISegmentedControl فرعية ببساطة بتشغيل UIControlEventValueChanged الحدث حتى عندما تكون قيمة لم تتغير ، والتي من الواضح يقرأ غريبا بعض الشيء ، ولكن يعمل بشكل جيد في حالتي وتبقى الأمور بسيطة.

AKSegmentedControl.ح

#import <UIKit/UIKit.h>

@interface AKSegmentedControl : UISegmentedControl {
}

@end

AKSegmentedControl.م

#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

وهذا يعمل على كل من دائرة الرقابة الداخلية 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];
}

وحظا سعيدا!

وكان هذا السؤال القديم جميلة حتى ظننت فما استقاموا لكم فاستقيموا إضافة حل بسيط بدلا اعتدت عندما واجهت هذا في دائرة الرقابة الداخلية 5+ التطبيق.

وكان كل ما فعلته سحب التعرف الحنفية لفتة على UISegmentedControl في ملف .xib بلدي. افحص توصيلات لجهاز التعرف على بادرة جديدة للتأكد من السيطرة مجزأة هو منفذ gestureRecognizer الوحيد ثم سلك للتو انها عمل إلى الطريقة التي تريد لاطلاق النار في وحدة التحكم الخاصة بك.

وهذه الطريقة يجب أن إطلاق النار في أي وقت كنت على اتصال تحكم مجزأة، حتى مجرد التحقق من الفهرس المحدد ربما مع متغير مثيل لمعرفة ما إذا مست المستخدم شريحة محددة مسبقا.

@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 قبل تغيير شريحة تحكم مجزأة. وسوف يحدث في طريقة touchesEnded.

وهذا يعمل:

- (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 الحلول على النحو التالي.عن حالة خاصة نشرت لي أيضا حل ثالث ، حيث الجزء المحدد يعمل زر تبديل.

الحل 1:

تلميح:هذا الحل يعمل فقط على لحظة 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")
        }
    }
}

الحل 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 في كل مرة يتم استغلالها.

ومساعدة كبيرة! ما أريد القيام به هو لدينا خيار واحد أو أي أزرار مجموعة - وعندما يتم تعيين زر واحدة، حنفية الثاني unsets ذلك. هذا هو بلدي تعديل:

- (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]; 
  }
}

ويخطر يتيح لأول مرة تقرأ السيطرة للعثور على الإعداد الحالي قبل أن إعادة تعيين.

وبناء على الجواب بوب دي غراف في:

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

ودائرة الرقابة الداخلية 9 الحل. تجاوز UISegmentedControl مع هذه الفئة:

@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

ويبدو وكأنه مسألة متعة للإجابة. توسع هذا المخطط على ستيف E وحلول yershuachu ل. يستخدم هذا الإصدار على UITapGestureRecognizer للقبض على كل اللمسات والذي يحدد selectedSegmentIndex إلى -1. ولكنه يمر أيضا على جميع اللمسات لUISegmentedControl حتى تتمكن من التعامل مع أي لمسات طبيعية. لا يلزم إن شاء subclasses ترث.

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
}

وأنا باستخدام المنظمة من لعكس شريحة محددة مسبقا ل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

والحل والجواب المحدد لم تنجح بالنسبة لي من v8.x. دائرة الرقابة الداخلية الحالي لكنAndy تقدم حلا وسأكمل:

وفئة فرعية UISegmentedControl، والكتابة طريقة touchesEnded في فئة فرعية:

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

في الطبقة حيث كنت تنوي استخدام UISegmentedControl، إنشاء ايفار currentSelectedSegIndex. إضافة UIControlEventAllTouchEvents بجانب أساليب العمل 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