UIButton not firing selector if I draw it using CALayer - iphone

Hi everybody I create this button like this:
_myButton = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
DLBadgeLayerDelegate *layerDelegate = [[DLBadgeLayerDelegate alloc] init];
_myButton.frame = CGRectMake(0.0 , 0.0, 100.0, 100.0);
[_myButton addTarget:self action:#selector(myButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
_myButton.layer.backgroundColor = [[UIColor redColor] CGColor];
_myButton.center = CGPointMake(10.0, 10.0);
[self addSubview:_myButton];
[_myButton release];
The button appears on the screen but if I tap on it nothing happens. If I just create a Rounded rect button instead with no custom drawing on its layer or if I just leave the layer line of code out all works well. Do you have any Idea why do I get this behaviour as I would like to do some custom drawing in the button's layer?

Events are not sent to a control that is (1) Hidden, (2) alpha < 0.1, (3) userInteraction=NO, etc. Since you have no button image, no button title, no background color, no background image, maybe it is being treated as transparent (like alpha < 0.1) and is not getting events. Try adding an image, title, or background color (in the UIView, not the layer) to see if that's the problem.
EDIT: Try putting the background color in the view's backgroundColor instead of in the layer's backgroundColor:
_myButton.backgroundColor = [UIColor redColor];

If I leave this line out:
_myButton.layer.backgroundColor = [[UIColor redColor] CGColor];
the event is triggered correctly and I still have no title, alpha, etc. I don't think that is the problem or explication, but I will try that way too.

Related

CALayer shadow and translucent UINavigationBars

I've got a translucent navigation bar which is being rendered with a navigation controller.
I'd like to add a drop shadow underneath it, however, when the shadow is rendered, it seems to draw it inside the navigation bar too.
This is quite annoying, and I'd like to render the part of the shadow which is beneath the navigation bar.
Here's the code to render the shadow:
navController.navigationBar.layer.shadowColor = [[UIColor blackColor] CGColor];
navController.navigationBar.layer.masksToBounds = NO;
navController.navigationBar.layer.shadowPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 320, 44)].CGPath;
navController.navigationBar.layer.shadowOpacity = 1.0f;
navController.navigationBar.layer.shadowRadius = 2.0f;
navController.navigationBar.layer.shadowOffset = CGSizeMake(0, 0);
navController.navigationBar.barStyle = UIBarStyleBlackTranslucent;
Here's what I would like to achieve (created in an image editor):
However, here's what is actually rendered:
Any help appreciated.
[self.navigationController.navigationBar setTintColor:[UIColor colorWithRed:(132.0/255) green:(132.0/255) blue:(132.0/255) alpha:1.0]];
Try changing parameters as per your requirements.
Rather I would suggest to go with the linked approach will be beneficial as well as standard.
http://sebastiancelis.com/2009/12/21/adding-background-image-uinavigationbar/
source for that :
https://github.com/scelis/ExampleNavBarBackground

CALayer Border is appearing above subview (Z-order related, I think)

