【问题标题】:ObjectiveC - UIButton remains highlighted/selected and background color and font color changes when highlighted/selectedObjective C - UIButton 保持突出显示/选中,背景颜色和字体颜色在突出显示/选中时发生变化
【发布时间】: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];

}

【问题讨论】:

    标签: ios objective-c uibutton


    【解决方案1】:

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

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

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

    -(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 的方式,也绝对不是一个优雅的解决方案。

    这里有多个问题:

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

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

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

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

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

    您应该花一两天时间真正熟悉 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造成的。

      希望这会有所帮助。

      【讨论】:

      • 感谢您的回答,一旦我测试了您的回答,我将奖励您积分。同时,请您有时间看看这个问题stackoverflow.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】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-01-09
          • 1970-01-01
          • 1970-01-01
          • 2014-01-15
          相关资源
          最近更新 更多