Showing posts with label uibutton. Show all posts
Showing posts with label uibutton. Show all posts

Tuesday, September 4, 2018

ObjectiveC - UIButton remains highlighted/selected and background color and font color changes when highlighted/selected

Leave a Comment

I have used the interface builder to create the following UIButton for different time slot and a UIButton for Search. I want the UIButton for different time slot to remain selected/highlighted when user tap on it. And the background color and font color will change as well (See pic for illustration). Moreover, user can only select one of the time slot at one time.

UIButton with different time slotenter image description here

What I am trying to achieve button

enter image description here

Code

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

5 Answers

Answers 1

Theoretically, you could do the following:

  1. Store all the buttons in an array (an instance variable)
  2. Add a target to each button which sets one button to be selected and deselects all other buttons.

The constructor function of the button would like something like this:

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

The button action function could be:

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

BUT I wouldn't do it this way. The problem with this solution is while it is possible, it's not the Apple way and it's definitely not an elegant solution.

There are multiple problems here:

  1. How are you binding the data between each button and the value that it represents? You could do that by either using associative objects OR by subclassing UIButton and adding a property OR by using tags and a lookup table. All of which are not great solutions.

  2. This design is hardcoded and not flexible. There is a lot of boilerplate code for the creation of the buttons and you have to keep track of all these properties.

  3. What are you going to do if the requirement will change and you'll need a button for each hour of the day?

A better way to do this layout, which was hinted by user10277996 is to use a collection view. It will allow you to separate the concerns:

  1. a data source where you decide how many buttons (cells) should be created (and what data they should contain)
  2. a constructor class for the cell, where you define the design once.
  3. a layout class where you define how to lay out your buttons.

You should take a day or two and get really familiar with UICollectionView as it is one of the most powerful and useful classes in iOS.

Here is a tutorial to get you started: https://www.raywenderlich.com/975-uicollectionview-tutorial-getting-started

Apple's official documentation: https://developer.apple.com/library/archive/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/Introduction/Introduction.html#//apple_ref/doc/uid/TP40012334-CH1-SW1

If you want to dig deeper, check out the following resources (although not necessary for solving your specific issue): https://www.objc.io/issues/3-views/collection-view-layouts/ https://ashfurrow.com/uicollectionview-the-complete-guide/

Answers 2

I was able to achieve the function you are working on and below is how i did it.

I created the design via storyboard and connected all the 9 button's actions methods to a single Selector method, inside the action method with the help sender parameter we can get the selected buttons reference and use it.

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

You can also add custom layer for the button by using the "sender.Layer" property.

The Whole code is added below,

#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 

And the Final Result

Ignore the delay in button selection, it is caused by the video to gif conversion.

Hope This helps.

Answers 3

Try to use custom type button.

UIButton *customButton = [UIButton buttonWithType:UIButtonTypeCustom]; 

Or set this property in Interface Builder.

Answers 4

You can prepare you screen with the help UICollectionView.

Create custom class with UICollectionViewCell and override below property.

override var isSelected: Bool `{          willSet{                    super.isSelected = newValue            // put button background color value as per selected state` 

Answers 5

You can get any button and control any button through the tag control.

enter image description here

Read More

Monday, July 31, 2017

UIButton Click Not working when its triggered from static library

Leave a Comment

We are trying to trigger display button from static library project using webview. while integrating static library with single view application we have got the output design. but when we tried to attempt action by clicking on Button its not working.

Below is the code,which we have used inside cocoa touch static library

UIButton *imageButton = [UIButton buttonWithType:UIButtonTypeCustom];  imageButton.frame = CGRectMake(self.view.frame.size.width-50, 10, 50, 50);  [imageButton setImage:[UIImage imageNamed:@"close.png"] forState:UIControlStateNormal];  imageButton.adjustsImageWhenHighlighted = NO;  // [imageButton addTarget:self  action:@selector(close:) forControlEvents:UIControlEventTouchUpInside];  [imageButton addTarget:self action:@selector(hideWebViewBtn:) forControlEvents:UIControlEventTouchUpInside];   -(IBAction)hideWebViewBtn:(id)sender {        NSLog(@"Hide Button clicked");      [self.adView removeFromSuperview];      self.adView = nil;      return;  } 