I have searched but could not find the reason for this behavior.
I have a UIButton whose image I am setting. Here is how the button should appear. Note that this is just a photoshop of the intended button design:
Essentially, it is a square custom UIButton with a white border and a little surrounding shadow. In the upper right corner, there is a "X" mark, that will be added programmatically as a subview.
Here is the screenshot of the button within the actual app. At this point, I have only added a shadow and the X mark as a subview:
How, when I try to add the white border, here is what it looks like:
It seems that the white border is appearing above the X mark sublayer. I don't know why.
Here is the code that I am using:
// selectedPhotoButton is the UIButton with UIImage set earlier
// At this point, I am adding in the shadow
[selectedPhotoButton layer] setShadowColor:[[UIColor lightGrayColor] CGColor]];
[[selectedPhotoButton layer] setShadowOffset: CGSizeMake(1.0f, 1.0f)];
[[selectedPhotoButton layer] setShadowRadius:0.5f];
[[selectedPhotoButton layer] setShadowOpacity:1.0f];
// Now add the white border
[[selectedPhotoButton layer] setBorderColor:[[UIColor whiteColor] CGColor]];
[[selectedPhotoButton layer] setBorderWidth:2.0];
// Now add the X mark subview
UIImage *deleteImage = [UIImage imageNamed:#"nocheck_photo.png"];
UIImageView *deleteMark = [[UIImageView alloc] initWithFrame:CGRectMake(53, -5, 27, 27)];
deleteMark.contentMode = UIViewContentModeScaleAspectFit;
[deleteMark setImage:deleteImage];
[selectedPhotoButton addSubview:deleteMark];
[deleteMark release];
I don't understand why the border is appearing above the deleteMark subview. Is there any way to get the intended effect?
Thank you!
From Apple's docs on CALayer:
The border is drawn inset from the receiver’s bounds by borderWidth. It is composited above the receiver’s contents and sublayers and includes the effects of the cornerRadius property.
In order to get the effect you want, I suggest you put the image into an own subview/sublayer and set that sublayer's borderWidth property.
You can set the layer's zPosition to -1. That worked for me.
I had similar problem (I wanted to prevent border line to be on top of my subviews)
CAShapeLayer * _border = [CAShapeLayer layer];
_border.strokeColor = [UIColor colorWithRed:119/255.0f green:119/255.0f blue:119/255.0f alpha:1.0f].CGColor;
_border.fillColor = nil;
[bgRoundView.layer addSublayer:_border];
_border.path = [UIBezierPath bezierPathWithRoundedRect:bgRoundView.bounds cornerRadius:20.f].CGPath;

There's a shadow on my button

i'm creating a button programmaticly for an iPad application. when i see the button, there looks to be a shadow type thing below it. what is it and how can i get rid of it?
here is the code that creates it:
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
myButton.titleLabel.font = [UIFont fontWithName:#"Trebuchet MS" size:12];
[myButton setTitle:#"test" forState:UIControlStateNormal];
myButton.frame = CGRectMake(0, 0, self.leftScrollView.frame.size.width, 50);
UIImageView *myImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"gear12.png"]];
[myButton addSubview:myImageView];
[self.leftScrollView addSubview:myButton];
UPDATE:
ok, i notice i only get that effect when its in my scrollview. if i add it to the view, no shadow effect.
the top test button, the button is a subview of the view. the bottom button is a subview of the scrollview which is a subview of the view (button/view vs button/scrollview/view).
white section is the view, grey is the scrollview/view.
UPDATE 2:
as pointed out by robmayor, UIButtons always have that double line effect, just not noticeble when the background color is white. the blue is a view and the grey is the subview scrollview.
This question is old (6 months) but i'have found a solution to delete/mask this bad effect of double lines.
[yourButton.layer setBackgroundColor: [[UIColor blackColor]CGColor]];
[yourButton.layer setBorderWidth:1.0f];
[yourButton.layer setBorderColor:[[UIColor blackColor]CGColor]];
[yourButton.layer setShadowOpacity:0.1f];
[yourButton.layer setCornerRadius:10];
UIColor selected is depending of the current background of your view.
Result :
On iPads, a rounded-rect UIButton always draws a white line along its bottom edge. You can't see that white line if the button's superview is white, but it's still there.
You have a few options:
Make the superview white. This is the easiest but you might not like the way it looks.
Make some rounded rect images in your favorite image editor. Set the button type to custom and set your rounded rect images as the button's images.
Make a subclass of UIButton and override its drawRect: method.
Set the button type to custom and use the button's layer properties (button.layer.backgroundColor, button.layer.borderColor, button.layer.borderWidth, button.layer.cornerRadius) to give the button a rounded rect appearance. You'll have to update button.layer.backgroundColor when the button is touched if you want it to turn blue like a normal one does. (Actually a normal one uses a blue gradient.)
Replace [UIButton buttonWithType:UIButtonTypeRoundedRect] with:
UIButton *myButton = [UIButton new];
or:
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeCustom];
You want to have your customized button. You can still make it with rounded corners if needed.

Make intersection transparent using multiple subviews

