Как создать несколько радиокнопок, но только одна всегда выбирается там, где первая по умолчанию?

#objective-c #uibutton

#objective-c #uibutton

Вопрос:

Я работаю над проектом Objective-C и пытаюсь создать несколько переключателей. Вкратце я хочу создать несколько радиокнопок, но только одна всегда выбирается там, где первая используется по умолчанию.

Я начал пробовать с 2 кнопками, но не смог добиться именно того, чего хочу. Я надеюсь, что есть хорошие способы сделать это. Я тоже согласен с расширением.

Комментарии:

1. короче говоря: вам нужно несколько радиокнопок, но только одна всегда выбирается там, где первая по умолчанию?

2. Вероятно, вам следует создать свой собственный UIView подкласс для реализации набора переключателей. В любом случае, вам понадобится массив кнопок. Когда кнопка выбрана, просто выполните итерацию по массиву, и если текущий элемент в итерации не является кнопкой, которая была только что выбрана, отмените ее выбор.

Ответ №1:

вы можете группировать элементы пользовательского интерфейса, помещая их в UIView и использовать KVO observer, чтобы воспользоваться дополнительным кодом.

 @interface ViewController ()
@property (nonatomic) UIView *group;
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    [self createGroupWithRadios:3 andSelectIndex:0];
}

//a context to make KVO much easier to catch (and less string compare'y)
static void * kRadioGroupContext = amp;kRadioGroupContext;

