UIButton + XIB subviews = no highlight - uibutton

I have a UIButton and this button loads a subview from an xib.
Everything is drawn fine and the delegate method is called correctly but there's no highlight effect.
I have everything on the xib set as userInteractionEnabled=false.
If I remove those subviews, the highlight effect works again.

If all your subviews happen to be images, there is a crazy solution: create multiple UIButtons as subviews and tie their highlight / disabled states together. Add them all as subviews of a master button, disable user interaction, and use a K-V observer on the master button. Here's a quick example:
// Only perform the addObserver part if from a XIB
- (UIButton *) makeMasterButton {
// Create some buttons
UIButton *masterButton = [UIButton buttonWithType:UIButtonTypeCustom];
masterButtonFrame = CGRectMake(0,0,100,100);
UIButton *slaveButton1 = [UIButton buttonWithType:UIButtonTypeCustom];
slaveButton1.userInteractionEnabled = NO;
[slaveButton1 setImage:[UIImage imageNamed:#"Top.png"]];
slaveButton1.frame = CGRectMake(0, 0,100,50);
[masterButton addSubview:slaveButton1];
UIButton *slaveButton2 = [UIButton buttonWithType:UIButtonTypeCustom];
slaveButton2.userInteractionEnabled = NO;
[slaveButton2 setImage:[UIImage imageNamed:#"Bottom.png"]];
slaveButton2.frame = CGRectMake(0,50,100,50);
[masterButton addSubview:slaveButton2];
// Secret sauce: add a K-V observer
[masterButton addObserver:self forKeyPath:#"highlighted" options:(NSKeyValueObservingOptionNew) context:NULL];
[masterButton addObserver:self forKeyPath:#"enabled" options:(NSKeyValueObservingOptionNew) context:NULL];
return masterButton;
}
...
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([object isKindOfClass:[UIButton class]]) {
UIButton *button = (UIButton *)object;
for (id subview in button.subviews) {
if ([subview isKindOfClass:[UIButton class]]) {
UIButton *buttonSubview = (UIButton *) subview;
buttonSubview.highlighted = button.highlighted;
buttonSubview.enabled = button.enabled;
}
}
}
}
I had to do this once when I wanted to have an "image" for a UIButton that had layers, transparency and dynamically loaded content.

You can convert the view you've loaded from the xib into a UIImage and add that image to the UIButton instead. This way the highlight will be shown when the button is pressed:
UIButton *button;
UIGraphicsBeginImageContext(viewFromXib.frame.size);
[viewFromXib.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[button setImage:image forState:UIControlStateNormal];

Related

How to pass prepareForSegue programmatically an objected created programmatically

i have a loop in which i create buttons with a selector calling a prepareForSegue. I would pass to the next page the image of the button i clicked.
for (i = 1; i <= 22; i++) //22 it's just temporary
{
//creating button
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self
action:#selector(nextPage: )
forControlEvents:UIControlEventTouchUpInside];
[button setTitle:#"" forState:UIControlStateNormal];
button.frame = CGRectMake(X, Y, 100.0, 100.0);
UIImage *buttonImageNormal = [UIImage imageNamed:#"ambient.png"];
//image obviously will be different and i want to pass that
[button setBackgroundImage:buttonImageNormal forState:UIControlStateNormal];
if (i%3==0 && i==0)
X = 20;
if (i%3==0 && i!=0){
X = 20;
Y = Y+150;
}
if (i%3==1)
X = 140;
if (i%3==2)
X = 260;
[_scroll addSubview:button];
}
this is the method called by every button
-(void)nextPage:(id)sender {
UIViewController *myController = [self.storyboard instantiateViewControllerWithIdentifier:#"signSegue"];
[self.navigationController pushViewController: myController animated:YES];
}
and this is the prepareForSegue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
addController *controller = (addController *)segue.destinationViewController;
}
what i have to pass with controller?
You should not be calling prepareForSegue directly. Instead, you should trigger your segue programmatically, letting the framework take care of calling prepareForSegue in the due course:
[self performSegueWithIdentifier:#"mySegue" sender:self];
You can do like following
-(void)nextPage:(id)sender {
UIButton *pressedButton=(UIButton *)sender;
SecondViewController *myController = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
myController.pressedButtonImageName=pressedButton.currentBackgroundImage;
[self.navigationController pushViewController: myController animated:YES];
}
in your second VC :
#property (nonatomic,strong) UIImage *pressedButtonImageName;
Here, you dont need to do anything with prepareForSegue method.

Why does my textField disappear?

I do some practice with iPhone4S about UITextField on iOS 7.1.2.
Interface:
The interface of the first version is simple, which just has a custom UITextField named MyUITextField and a UIButtom object that use to cancel the search operation. Inside the textField, its leftView property is initially set to a UIButton object, which background image is a magnifying glass. When users tap in the textField, that magnifying glass button will be removed and the leftView property will also set to a new UIButton object, which background image is a inverted triangle. When users tap the triangle button, app will create a new view object.
Main code:
//In this version,the textField's original frame property is set to (10,40,250,30)
//and the main operations are like this:
- (void)viewDidLoad
{
[super viewDidLoad];
self.myTextField.delegate = self;
self.myTextField.leftViewMode = UITextFieldViewModeUnlessEditing;
self.myTextField.leftView = [self creCustomSearchBar];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyBoardWillAppear:)
name:#"UIKeyboardWillShowNotification"
object:nil];
[self.cancleSearchButton addTarget:self
action:#selector(cancleSearch:)
forControlEvents:UIControlEventTouchUpInside];
}
/*when tapping in the textField,keyboard will appear*/
- (void)keyBoardWillAppear:(NSNotification *)notification
{
CGRect newLeftViewIndicatorRect = CGRectMake(20,5,20,20);
UIButton *newLeftViewIndicator = [[UIButton alloc] initWithFrame:newLeftViewIndicatorRect];
NSString *imagePath = [[NSBundle mainBundle] pathForResource:#"searchbar_textfield_down_icon#2x" ofType:#"png"];
[newLeftViewIndicator setBackgroundImage:[UIImage imageWithContentsOfFile:imagePath] forState:UIControlStateNormal];
[newLeftViewIndicator addTarget:self action:#selector(createActuralLeftView:) forControlEvents:UIControlEventTouchUpInside];
self.myTextField.leftView = newLeftViewIndicator;
/*in the second verson need to call */
//[self adjustViewFrame];
[self.cancleSearchButton setTitle:#"取消" forState:UIControlStateNormal];
}
- (void)createActuralLeftView:(UIButton *)leftViewButton
{
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(tapRegionAboveKeyboard:)];
[self.view addGestureRecognizer:tapGesture];
NewLeftView *leftView = [[NewLeftView alloc] initWithFrame:CGRectMake(10, 80, 140, 100)];
leftView.delegate = self;
[self.view addSubview:leftView];
}
- (void)tapRegionAboveKeyboard:(UITapGestureRecognizer *)tapGesture
{
for (UIView *v in self.view.subviews) {
if ([v isKindOfClass:[NewLeftView class]]) {
[v removeFromSuperview];
[self.view removeGestureRecognizer:tapGesture];
return;
}
}
}
//in the second version need to call
- (void)adjustViewFrame
{
[[self.myTextField class] animateWithDuration:0.05 animations:^{
[self.myTextField setFrame:CGRectMake(self.myTextField.frame.origin.x, 40, self.myTextField.frame.size.width, self.myTextField.frame.size.height)];
}];
[[self.cancleSearchButton class] animateWithDuration:0.05 animations:^{
[self.cancleSearchButton setFrame:CGRectMake(self.cancleSearchButton.frame.origin.x, 40, self.cancleSearchButton.frame.size.width, self.cancleSearchButton.bounds.size.height)];
}];
}
In the first version things work well.
But in the second version, I set the textField frame property to (10,260,250,30), so I need to call the adjustViewFrame method in the keyBoardWillAppear: to reposition the textField in case of obscuring by the keyboard.
Here comes the problem: the textField's position is correctly moved to the right place, but when I tap the inverted triangle button, the textField disappeared.
I can't figure out what's going wrong here.

How to change UIButton Background Image on UITableView didSelectRow without Reloading

I added a **UIButton** in UITableView Cell. And I wantto add a functionality on both clicks (UIButton and UITable - didSelectRow).
On Button Click I am able to change the button background image by Sender.
The Code is look like this:
-(void)tableButton_OnClick:(id)sender
{
UIButton *btn=(UIButton *)sender;
[btn setImage:[UIImage imageNamed:#"checked.png"] forState:UIControlStateNormal];
}
And the same functionality I want to add on UITable - didSelectRow without Reloading the table.
You have to make your own custom UITableViewCell with public #property UIButton. Then in didSelectRowAtIndexPath you may use something like this:
- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
YourCell* yourCell = (YourCell*)[tableView cellForRowAtIndexPath:indexPath];
UIButton* button = yourCell.button;
[button setImage:[UIImage imageNamed:#"checked"] forState:UIControlStateNormal];
}
if ([[[myarry objectAtIndex:indexPath.row] objectForKey:#"key_name"] isEqualToString:#"1"])
{
[cell.button_my setBackgroundImage:[UIImage imageNamed:#"first.png"] forState:UIControlStateNormal];
}
els
{
[cell.button_my setBackgroundImage:[UIImage imageNamed:#"first_other.png"] forState:UIControlStateNormal];
}
STEPS - try this
while adding button on cell ,set the tag value to your button
eg :
btn.tag=indexpath.row;
cell.tag=indexpath.row;
On didSelectRowAtIndexPath, Create UIButton based on tag value
eg:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
UITableViewCell *cell=(UITableViewCell *)[self.TableView viewWithTag:indexPath.row];
UIButton *btn=(UIButton *)[cell viewWithTag:indexPath.row];
[self tableButton_OnClick:btn];
}

UIButton below UITableView cannot be clicked

I have a Table View with APParallaxHeader. This creates a view behind the table, which acts as the header of it. My problem is, that I cannot click anything in this header. I've tried overriding -hitTest of the UITableView, but had no success.
Here is my view controller:
#import "TableViewController.h"
#import "UIScrollView+APParallaxHeader.h"
#implementation TableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];
[button setTitle:#"Hello" forState:UIControlStateNormal];
[button setBackgroundColor:[UIColor redColor]];
[button addTarget:self action:#selector(ping) forControlEvents:UIControlEventTouchUpInside];
[self.tableView addParallaxWithView:button andHeight:320];
}
- (void)ping
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
#end
EDIT:
My further investigation shows, that the problem can be reduced to a simple UIButton below a UITableView. How can you get the tap events with the button?

How can I replace the text in a round rect button with a spinner?

I have a view with a generic rounded rect button that segues to another view. When users press the rounded rect it starts a fetch. I would like to have a spinning wheel replace the text ("Next") inside the rounded rect button while the fetch is processed.
I created the spinner:
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[spinner startAnimating];
But I don't know how to make it replace the text in the rounded rect button.
Any suggestion? Thank you.
Create (or get a reference to) the button as usual, then, while handling the button click, create your spinner and set it as a subview of the button. It's probably also worth disabling the button to stop multiple clicks.
Something along the following lines should do the trick:
...
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(10, 10, 70, 40);
[button setTitle:#"Next" forState:UIControlStateNormal];
[button addTarget:self action:#selector(click:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
...
- (void)click:(UIButton *)button {
[button setTitle:#"" forState:UIControlStateNormal];
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[spinner startAnimating];
spinner.frame = button.bounds;
[button addSubview:spinner];
button.enabled = NO;
// do your actual work...
}
I wrote a category that utilizes associated objects
UIButton+ActivityIndicator.h
// Created by reynaldo on 1/16/14.
#import <Foundation/Foundation.h>
#interface UIButton (ActivityIndicator)
- (void)startActivityIndicator;
- (void)stopActivityIndicator;
#end
UIButton+ActivityIndicator.m
// Created by reynaldo on 1/16/14.
#import <objc/runtime.h>
#import "UIButton+ActivityIndicator.h"
static char TITLE_KEY;
static char ACTIVITY_INDICATOR_KEY;
#implementation UIButton (ActivityIndicator)
- (void)startActivityIndicator {
objc_setAssociatedObject(self, &TITLE_KEY, self.currentTitle, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[self setTitle:#"" forState:UIControlStateNormal];
UIActivityIndicatorView *activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[self addSubview:activityIndicatorView];
activityIndicatorView.frame = CGRectMake(self.frame.size.width / 2, self.frame.size.height / 2. - 2, 7, 7);
[activityIndicatorView startAnimating];
objc_setAssociatedObject(self, &ACTIVITY_INDICATOR_KEY, activityIndicatorView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)stopActivityIndicator {
NSString *title = objc_getAssociatedObject(self, &TITLE_KEY);
UIActivityIndicatorView *activityIndicatorView = objc_getAssociatedObject(self, &ACTIVITY_INDICATOR_KEY);
if(activityIndicatorView) {
[activityIndicatorView removeFromSuperview];
}
if(title.length) {
[self setTitle:title forState:UIControlStateNormal];
}
}
#end