Objective C - UIButton 保持突出显示/选中,背景颜色和字体颜色在突出显示/选中时发生变化

Posted

技术标签:

【中文标题】Objective C - UIButton 保持突出显示/选中,背景颜色和字体颜色在突出显示/选中时发生变化【英文标题】:ObjectiveC - UIButton remains highlighted/selected and background color and font color changes when highlighted/selected 【发布时间】:2018-08-27 03:09:14 【问题描述】:

我使用界面构建器为不同的时间段创建了以下UIButton,为Search 创建了UIButton。当用户点击它时,我希望不同时隙的 UIButton 保持选中/突出显示。背景颜色和字体颜色也会改变(见图)。此外,用户一次只能选择一个时间段。

UIButton不同时隙

我想要实现的按钮

代码

#import "Search.h"
#import <QuartzCore/QuartzCore.h>

@interface Search()



@end

@implementation Search

@synthesize btn1;
@synthesize btn2;
@synthesize btn3;
@synthesize btn4;
@synthesize btn5;
@synthesize btn6;
@synthesize btn7;
@synthesize btn8;
@synthesize btn9;
@synthesize btnSearch;

- (void)viewDidLoad

    [super viewDidLoad];

    _borderBox.layer.shadowRadius  = 5;
    _borderBox.layer.shadowColor   = [UIColor colorWithRed:211.f/255.f green:211.f/255.f blue:211.f/255.f alpha:1.f].CGColor;
    _borderBox.layer.shadowOffset  = CGSizeMake(0.0f, 0.0f);
    _borderBox.layer.shadowOpacity = 0.9f;
    _borderBox.layer.masksToBounds = NO;

    btn1.layer.borderColor = [UIColor lightGrayColor].CGColor;
    btn1.layer.borderWidth =1.0f;
    btn2.layer.borderColor = [UIColor lightGrayColor].CGColor;
    btn2.layer.borderWidth =1.0f;
    btn3.layer.borderColor = [UIColor lightGrayColor].CGColor;
    btn3.layer.borderWidth =1.0f;
    btn4.layer.borderColor = [UIColor lightGrayColor].CGColor;
    btn4.layer.borderWidth =1.0f;
    btn5.layer.borderColor = [UIColor lightGrayColor].CGColor;
    btn5.layer.borderWidth =1.0f;
    btn6.layer.borderColor = [UIColor lightGrayColor].CGColor;
    btn6.layer.borderWidth =1.0f;
    btn7.layer.borderColor = [UIColor lightGrayColor].CGColor;
    btn7.layer.borderWidth =1.0f;
    btn8.layer.borderColor = [UIColor lightGrayColor].CGColor;
    btn8.layer.borderWidth =1.0f;
    btn9.layer.borderColor = [UIColor lightGrayColor].CGColor;
    btn9.layer.borderWidth =1.0f;


-(void)viewWillAppear:(BOOL)animated




- (void)viewDidAppear:(BOOL)animated

    [super viewDidAppear:animated];



- (void)viewDidDisappear:(BOOL)animated

    [super viewDidDisappear:animated];



+(void)makeButtonColored:(UIButton*)button color1:(UIColor*) color


    CALayer *layer = button.layer;
    layer.cornerRadius = 8.0f;
    layer.masksToBounds = YES;
    layer.borderWidth = 4.0f;
    layer.opacity = .3;//
    layer.borderColor = [UIColor colorWithWhite:0.4f alpha:0.2f].CGColor;

    CAGradientLayer *colorLayer = [CAGradientLayer layer];
    colorLayer.cornerRadius = 8.0f;
    colorLayer.frame = button.layer.bounds;
    //set gradient colors
    colorLayer.colors = [NSArray arrayWithObjects:
                     (id) color.CGColor,
                     (id) color.CGColor,
                     nil];

    //set gradient locations
    colorLayer.locations = [NSArray arrayWithObjects:
                        [NSNumber numberWithFloat:0.0f],
                        [NSNumber numberWithFloat:1.0f],
                        nil];


    [button.layer addSublayer:colorLayer];


【问题讨论】:

【参考方案1】:

理论上,您可以执行以下操作:

    将所有按钮存储在一个数组中(一个实例变量) 为每个按钮添加一个目标,设置一个按钮被选中并取消选择所有其他按钮。

