iOS7 custom button become transparent when highlighted - iphone

I just create my own custom button that seem like iOS6 and earlier buttons but on iOS7 my CustomButton turn transparent when highlighted.
I have try to set property adjustsImageWhenHighlighted at NO but nothing change, [self setAlpha:1.f] doesn't work either.
Following, my init method:
-(void) baseInit:(CGRect)frame :(CGFloat *)colorsNormal :(CGFloat *)colorsHighlighted :(CGFloat *)colorsDisabled
{
self.layer.borderWidth=1.0f;
self.layer.borderColor=[[UIColor colorWithRed:0.67f green:0.67f blue:0.67f alpha:1.0f] CGColor];
self.layer.cornerRadius=7.0f;
self.clipsToBounds = YES;
UIImage *image = [self generateUIImageWithGradient:frame :colorsNormal];
[self setBackgroundImage:image forState:UIControlStateNormal];
[self setTitleColor:[UIColor colorWithRed:0.22f green:0.33f blue:0.53f alpha:1.0f] forState:UIControlStateNormal];
UIImage *image2 = [self generateUIImageWithGradient:frame :colorsHighlighted];
[self setBackgroundImage:image2 forState:UIControlStateHighlighted];
[self setTitleColor:[UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f] forState:UIControlStateHighlighted];
UIImage *image3 = [self generateUIImageWithGradient:frame :colorsDisabled];
[self setBackgroundImage:image3 forState:UIControlStateDisabled];
}
-(id) generateUIImageWithGradient:(CGRect)frame :(CGFloat *)colors
{
CGSize size = CGSizeMake(frame.size.width, frame.size.height);
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
size_t gradientNumberOfLocations = 2;
CGFloat gradientLocations[2] = {0.0, 1.0};
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorspace, colors, gradientLocations, gradientNumberOfLocations);
CGContextDrawLinearGradient(context, gradient, CGPointMake(0, 0), CGPointMake(0, size.height), 0);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
CGGradientRelease(gradient);
CGColorSpaceRelease(colorspace);
UIGraphicsEndImageContext();
return image;
}
And my method call :
CGFloat colorsNormal [] = {1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f};
CGFloat colorsHighlighted [] = {0.03f,0.55f,0.97f,1.0f,0.0f,0.37f,0.90f,1.0f};
CGFloat colorsDisabled [] = {1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f};
[self baseInit:rect :colorsNormal :colorsHighlighted :colorsDisabled];
That work like a charm on iOS6 and NormalState work on iOS7.
Thanks for your help

Set the button type property to UIButtonTypeCustom seem to work. Problem solved.

Related

Color Overlay UIButton Image

I'm having this issue when trying to overlay a UIButton's Image with a color.
The overlay color is appearing underneath the Image.
Here is the code that I have in my drawRect method (I have subclassed UIButton):
(void)drawRect:(CGRect)rect
{
CGRect bounds = self.imageView.bounds;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextTranslateCTM(context, 0.0, self.imageView.image.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextClipToMask(context, bounds, [self.imageView.image CGImage]);
CGContextFillRect(context, bounds);
}
Any ideas on how to get the red color on top of the Image?
Succeeded with this hacky code:
- (void)drawRect:(CGRect)rect
{
UIImage* img = [self imageForState:UIControlStateNormal];
[self setImage:nil forState:UIControlStateNormal];
CGRect bounds = self.imageView.bounds;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor colorWithRed:1 green:0 blue:0 alpha:0.2].CGColor);
CGContextDrawImage(context, bounds, img.CGImage);
CGContextFillRect(context, bounds);
}
It seems the image is drawn after drawRect so unless you make it nil, it goes on top of whatever you draw there.
This is solution is not final. I'll edit it with what I get to next.
EDIT: The right solution is to add a semi-transparent UIView on top of the image like this:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
UIView* tintView = [[UIView alloc] initWithFrame:self.bounds];
tintView.backgroundColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:0.2];
tintView.userInteractionEnabled = NO;
[self addSubview:tintView];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
UIView* tintView = [[UIView alloc] initWithFrame:self.bounds];
tintView.backgroundColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:0.2];
tintView.userInteractionEnabled = NO;
[self addSubview:tintView];
}
return self;
}
Note: you should do this in your UIButton subclass.

Face detection is not working properly on resized images specially in Device, why?