-(void)createGroupWithRadios:(int)amount andSelectIndex:(int)idx {
    CGFloat h = 30.0;
    _group = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, h*amount)];
    for (int i=0; i<amount; i  ) {
        UIButton *radio = [UIButton buttonWithType:(UIButtonTypeSystem)];
        radio.tag = i;
        radio.selected = i==idx;
        { //style stuff
            radio.frame = CGRectMake(0, h*i, 100, h);
            [radio setTitle:@"off" forState:UIControlStateNormal];
            [radio setTitle:@"on" forState:UIControlStateSelected];
            [radio setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
            [radio setTitleColor:UIColor.redColor forState:UIControlStateSelected];
            //[radio setImage:[UIImage imageNamed:@"active"] forState:UIControlStateSelected];
            //[radio setImage:[UIImage imageNamed:@"inactive"] forState:UIControlStateNormal];
        }
        [radio addTarget:self action:@selector(radioButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
        [_group addSubview:radio];
    }
    [self.view addSubview:_group];

    //you can use _group.tag to keep which one is selected and observe it
    _group.tag = idx;
    [_group addObserver:self forKeyPath:@"tag" options:(NSKeyValueObservingOptionNew) context:kRadioGroupContext];
}

-(void)radioButtonPressed:(UIButton*)sender {
    _group.tag = sender.tag;
    for (int i=0; i<_group.subviews.count; i  ) {
        UIButton *radio = _group.subviews[i];
        radio.selected = radio.tag==sender.tag;
    } 
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if (context == kRadioGroupContext) {
        // do something when a new radio is selected
        NSLog(@"selected Radio %lu", _group.tag);
    }
}
  

Комментарии:

1. спасибо за ваш ответ, я попробую это в следующий раз и сохраню в своей библиотеке, но я не уверен, что для моего случая это кажется мне немного сложным. Я уже установил ограничения и написал функцию #selector.

2. Я также не могу сгруппировать кнопки в UIView, поскольку у них уже есть супервизор.

3. вы также можете поместить группу UIView в этот супервизор. Не повредит, вам это все равно понадобится, чтобы определить, изменил ли один из них свой выбор и какое состояние имеет выбор. В любом случае, в этом примере вы найдете несколько идей для улучшения вашей цели. Тем не менее, расширение для UIButton тоже может быть хорошим. Или используйте свой супервизор вместо _group

4. да, большое вам спасибо, я начал думать о ваших кодах, я скоро дам отзыв

5. или вы сходите с sender.superview.subviews ума от in radioButtonPressed: , когда знаете, что ваш супервизор является единственным хранителем кнопок «радио»

Ответ №2:

Как уже упоминалось, UIControl это подкласс UIView, что означает, что вы также можете использовать UIControl для группировки ваших UIButtons вместе. Преимущество заключается в том, что добавление цели легко обнаружить при создании нового выбора. Недостатком является то, что вам нужно немного больше подумать о стиле / макете, потому что это исправлено в коде, и изменение требует большей осторожности. В приведенном ниже примере используется NSArray NSStrings, который будет распространяться в виде заголовков внутри кнопок UIControl. Таким образом, количество NSArray определяет, сколько кнопок генерируется по высоте кадра. С помощью этого должно быть легко создавать формы с несколькими вариантами выбора.

 //ButtonSelectGroup.h
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface ButtonSelectGroup : UIControl
-(instancetype)initWithFrame:(CGRect)frame andTitles:(NSArray<NSString*>*)titles preValue:(NSInteger)idx;
@property (nonatomic) NSInteger value;
-(void)setTitles:(NSArray<NSString *> * _Nonnull)titles;
@end

NS_ASSUME_NONNULL_END
  

и

 //ButtonSelectGroup.m
#import "ButtonSelectGroup.h"

@interface ButtonSelectGroup () {
    NSInteger oldValue;
}
@end

@implementation ButtonSelectGroup
-(instancetype)initWithFrame:(CGRect)frame andTitles:(NSArray<NSString*>*)titles preValue:(NSInteger)idx {
    if (!(self=[super initWithFrame:frame])) return nil;
    [self createGroupWithPreSelectIndex:idx andTitles:titles];
    return self;
}
-(void)createGroupWithPreSelectIndex:(NSInteger)idx andTitles:(NSArray<NSString*>*)titles {
    NSInteger amount = titles.count;
    CGFloat h = self.frame.size.height / amount;
    for (NSInteger i=0; i<amount; i  ) {
        UIButton *radio = [UIButton buttonWithType:(UIButtonTypeSystem)];
        radio.tag = i;
        radio.selected = i==idx;
        { //style stuff
            radio.frame = CGRectMake(0, h*i, 100, h);
            [radio setTitle:titles[i] forState:UIControlStateNormal];
            [radio setTitle:titles[i] forState:UIControlStateSelected];
        }
        [radio addTarget:self action:@selector(radioButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:radio];
    }
    self.value = idx;
}
-(void)radioButtonPressed:(UIButton*)sender {
    oldValue = _value;
    for (NSInteger i=0; i<self.subviews.count; i  ) {
        UIButton *radio = self.subviews[i];
        radio.selected = radio.tag==sender.tag;
    }
    _value = sender.tag;
    if (_value != oldValue) [self sendActionsForControlEvents:(UIControlEventValueChanged)];
}
-(void)setTitles:(NSArray<NSString *> *)titles {
    for (NSInteger i=0; i<self.subviews.count amp;amp; i<titles.count; i  ) {
        UIButton *radio = self.subviews[i];
        [radio setTitle:titles[i] forState:UIControlStateNormal];
        [radio setTitle:titles[i] forState:UIControlStateSelected];
    }
}
@end
  

Затем используйте #import "ButtonSelectGroup.h" следующий способ из вашего ViewController.

 -(void)viewDidLoad {
    [super viewDidLoad];
    ButtonSelectGroup *group = [[ButtonSelectGroup alloc] initWithFrame:CGRectMake(0, 0, 100, 300) andTitles:@[@"even",@"donald",@"duck",@"would",@"concede"] preValue:0];
    [self.view addSubview:group];
    [group addTarget:self action:@selector(singularChoice:) forControlEvents:(UIControlEventValueChanged)];
    // and changing all titles again if you wish
    //group.titles = @[@"but",@"not",@"orangeman"];
}
-(void)singularChoice:(id)sender {
    ButtonSelectGroup* group = (ButtonSelectGroup*)sender;
    UIButton *btn = group.subviews[group.value];
    NSLog(@"groups selection = %lu %@",group.value, btn.titleLabel.text);
}
  

Комментарии:

1. спасибо, на самом деле мне нужно отредактировать свой вопрос в соответствии с вашими ответами, но я принимаю ваш первый ответ.