按钮的构造函数是这样的:

-(UIButton *)newButtonWithTitle:(NSString *)title fontSize:(NSInteger)fontSize 
    UIColor *selectedButtonColor = [UIColor colorWithRed:1.0 green:0.2 blue:0.2 
    alpha:0.5];

    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button setTitle:title forState:UIControlStateNormal];
    [button setTitleColor:selectedButtonColor forState:UIControlStateHighlighted];
    [button setTitleColor:selectedButtonColor forState:UIControlStateSelected];
    button.titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightRegular];
    button.layer.borderColor = [UIColor lightGrayColor].CGColor;
    button.layer.borderWidth = 1.0;

    [button addTarget:self action:@selector(scheduleButtonAction:) forControlEvents:UIControlEventTouchUpInside];
    return button;

按钮动作函数可以是:

-(void)scheduleButtonAction:(UIButton *)button 
    button.selected = YES;
    [self.buttons enumerateObjectsUsingBlock:^(UIButton *aButton, NSUInteger idx, BOOL * _Nonnull stop) 
        if (![aButton isEqual:button]) 
            aButton.selected = NO;
        
    ];

但是我不会这样做。这个解决方案的问题在于,虽然可行,但它不是 Apple 的方式,也绝对不是一个优雅的解决方案。

这里有多个问题:

    如何绑定每个按钮和它所代表的值之间的数据?您可以通过使用关联对象或通过子类化 UIButton 并添加属性或通过使用标签和查找表来做到这一点。所有这些都不是很好的解决方案。

    这种设计是硬编码的,不灵活。有很多用于创建按钮的样板代码,您必须跟踪所有这些属性。

    如果需求发生变化并且您需要在一天中的每个小时使用一个按钮,您会怎么做?

user10277996 暗示的一种更好的布局方式是使用集合视图。它将允许您分离关注点:

    您决定应该有多少按钮(单元格)的数据源 创建(以及它们应包含哪些数据) 单元的构造函数类,您可以在其中定义设计一次。 一个布局类,您可以在其中定义如何布局按钮。

您应该花一两天时间真正熟悉 UICollectionView,因为它是 ios 中最强大和最有用的类之一。

以下是帮助您入门的教程: https://www.raywenderlich.com/975-uicollectionview-tutorial-getting-started

苹果官方文档: https://developer.apple.com/library/archive/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/Introduction/Introduction.html#//apple_ref/doc/uid/TP40012334-CH1-SW1

如果您想深入了解,请查看以下资源(尽管对于解决您的特定问题不是必需的): https://www.objc.io/issues/3-views/collection-view-layouts/ https://ashfurrow.com/uicollectionview-the-complete-guide/

【讨论】:

【参考方案2】:

我能够实现您正在处理的功能,以下是我是如何做到的。

我通过故事板创建了设计,并将所有 9 个按钮的操作方法连接到单个 Selector 方法,在操作方法中使用 help sender 参数我们可以获取选定按钮的引用并使用它。

- (IBAction)btnPressed:(UIButton*)sender 

/* Below for loop works as a reset for setting the default colour of button and to not select the same one twice*/
for (UIButton* button in buttons) 
    [button setSelected:NO];
    [button setBackgroundColor:[UIColor whiteColor]];
    [button setUserInteractionEnabled:true];
// [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [button setTitleColor:[UIColor blackColor] forState:UIControlStateSelected];


NSInteger tag = sender.tag;        // Here we get the sender tag, which we can use for our needs. Also we can directly use the sender and get the title or whatsoever needed.

/*Now below line works as a toggle for the button where multiple buttons can't be selected at the same time.*/
sender.selected = ! sender.selected;      

if(sender.selected)

/* Here we set the color for the button and handle the selected function*/
    [sender setSelected:YES];
    [sender setUserInteractionEnabled:false];
    [sender setBackgroundColor:[UIColor magentaColor]];


您还可以使用“sender.Layer”属性为按钮添加自定义层。

下面添加了整个代码,

所有按钮的动作都需要连接到一个选择器方法, - (IBAction)btnPressed:(UIButton*)sender;

