提问人:roadRunner 提问时间:11/13/2020 最后编辑:WillekeroadRunner 更新时间:11/14/2020 访问量:184
如何制作多个单选按钮,但始终只选择一个,第一个是默认的?
How to make multiple radioButtons but only one is always selected where the first is default?
问:
我从事一个 Objective-C 项目并尝试构建多个单选按钮。不久,我想创建多个 radioButton,但始终只选择一个,其中第一个是默认的。
我开始尝试使用 2 个按钮,但我无法完全实现我想要的。我希望有很好的方法可以做到这一点。我也对扩展感到满意。
答:
2赞
Ol Sen
11/13/2020
#1
您可以通过放置 UI 元素来对它们进行分组,并使用 KVO 观察器来利用额外的代码。UIView
@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 = &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);
}
}
评论
0赞
roadRunner
11/13/2020
感谢您的回复,我下次会尝试这个并保存在我的图书馆,但我不确定我的情况在我看来有点复杂。我已经设置了约束并编写 #selector 函数。
0赞
roadRunner
11/13/2020
我也不能在UI中对按钮进行分组,因为它们已经有了超级视图。
0赞
Ol Sen
11/13/2020
也可以将 UIView 组放入该超级视图中。没有坏处,无论如何你都需要它来捕捉其中一个是否改变了它的选择以及选择的状态。无论如何,您会在此示例中找到一些想法来改善您的目标。尽管如此,对 UIButton 的扩展也可能很好。或者使用您的超级视图而不是_group
0赞
roadRunner
11/13/2020
是的,非常感谢你,我开始考虑你的代码,我会尽快提供反馈
0赞
Ol Sen
11/13/2020
或者,当您知道您的 SuperView 是“单选”按钮的唯一守护者时,您会疯狂使用sender.superview.subviews
radioButtonPressed:
1赞
Ol Sen
11/13/2020
#2
如前所述,是 UIView 的一个子类,这意味着您也可以使用 UIControl 将 UIButton 组合在一起。优点是,当有新的选择时,添加目标很容易捕获。缺点是你必须更多地考虑样式/布局,因为这在代码中是固定的,更改需要更多的注意。下面的示例使用 NSStrings 的 NSArray,作为标题在 UIControl 的按钮内传播。因此,NSArray 计数定义了在帧高度中生成多少按钮。用这个应该很容易构建多项选择表单。UIControl
//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 && i<titles.count; i++) {
UIButton *radio = self.subviews[i];
[radio setTitle:titles[i] forState:UIControlStateNormal];
[radio setTitle:titles[i] forState:UIControlStateSelected];
}
}
@end
然后,从 ViewController 使用以下方法。#import "ButtonSelectGroup.h"
-(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);
}
评论
0赞
roadRunner
11/14/2020
谢谢,实际上我需要根据您的答案编辑我的问题,但我接受您的第一个答案。
评论
UIView