Please check below image. i have added scrollview in "BLACK" color and added subview in "GREY" color. now i want to make subview transparent which is define as "WHITE" color.
Please refer the below code. Let me know how to make button transparent with particular frame or let me know if you have any alternative for that.
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0, 40.0, self.frame.size.width, 300.0)];
self.scrollView.contentSize = CGSizeMake(self.bounds.size.width,ViewHeight);
self.scrollView.autoresizingMask=UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.scrollView.delegate = self;
self.scrollView.backgroundColor =[UIColor blackColor];
[self.view addSubview:self.scrollView
UIButton *butApp = [UIButton buttonWithType:UIButtonTypeCustom];
[butApp setFrame:CGRectMake(x, y , w, h)];
[butApp setBackgroundColor:[UIColor greyColor]];
[self.scrollView addSubview:butApp];
UIButton* gapButton = [UIButton buttonWithType:UIButtonTypeCustom];
[gapButton setFrame:CGRectMake(x+3, y+10, w-6, 10)];
[gapButton setBackgroundColor:[UIColor whiteColor]];
[self.scrollView addSubview:gapButton];
Instead of this gapButton i need transparent portion in grey color so user can see black color in that portion.
Try this, I suggested it in comments. Other answer requires subclassing UIButton, which you suggested was not ideal in your situation.
UIButton *butApp = [UIButton buttonWithType:UIButtonTypeCustom];
[butApp setFrame:CGRectMake(x, y , w, h)];
//[butApp setBackgroundColor:[UIColor greyColor]]; //replace this...
[butApp setBackgroundImage:[UIImage imageNamed:#"greyWithHoleInCenter.png"]
forState:UIControlStateNormal]; //...with this
[self.scrollView addSubview:butApp];
I created a crude .png file to represent the kind of backgroundImage you might be looking for. Note that the center is clear, not white. Therefore, it should show whatever image is behind it:
Ok. Funny question. In my opinion you have to override drawRect: + drawInContext: methods by subclassing UIView class.
You also need to set the container view (the gray view) + button bg to clearColor
-(void)drawRect:(CGRect)r
{
// Let this method blank will cause drawLayer:InContext to be called
}
-(void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context
{
// Fill the bg with gray
CGContextSetFillColorWithColor(context, [UIColor grayColor].CGColor);
CGContextFillRect(context, self.bounds);
// I clear the subview frames
for (UIView * v in [self subviews]) // I do it for all subviews
{
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextFillRect(context, v.frame);
}
}

How to programmatically render a flat background UIColor as the background for a UIToolbar?

So I followed a tutorial which allows me to subclass UIToolbar and draw an image as a custom background for the UIToolbar.
Code was something like this:
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
UIImage *backgroundImage = [UIImage imageNamed:#"toolbar_background.png"];
[backgroundImage drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
This works flawlessly. Considering though that I just want my toolbar background to be a flat color. Basically something like [UIColor blackColor], is there an easier way to do this in the drawRect method?
Having to make a 320 x 44 px height flat black background image and use that with the above code seems like extreme overhead when [UIColor blackColor] is available? I'm just not sure how to implement it here.
I thought about doing something like this instead:
- (void)drawRect:(CGRect)rect
{
UIView *test = [[UIView alloc] initWithFrame:CGRectMake(0,0,self.frame.size.width,self.frame.size.height)];
test.backgroundColor = [UIColor blackColor];
[self addSubview:test];
}
But this doesn't work because then the UIView COVERS all the UIToolbar items that I add later i.e the Toolbar is black yes, but the black is overtop all the toolbar items so they are not visible.
Is there a workaround?
Thanks.
You can create a flat UIToolbar without the need to create a subclass. Simply set BackgroundColor, BackgroundImage and ShadowImage.
[toolbar setBackgroundColor:[UIColor blackColor]];
[toolbar setBackgroundImage:[[UIImage alloc] init] forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
[toolbar setShadowImage:[[UIImage alloc] init] forToolbarPosition:UIToolbarPositionAny];
Override the -drawRect: method as in your first example, but instead of drawing an image, use the UIRectFill method, like this:
[[UIColor blackColor] setFill];
UIRectFill(self.bounds);