#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *mainViewOL;
@property (weak, nonatomic) IBOutlet UIButton *btn1;
@property (weak, nonatomic) IBOutlet UIButton *btn2;
@property (weak, nonatomic) IBOutlet UIButton *btn3;
@property (weak, nonatomic) IBOutlet UIButton *btn4;
@property (weak, nonatomic) IBOutlet UIButton *btn5;
@property (weak, nonatomic) IBOutlet UIButton *btn6;
@property (weak, nonatomic) IBOutlet UIButton *btn7;
@property (weak, nonatomic) IBOutlet UIButton *btn8;
@property (weak, nonatomic) IBOutlet UIButton *btn9;

@end

@implementation ViewController

NSArray* buttons;

- (void)viewDidLoad 
    [super viewDidLoad];

    buttons = [NSArray arrayWithObjects:_btn1, _btn2, _btn3,_btn4,_btn5,_btn6,_btn7,_btn8,_btn9,nil];

    self.mainViewOL.layer.shadowRadius  = 5;
    self.mainViewOL.layer.shadowColor   = [UIColor colorWithRed:211.f/255.f green:211.f/255.f blue:211.f/255.f alpha:1.f].CGColor;
    self.mainViewOL.layer.shadowOffset  = CGSizeMake(0.0f, 0.0f);
    self.mainViewOL.layer.shadowOpacity = 0.9f;
    self.mainViewOL.layer.masksToBounds = NO;

    /* I Have added the 9 button's in an array and used it to reduce the lines of code and for easy understanding as well*/
    for (UIButton* button in buttons) 
        button.layer.borderColor = [UIColor lightGrayColor].CGColor;
        button.layer.borderWidth =1.0f;
    


- (IBAction)btnPressed:(UIButton*)sender 
    for (UIButton* button in buttons) 
        [button setSelected:NO];
        [button setBackgroundColor:[UIColor whiteColor]];
        [button setUserInteractionEnabled:true];
     // [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];        //Based on your needs and colour variant you cant add properties to the button for different control states.
        [button setTitleColor:[UIColor blackColor] forState:UIControlStateSelected];
    

    NSInteger tag = sender.tag;

    sender.selected = ! sender.selected;


    if(sender.selected)
    
        [sender setSelected:YES];
        [sender setUserInteractionEnabled:false];
        [sender setBackgroundColor:[UIColor purpleColor]];
        sender.backgroundColor = [UIColor magentaColor];
    


@end

以及最终结果

忽略按钮选择的延迟,是视频转gif造成的。

希望这会有所帮助。

【讨论】:

感谢您的回答,一旦我测试了您的回答,我将奖励您积分。同时,请您有时间看看这个问题***.com/questions/52093069/… 是的,我看了一下这个问题,简单而正确的方法是协议(委托)方法。会解决一些问题并尽快通知您。 嗨@daris mathew,当我按下按钮时,我无法触发- (IBAction)btnPressed:(UIButton*)sender 方法 我需要在 IB 中为 *mainViewOL 做任何事情吗? 知道了,添加了以下All the buttons need to drag to the following method - (IBAction)btnPressed:(UIButton*)sender;【参考方案3】:

尝试使用自定义类型按钮。

UIButton *customButton = [UIButton buttonWithType:UIButtonTypeCustom];

或者在 Interface Builder 中设置这个属性。

【讨论】:

如何做到这一点,你能详细说明一下吗?我需要按钮来更改背景颜色和字体颜色并保持选中状态。【参考方案4】:

您可以借助 UICollectionView 来准备屏幕。

使用 UICollectionViewCell 创建自定义类并覆盖以下属性。

override var isSelected: Bool `
         willSet
                   super.isSelected = newValue

          // put button background color value as per selected state`

【讨论】:

【参考方案5】:

可以通过标签控件获取任意按钮,控制任意按钮。

【讨论】:

以上是关于Objective C - UIButton 保持突出显示/选中,背景颜色和字体颜色在突出显示/选中时发生变化的主要内容,如果未能解决你的问题,请参考以下文章

带有分隔线的Objective C UIButton并在选择时更改文本颜色

如何在 OBJECTIVE C 的 UITableViewCell 中更改先前按下的 UIButton 标签?

Objective C UIButton with divider并在选中时更改textcolor

Objective c 动画 UIbutton 像 mac os x 上的停靠效果

将NSArray中的每个NSString元素显示为UIButton Objective C

将 NSArray 中的每个 NSString 元素显示为 UIButton Objective C