I want to use custom code to draw the image for UIButton. How do I go about doing that? I have the code that can go into drawRect, but that's for UIView, not UIButton.
In the Custom view's drawRect:
#implement MyCustomView
- (void)drawRect:(CGRect)rect {
UIColor *color = [UIColor blueColor];
// Vertical stroke
{
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint: CGPointMake(20, 0)];
[bezierPath addLineToPoint: CGPointMake(20, 40)];
[color setStroke];
bezierPath.lineWidth = 1;
[bezierPath stroke];
}
}
- (UIImage *)imageFromView {
[self drawRect:CGRectMake(0, 0, 40, 40)];
UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, 0.0);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
In the button code:
UIButton *button = [[UIButton alloc] init];
MyCustomView *view = [[MyCustomView alloc] init];
[button setImage:view.imageFromView forState:UIControlStateNormal];
Use your drawing code to draw into an image graphics context opened with UIGraphicsBeginImageContextWithOptions.
Pull out the image using UIGraphicsGetImageFromCurrentImageContext.
Close the image graphics context with UIGraphicsEndImageContext.
Use the image in the button.
Simple example:
UIGraphicsBeginImageContextWithOptions(CGSizeMake(100,100), NO, 0);
UIBezierPath* p =
[UIBezierPath bezierPathWithOvalInRect:CGRectMake(0,0,100,100)];
[[UIColor blueColor] setFill];
[p fill];
UIImage* im = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// im is the blue circle image, do something with it here ...
Related
I currently have the following image on which I am trying to set a border. It consists of an UIImageView with an image inside (a transparent.png)
When I try to set the border for my image (see code), it gives a border to the UIImage, but it doesn't 'snap' around my image. Is it possible to achieve that effect?
See image current implementation here.
- (UIImage*)imageWithBorderFromImage:(UIImage*)source;
{
CGSize size = [source size];
UIGraphicsBeginImageContext(size);
CGRect rect = CGRectMake(0, 0, size.width, size.height);
[source drawInRect:rect blendMode:kCGBlendModeNormal alpha:1.0];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 0.5, 1.0, 1.0);
CGContextStrokeRect(context, rect);
UIImage *testImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return testImg;
}
Try Adding a layer behind UIImageView and add a border to it that will do the trick
#define kBorderWidth 3.0.
#define kCornerRadius 8.0
CALayer *borderLayer = [CALayer layer];
CGRect borderFrame = CGRectMake(0, 0, (imageView.frame.size.width), (imageView.frame.size.height));
[borderLayer setBackgroundColor:[[UIColor clearColor] CGColor]];
[borderLayer setFrame:borderFrame];
[borderLayer setCornerRadius:kCornerRadius];
[borderLayer setBorderWidth:kBorderWidth];
[borderLayer setBorderColor:[[UIColor redColor] CGColor]];
[imageView.layer addSublayer:borderLayer];
And don't forget to import QuartzCore/QuartzCore.h
This example will draw a boarder on the layer, but change it's frame slightly to make the border around the layer.
Depending on your needs, if you don't want it to be as accurate as possible, a quick and dirty solution could be something like this:
- (UIImage *)borderedImageFromImage:(UIImage *)source andColor:(UIColor *)borderColor{
CGFloat scale = 0.95;//this determines how big the border will be, the smaller it is the bigger the border
UIImage *borderImage = [source imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIGraphicsBeginImageContextWithOptions(source.size, NO, source.scale);
[borderColor set];
[borderImage drawInRect:CGRectMake(0, 0, source.size.width, source.size.height)];
[source drawInRect:CGRectMake(source.size.width*(1-scale)/2,
source.size.height*(1-scale)/2,
source.size.width * scale,
source.size.height * scale)];
borderImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return borderImage;
}
and here is how to use it:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.heartImageView.image = [self borderedImageFromImage:[UIImage imageNamed:#"heart"] andColor:[UIColor blackColor]];
}
What this essentially does is draw the image you want twice, once in the colour of the border (slightly scaled) and once with the normal colour. Your mileage may vary depending on the image.
How can I call this function?
I am trying to call this function from -viewDidLoad.
I tried [circularImageWithImage(imageView.image, myclor, 0.2)];
static UIImage *circularImageWithImage(UIImage *inputImage,
UIColor *borderColor,
CGFloat borderWidth)
{
CGRect rect = (CGRect){ .origin=CGPointZero, .size=inputImage.size };
UIGraphicsBeginImageContextWithOptions(rect.size, NO, inputImage.scale); {
// Fill the entire circle with the border color.
[borderColor setFill];
[[UIBezierPath bezierPathWithOvalInRect:rect] fill];
// Clip to the interior of the circle (inside the border).
CGRect interiorBox = CGRectInset(rect, borderWidth, borderWidth);
UIBezierPath *interior = [UIBezierPath bezierPathWithOvalInRect:interiorBox];
[interior addClip];
[inputImage drawInRect:rect];
}
UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return outputImage;
}
You can try with this code.
UIImage *image = [UIImage imageNamed:#"yourImage.png"];
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];//set your frame
//imageView.center = self.view.center;
UIImage *modifiedImage = circularImageWithImage(image, [UIColor redColor], 1.2);//border width >= 1.0 is better. Otherwise you may not see this
imageView.image = modifiedImage;
[self.view addSubview:imageView];
UIImage *sample = circularImageWithImage(imageView.image, myclor, 0.2);
I am using below code to add text and border to selected image from cameraroll.
-(UIImage*)image:(UIImage*)image withText:(NSString*)text atPoint:(CGPoint)point{
if (text) {
CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
[image drawInRect:rect];
NSDictionary *attributes = #{NSFontAttributeName : [UIFont boldSystemFontOfSize:80],
//NSStrokeWidthAttributeName : #(4),
NSStrokeColorAttributeName : [UIColor whiteColor]};
[text drawAtPoint:point withAttributes:attributes];
CALayer *l = [self.imageView layer];
[l setBorderWidth:10.0];
[l setBorderColor:[[UIColor blueColor] CGColor]];
newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
return newImage;
}
When i click on save button in my app, i am saving edited image to cameraroll.But edited image inside cameraroll only has text without any added border. Whether i am missing anything in above code to add and save border around image? Is there any other way to add border other than CALayer?
Replace this:
CALayer *l = [self.imageView layer];
[l setBorderWidth:10.0];
[l setBorderColor:[[UIColor blueColor] CGColor]];
With this:
UIBezierPath *rectangleBezier = [UIBezierPath bezierPathWithRect:rect];
rectangleBezier.lineWidth = 20.0f; // 10 * 2 because line drawn from the center of edge
[[UIColor blueColor] setStroke];
[rectangleBezier stroke];
Remarks:
CALayer *l = [self.imageView layer]; has nothing to do with UIImage data. imageView's layer change imageView presentation. Not the content of UIImage.
I will respond to "Adding a border around an UIImage in a UIView"
From far, the easiest method is to insert another view in the view hierarchy.
[self.view insertSubview:({
UIView * border = [[UIView alloc]
initWithFrame:CGRectInset(self.imageView.frame, -1, -1)];
border.backgroundColor = [UIColor blueColor];
border;
})
belowSubview:self.imageView];
I have the following method that for some reason does NOT display the image:
- (void)drawRect:(CGRect)rect
{
float cornerRadius = self.bounds.size.width/RADIUS_RATIO;
UIBezierPath *roundedRect = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:cornerRadius];
[roundedRect addClip];
[[UIColor whiteColor] setFill];
UIRectFill(self.bounds);
[[UIColor blackColor] setStroke];
[roundedRect stroke];
CGRect imageRect = CGRectInset(self.bounds,
self.bounds.size.width * 0.5,
self.bounds.size.height * 0.5);
if (self.faceUp)
{
UIImage *cardFace = [UIImage imageNamed:[NSString stringWithFormat:
#"%#%#.png",[self rankAsStrings],self.suit]];
if (cardFace)
{
NSLog(#"%#%#.png",[self rankAsStrings],self.suit);
[cardFace drawInRect:imageRect];
} else {
NSLog(#"No Image Found: %#%#.png",[self rankAsStrings],self.suit);
}
} else {
[[UIImage imageNamed:#"Back.png"] drawInRect:imageRect];
}
}
Can someone shed some light on this?
P.S. The images are present and I do get the "NSLog(#"%#%#.png",[self rankAsStrings],self.suit);" message in the console.
TIA
I think your imageRect has 0.0 width and 0.0 height. Check the docs for CGRectInset method - it reduces original rect by 2*dx and 2*dy.
I would have done it like this :
myView.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed: #"MyProfilePic.png"]];
I'm trying to create a UIbutton that has the following characteristics:
* A custom image as its content
* Rounded corners
* A drop shadow
Using the following code will format the button to appear correctly and function but the highlight action (i.e., the darkening of the button when touched) is lost when the touch occurs. Any ideas?
+(void) styleButton:(UIButton*)button{
UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(button.bounds.origin.x, button.bounds.origin.y, button.bounds.size.width, button.bounds.size.height)];
CALayer *sublayer = [CALayer layer];
sublayer.shadowOffset = CGSizeMake(0, 3);
sublayer.shadowRadius = 5.0;
sublayer.shadowColor = [UIColor blackColor].CGColor;
sublayer.shadowOpacity = 0.8;
sublayer.frame = CGRectMake(button.bounds.origin.x, button.bounds.origin.y, button.bounds.size.width, button.bounds.size.height);
backgroundView.userInteractionEnabled = NO;
[backgroundView.layer addSublayer:sublayer];
[button insertSubview:backgroundView atIndex:0];
CALayer *imageLayer = [CALayer layer];
imageLayer.frame = sublayer.bounds;
imageLayer.cornerRadius = 10.0;
imageLayer.contents = (id) [UIImage imageNamed:#"myImage.png"].CGImage;
imageLayer.cornerRadius = 5.0f;
imageLayer.masksToBounds = YES;
[sublayer addSublayer:imageLayer];
}
Have you tried converting your backgroundView into a UIImage and add it to the button instead of adding backgroundView as a subview? That would preserve the darkening when the button is pressed:
UIGraphicsBeginImageContext(backgroundView.frame.size);
[backgroundView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[button setImage:image forState:UIControlStateNormal];
Like this (ARC enabled):
UIGraphicsBeginImageContextWithOptions(self.button.bounds.size, NO, [[UIScreen mainScreen] scale]);
CGContextRef context = UIGraphicsGetCurrentContext();
for (UIView *aView in self.button.subviews) {
CGContextSaveGState(context);
CGContextTranslateCTM(context, aView.frame.origin.x, aView.frame.origin.y);
[aView.layer renderInContext:UIGraphicsGetCurrentContext()];
CGContextRestoreGState(context);
}
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.button setImage:image forState:UIControlStateNormal];
[self.button.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
[self.button setAdjustsImageWhenHighlighted:YES];