Below is the screenshot which displayed in single view application after integration and running. Once i click on the button its not getting clicked.

enter image description here

5 Answers

Answers 1

try this,whether self button is triggering or not..

  [self.myButton sendActionsForControlEvents:UIControlEventTouchUpInside]; 

It worked for me

Answers 2

You should add your button to a super view.And also,the super view should enable user interfaces.

[yourSuperView addSubView:button];yourSuperView.userInteractionEnabled=YES;

Answers 3

How about you change your return type of your 'hideWebViewBtn' method from 'IBAction' to 'void'?

Answers 4

"Once i click on the button its not getting clicked." You mean that u click the close button,but it doesn't call the function hideWebViewBtn:() ?

Answers 5

You can try this.

UIButton *imageButton = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width-100, 10, 50, 50)];      [imageButton setImage:[UIImage imageNamed:@"close.png"] forState:UIControlStateNormal];      [self.view addSubview:imageButton];     [self.view bringSubviewToFront:imageButton];     [imageButton removeTarget:self action:NULL forControlEvents:UIControlEventAllEvents];      [imageButton addTarget:self action:@selector(hideWebViewBtn:) forControlEvents:UIControlEventTouchUpInside]; 

Hope it works for you. Thanks!

Read More

Thursday, April 21, 2016

Apply CAShapeLayer to main UIView except UIButton

Leave a Comment

Here is a code which applying mask to the whole UIView:

UIBezierPath *maskPath = [UIBezierPath bezierPathWithRect:self.view.bounds]; [maskPath appendPath:[UIBezierPath bezierPathWithArcCenter:self.mapCardsButton.center                                                     radius:self.mapCardsButton.frame.size.height/2.0f                                                 startAngle:0.0f                                                   endAngle:2.0f*M_PI                                                  clockwise:NO]]; CAShapeLayer *maskLayer = [CAShapeLayer layer]; maskLayer.fillRule  = kCAFillRuleEvenOdd; maskLayer.fillColor = [UIColor blackColor].CGColor; maskLayer.path = maskPath.CGPath; self.view.layer.mask = maskLayer; 

The problem is that I want to apply the mask above to the whole UIView except one specific UIButton(mapCardsButton) which is also on the same UIView. Is it possible to do?

UPD: I tried

[self.view.layer insertSublayer:maskLayer atIndex:0]; 

instead of

self.view.layer.mask = maskLayer; 

but my self.view lost alpha channel and animation of maskLayer doesn't work anymore

Here is a project with code: https://www.dropbox.com/s/b94qcwxzoi23kwk/test_04092016.zip?dl=0

2 Answers

Answers 1

The simplest way would be for the UIButton to be a sibling view of the masked view, rather than a subview. I realise that it might make logical sense for the button to be a subview (especially since it looks like your code is probably from a UIViewController subclass), so I would create a container UIView that holds all the other subviews apart from mapCardsButton and apply the mask to this new view.

So say you called the new view maskedContainerView, then:

  • self.view has two subviews: maskedContainerView and mapCardsButton
  • maskedContainerView holds all the subviews that self.view used to, except mapCardsButton
  • maskedContainerView.layer.mask = maskLayer.

Answers 2

Why don't you try the following? instead of the following stack:

• mask(view) -> button

make the view background color clear, at an additional subview and do the following:

• view -> mask(subView), button

This way you will have the same visual effect, but use the bottom view as a container. In code:

UIBezierPath *maskPath = [UIBezierPath bezierPathWithRect:self.view.bounds]; [maskPath appendPath:[UIBezierPath bezierPathWithArcCenter:self.mapCardsButton.center                                                     radius:self.mapCardsButton.frame.size.height/2.0f                                                 startAngle:0.0f                                                   endAngle:2.0f*M_PI                                                  clockwise:NO]]; CAShapeLayer *maskLayer = [CAShapeLayer layer]; maskLayer.fillRule  = kCAFillRuleEvenOdd; maskLayer.fillColor = [UIColor blackColor].CGColor; maskLayer.path = maskPath.CGPath;  UIView *maskedView = [[UIView alloc] initWithFrame:self.view.bounds];     maskedView.mask = maskLayer;  self.view.backgroundColor = [UIColor clearColor]; [self.view addSubView:maskedView]; [self.view addSubView:self.mapCardsButton]; 
Read More