Here is the code I am using to detect face from an Image:
- (void)detectFaces:(UIImageView *)photo
{
CIImage *coreImage = [CIImage imageWithCGImage:photo.image.CGImage];
CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeFace
context:nil
options:[NSDictionary dictionaryWithObject:CIDetectorAccuracyHigh
forKey:CIDetectorAccuracy]];
NSArray* features = [detector featuresInImage:coreImage];
for(CIFaceFeature* faceFeature in features)
{
NSLog(#"self.view %#",NSStringFromCGRect(self.view.frame));
NSLog(#"self.view %#",NSStringFromCGRect(self.view.bounds));
NSLog(#"self.vounds %#",NSStringFromCGRect(faceFeature.bounds));
CGFloat faceWidth = faceFeature.bounds.size.width;
UIView* faceView = [[UIView alloc] initWithFrame:faceFeature.bounds];
faceView.layer.borderWidth = 1;
faceView.layer.borderColor = [[UIColor redColor] CGColor];
[self.view addSubview:faceView];
if(faceFeature.hasLeftEyePosition)
{
UIView* leftEyeView = [[UIView alloc] initWithFrame:CGRectMake(faceFeature.leftEyePosition.x-faceWidth*0.15, faceFeature.leftEyePosition.y-faceWidth*0.15, faceWidth*0.3, faceWidth*0.3)];
[leftEyeView setBackgroundColor:[[UIColor blueColor] colorWithAlphaComponent:0.3]];
[leftEyeView setCenter:faceFeature.leftEyePosition];
leftEyeView.layer.cornerRadius = faceWidth*0.15;
[self.view addSubview:leftEyeView];
}
if(faceFeature.hasRightEyePosition)
{
UIView* leftEye = [[UIView alloc] initWithFrame:CGRectMake(faceFeature.rightEyePosition.x-faceWidth*0.15, faceFeature.rightEyePosition.y-faceWidth*0.15, faceWidth*0.3, faceWidth*0.3)];
[leftEye setBackgroundColor:[[UIColor blueColor] colorWithAlphaComponent:0.3]];
[leftEye setCenter:faceFeature.rightEyePosition];
leftEye.layer.cornerRadius = faceWidth*0.15;
[self.view addSubview:leftEye];
}
if(faceFeature.hasMouthPosition)
{
UIView* mouth = [[UIView alloc] initWithFrame:CGRectMake(faceFeature.mouthPosition.x-faceWidth*0.2, faceFeature.mouthPosition.y-faceWidth*0.2, faceWidth*0.4, faceWidth*0.4)];
[mouth setBackgroundColor:[[UIColor greenColor] colorWithAlphaComponent:0.3]];
[mouth setCenter:faceFeature.mouthPosition];
mouth.layer.cornerRadius = faceWidth*0.2;
[self.view addSubview:mouth];
}
}
}
This is code that I have used to resize an image:
- (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
//UIGraphicsBeginImageContext(newSize);
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
and finally I am calling detect face method like this:
UIImageView *inputImage = [[UIImageView alloc] initWithImage:[self imageWithImage:[UIImage imageNamed:#"facedetectionpic.jpg"] scaledToSize:CGSizeMake(320, 460)]];
[self.view addSubview:inputImage];
[inputImage setTransform:CGAffineTransformMakeScale(1, -1)];
[self.view setTransform:CGAffineTransformMakeScale(1, -1)];
[self performSelectorInBackground:#selector(detectFaces:) withObject:inputImage];
It is working properly in Simulator but not in device. Can anyone please help me on this.
Simulator:
Device:
When I have changed options in UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0); to UIGraphicsBeginImageContextWithOptions(newSize, NO, 1.0); it started working even in device. Solved the issue.
Change options in UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0); to
UIGraphicsBeginImageContextWithOptions(newSize, NO, 1.0); it will work.

UIImageView round corner has white background

The rounded corner has white background.
I followed other SO answers but don't know why i'm getting this whites
Bellow is the code.
UIView* testView = [[[UIView alloc] initWithFrame: self.animationView.bounds] autorelease];
UIImageView* testImageView = [[[UIImageView alloc] initWithImage:backImage] autorelease];
[testView addSubview: testImageView];
testImageView.backgroundColor = [UIColor clearColor];
CALayer* layer = [testView layer];
bool prev = layer.masksToBounds;
layer.masksToBounds = YES;
layer.cornerRadius = 30;
testView.clipsToBounds = YES;
UIImage* image = [UIImage captureView: testView];
//this image has the white regions in the four corners.
// when seen on iphone photo album
+ (UIImage*)captureView:(UIView*)view
{
CGSize size = view.bounds.size;
CGContextRef context = CreateARGBBitmapContext(size);
CGContextTranslateCTM(context, 0, size.height);
CGContextScaleCTM(context, 1.0, -1.0);
[view.layer renderInContext: context];
CGImageRef imageRef = CGBitmapContextCreateImage(context);
UIImage* img = [UIImage imageWithCGImage: imageRef];
CGImageRelease(imageRef);
CGContextRelease(context);
return img;
}
Add [testImageView setClipsToBounds:YES].
It might be that you have to set testImageView.opaque = NO.

Change background color of UIButton when Highlighted

Hi I want to change the UIButton background color which user Tap on the button.
I am showing background color using gradient, when user tap I need to change the gradient color.
[btn setTitle: #"Next" forState:UIControlStateNormal];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = btn.bounds;
gradient.cornerRadius = 10.0f;
locations = [[NSArray alloc] initWithObjects: 0.0f, 0.0f, 0.0f,0.0f, nil];
[gradient setLocations:locations];
colorNext = [[NSArray alloc] initWithObjects:…., nil];
gradient.colors = colorNext;
[locations release];
[btn.layer insertSublayer:gradient atIndex:0];
btn.titleLabel.textColor = [UIColor blackColor];
Changing the internal layer hierarchy of a UIButton is not recommended since it may break in a future update of the iOS. Also, it may cause Apple to reject your application. A better solution would be to create a button subclass. Here is an example of how to do it:
#interface MyButton : UIButton
#end
#implementation MyButton
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
[self addObserver:self forKeyPath:#"highlighted" options:NSKeyValueObservingOptionNew context:NULL];
}
return self;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
if (self.highlighted == YES)
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
const CGFloat *topGradientColorComponents = CGColorGetComponents([UIColor whiteColor].CGColor);
const CGFloat *bottomGradientColorComponents = CGColorGetComponents([UIColor blackColor].CGColor);
CGFloat colors[] =
{
topGradientColorComponents[0], topGradientColorComponents[1], topGradientColorComponents[2], topGradientColorComponents[3],
bottomGradientColorComponents[0], bottomGradientColorComponents[1], bottomGradientColorComponents[2], bottomGradientColorComponents[3]
};
CGGradientRef gradient = CGGradientCreateWithColorComponents(rgb, colors, NULL, sizeof(colors) / (sizeof(colors[0]) * 4));
CGColorSpaceRelease(rgb);
CGContextDrawLinearGradient(ctx, gradient, CGPointMake(0, 0), CGPointMake(0, self.bounds.size.height), 0);
CGGradientRelease(gradient);
}
else
{
// Do custom drawing for normal state
}
}
- (void)dealloc
{
[self removeObserver:self forKeyPath:#"highlighted"];
[super dealloc];
}
#end
You may need to modify it a bit to get it to do what you want but I think you get the basic idea.
Try this:
[Button addTarget:self action:#selector(doSomething:) forControlEvents:UIControlEventTouchUpInside];
[Button addTarget:self action:#selector(setBgColorForButton:) forControlEvents:UIControlEventTouchDown];
[Button addTarget:self action:#selector(clearBgColorForButton:) forControlEvents:UIControlEventTouchDragExit];
-(void)setBgColorForButton:(UIButton*)sender
{
[sender setBackgroundColor:[UIColor blackColor]];
}
-(void)clearBgColorForButton:(UIButton*)sender
{
[sender setBackgroundColor:[UIColor redColor]];
}
-(void)doSomething:(UIButton*)sender
{
double delayInSeconds = 0.3;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[sender setBackgroundColor:[UIColor redColor]];
});
//do something
}
You can use this method to create and solid UIImage of specified color and then apply it to your button. I've made a category for UIImage to do this.
+ (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size
{
UIGraphicsBeginImageContext(size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextFillRect(context, (CGRect){.size = size});
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
+ (UIImage *)imageWithColor:(UIColor *)color
{
return [UIImage imageWithColor:color size:CGSizeMake(1, 1)];
}
Usage:
[button setBackgroundImage:[UIImage imageWithColor:[UIColor redColor]]
forState:UIControlStateNormal];
As Matthias pointed out, you can safely use 1x1 image for your button background – it will be stretched to fill the button.
I found this AYUIButton on GitHub and it works perfectly :)
Here is sample code:
[btn setBackgroundColor:[UIColor redColor] forState:UIControlStateNormal];
[btn setBackgroundColor:[UIColor blueColor] forState:UIControlStateHighlighted];
When you set the TintColor of the Button it works when highlighted
[YourButton setTintColor:[UIColor color]];
Swift
Extension for UIButton that let you specify background color for each state:
https://github.com/acani/UIButtonBackgroundColor
Please note that for iphone 6 plus you should change the following, inside the extension in the .swift class, that will fix it for all the versions:
//let rect = CGRect(x: 0, y: 0, width: 0.5, height: 0.5) comment this line
let rect = CGRect(x: 0, y: 0, width: 1, height: 1)

iPhone SDK: Rendering a CGLayer into an image object

I am trying to add a curved border around an image downloaded and to be displayed in a UITableViewCell.
In the large view (ie one image on the screen) I have the following:
productImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:product.image]];
[productImageView setAlpha:0.4];
productImageView.frame = CGRectMake(10.0, 30.0, 128.0, 128.0);
CALayer *roundedlayer = [productImageView layer];
[roundedlayer setMasksToBounds:YES];
[roundedlayer setCornerRadius:7.0];
[roundedlayer setBorderWidth:2.0];
[roundedlayer setBorderColor:[[UIColor darkGrayColor] CGColor]];
[self addSubview:productImageView];
In the table view cell, to get it to scroll fast, an image needs to be drawn in the drawRect method of a UIView which is then added to a custom cell.
so in drawRect
- (void)drawRect:(CGRect)rect {
...
point = CGPointMake(boundsX + LEFT_COLUMN_OFFSET, UPPER_ROW_TOP);
//CALayer *roundedlayer = [productImageView layer];
//[roundedlayer setMasksToBounds:YES];
//[roundedlayer setCornerRadius:7.0];
//[roundedlayer setBorderWidth:2.0];
//[roundedlayer setBorderColor:[[UIColor darkGrayColor] CGColor]];
//[productImageView drawRect:CGRectMake(boundsX + LEFT_COLUMN_OFFSET, UPPER_ROW_TOP, IMAGE_WIDTH, IMAGE_HEIGHT)];
//
[productImageView.image drawInRect:CGRectMake(boundsX + LEFT_COLUMN_OFFSET, UPPER_ROW_TOP, IMAGE_WIDTH, IMAGE_HEIGHT)];
So this works well, but if I remove the comment and try to show the rounded CA layer the scrolling goes really slow.
To fix this I suppose I would have to render this image context into a different image object, and store this in an array, then set this image as something like:
productImageView.image = (UIImage*)[imageArray objectAtIndex:indexPath.row];
My question is "How do I render this layer into an image?"
TIA.
This is what I got to work well.
- (UIImage *)roundedImage:(UIImage*)originalImage
{
CGRect bounds = CGRectMake(0.0, 0.0, originalImage.size.width, originalImage.size.height);
UIImageView *imageView = [[UIImageView alloc] initWithImage:originalImage];
CALayer *layer = imageView.layer;
imageView.frame = bounds;
[layer setMasksToBounds:YES];
[layer setCornerRadius:7.0];
[layer setBorderWidth:2.0];
[layer setBorderColor:[[UIColor darkGrayColor] CGColor]];
UIGraphicsBeginImageContext(bounds.size);
[layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *anImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[imageView release];
return anImage;
}
Then to scale the image, I found this in the lazy loading example:
#define kAppIconHeight 48
CGSize itemSize = CGSizeMake(kAppIconHeight, kAppIconHeight);
UIGraphicsBeginImageContext(itemSize);
CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
[image drawInRect:imageRect];
self.appRecord.appIcon = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
You are on the right track with your own comment.
- (UIImage *)roundedImage:(UIImage*)originalImage;
{
CGRect bounds = originalImage.bounds;
CGImageRef theImage = originalImage.CGImage;
CALayer *roundedlayer = [CALayer layer];
roundedlayer.position = CGPointMake(0.0f,0.0f);
roundedlayer.bounds = bounds;
[roundedlayer setMasksToBounds:YES];
[roundedlayer setCornerRadius:7.0];
[roundedlayer setBorderWidth:2.0];
[roundedlayer setBorderColor:[[UIColor darkGrayColor] CGColor]];
roundedlayer.contents = theImage;
UIGraphicsBeginImageContext(bounds.size); // creates a new context and pushes it on the stack
CGContextBeginTransparencyLayerWithRect(UIGraphicsGetCurrentContext(), bounds, NULL);
CGContextClearRect(UIGraphicsGetCurrentContext(), bounds);
[roundedlayer drawInContext:UIGraphicsGetCurrentContext()];
UIImage *anImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext(); //releases new context and removes from stack
return anImage;
}
I would pre-render these and store them in your image array so they are not calculated during your drawRect, but set in your
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
method.