I'm implementing a custom UIButton with minimal functionality. The .h file:
#import <Foundation/Foundation.h>
#interface CustomButton : UIButton {
}
#end
I'm encountering a compilation error at line (A) in the .m file:
- (id)initWithCoder:(NSCoder *)coder {
if(self = [super initWithCoder:coder]) {
CALayer *layer = [self layer];
NSLog(#"layer=%#",layer);
NSLog(#"delegate=%#",[layer delegate]);
#ifdef __IPHONE_3_0
layer.cornerRadius = 4.0f; // (A) error: request for member 'cornerRadius' in something not a structure or union
#endif
}
return self;
}
If I comment out line (A), I get the following output:
2009-10-08 17:35:06.681 MyApp[2596:4e07] layer=<CALayer: 0x3cdf520>
2009-10-08 17:35:06.683 MyApp[2596:4e07] delegate=<CustomButton: 0x3cdaff0; baseClass = UIButton; frame = (9 212; 255 55); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x3cdf520>>
According to the documentation, CALayer should have a cornerRadius property. I'm using iPhone SDK 3.1 and even added an #ifdef to confirm this.
Can someone please show me where I've overlooked the obvious?
Thanks
Make sure you #import <QuartzCore/QuartzCore.h> into your header or implementation file.
Try this,
#import <QuartzCore/QuartzCore.h>
Button.layer.cornerRadius = 15.0;
[Button.layer setMasksToBounds:YES];
Related
I'm not sure if I'm missing something but what should be a simple task just doesn't want to work. I'm trying to add a drop shadow to a UIView in iOS 6. I'm using storyboards and auto layout. I'm drawing the UIView in the storyboard scene with a white background. Then linking it to an IBOutlet.
in my .h file I declare the IBOutlet and the property
#import <UIKit/UIKit.h>
#interface LoginViewController : UIViewController {
IBOutlet UIView *_loginPanel;
}
#property (nonatomic, retain) IBOutlet UIView *_loginPanel;
#end
and in my .m i import QuartzCore
#import <QuartzCore/QuartzCore.h>
Synthesize the property
#synthesize _loginPanel;
and do the following in my ViewDidLoad method
- (void)viewDidLoad
{
[super viewDidLoad];
UIBezierPath *path = [UIBezierPath bezierPathWithRect:_loginPanel.bounds];
_loginPanel.layer.masksToBounds = NO;
_loginPanel.layer.shadowColor = [UIColor blackColor].CGColor;
_loginPanel.layer.shadowOpacity = 0.7f;
_loginPanel.layer.shadowOffset = CGSizeMake(-5.0f, -5.0f);
_loginPanel.layer.shadowRadius = 8.0f;
_loginPanel.layer.shadowPath = path.CGPath;
_loginPanel.layer.shouldRasterize = YES;
}
but i get no shadow just the white UIView I defined in the storyboard.
Any help would be greatly appreciated.
Thanks,
Richard
maybe you can change this line :
UIBezierPath *path = [UIBezierPath bezierPathWithRect:_loginPanel.bounds];
with :
CGPathRef path = [UIBezierPath bezierPathWithRect:_loginPanel.bounds].CGPath;
and off course remove ".CGPath" in the shadowPath line.
Maybe you can try to make this in the viewDidAppear method to see if it's not a problem of resizing.
I'm trying to create a CGRect inside of a custom view (rectView) that will move up and down as you move a slider.
My slider's IBAction calls the following method: (which get's called fine)
- (void)moveRectUpOrDown:(int)y
{
self.verticalPositionOfRect += y;
[self setNeedsDisplay];
}
My drawRect method:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGFloat size = 100;
self.rect = CGRectMake((self.bounds.size.width / 2) - (size / 2),
self.verticalPositionOfRect - (size / 2),
size,
size);
CGContextAddRect(context, self.rect);
CGContextFillPath(context);
}
My custom view's initWithFrame calls the drawRect method using setNeedsDisplay, but for some reason the moveRectUpOrDown won't call drawRect.
Any ideas what I'm doing wrong?
For clarity the entire implementation is below:
//ViewController.h
#import <UIKit/UIKit.h>
#import "rectView.h"
#interface ViewController : UIViewController
#property (strong, nonatomic) IBOutlet rectView *rectView;
- (IBAction)sliderChanged:(id)sender;
#end
//ViewController.m
#import "ViewController.h"
#implementation ViewController
#synthesize rectView;
- (void)viewDidLoad
{
[super viewDidLoad];
self.rectView = [[rectView alloc] initWithFrame:self.rectView.frame];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (IBAction)sliderChanged:(id)sender
{
UISlider *slider = sender;
CGFloat sliderValue = slider.value;
[self.rectView moveRectUpOrDown:sliderValue];
}
#end
//rectView.h
#import <UIKit/UIKit.h>
#interface rectView : UIView
- (void)moveRectUpOrDown:(int)y;
#end
//rectView.m
#import "rectView.h"
#interface rectView ()
#property CGRect rect;
#property int verticalPositionOfRect;
#end
#implementation rectView
#synthesize rect, verticalPositionOfRect;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.verticalPositionOfRect = (self.bounds.size.height / 2);
[self setNeedsDisplay];
}
return self;
}
- (void)moveRectUpOrDown:(int)y
{
self.verticalPositionOfRect += y;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGFloat size = 100.0;
self.rect = CGRectMake((self.bounds.size.width / 2) - (size / 2),
self.verticalPositionOfRect - (size / 2),
size,
size);
CGContextAddRect(context, self.rect);
CGContextFillPath(context);
}
#end
Thanks for the help :)
OK so the answer is the view is never actually added to the viewController's view..
You have an IBOutlet to your rectView - so I assume you dragged a UIView component onto the view in Interface Builder and then changed it's class to rectView, which is all fine BUT in viewDidLoad you wipe over this object with a new one
self.rectView = [[rectView alloc] initWithFrame:self.rectView.frame];
So this is now no longer the object that was loaded from the xib.
Subsequently this view is never actually added to the view hierarchy so it's never going to draw itself as it does not make sense.
So the solution is to remove the line I highlighted above.
Notes
I would probably still go with my other answer for such an implementation but it's helpful to get tripped up and learn new things.
rectView does not follow naming conventions. Ideally you should start your class name with a 2-3 letter prefix (possibly your initial's or company name) followed by a camel cased named.
I don't see how you initialize CGFloat size. Can you put a value in there and see how it works? The rest of the code looks okay to me.
An easier thing would be to just add a UIView and animate this around.
Add an ivar for this UIView
// .h
#property (nonatomic, strong) UIView *animatedView;
// .m
#synthesize animatedView = _animatedView;
then just replace your logic with this
- (void)moveRectUpOrDown:(int)y;
{
CGRect frame = self.animatedView.frame;
frame.origin.y += y;
// If you want the change to animate uncomment this
// [UIView animateWithDuration:0.25f
// animations:^{
// self.animatedView.frame = frame;
// }];
// If you don't want the change to animate uncomment this
// self.animatedView.frame = frame;
}
I have requirement in which I have tableview as a subview of imageview. Now when the user zooms-in , the text inside the tableview is getting blur. Is there any way to manipulate it at time of zoom-in?
Please follow the steps which is below.
Don't set the position of image statically i mean by giving coordinate.Set the position dynamically or at the run time it will take position based on current window or zoom in zoom out position label,i am not pretty much sure because i havn't faced this situation earlier but as i think it might be use case scenario for solving your problem.
Thanks
I have achieved it by subclassing CALayer for labels. Thanks all for help.
Subclass label as follows :
TiledLable.h file ::
#import <UIKit/UIKit.h>
#import "FastCATiledLayer.h"
#interface TiledLable : UILabel
{
}
#end
TiledLale.m file ::
#import "TiledLable.h"
#import <QuartzCore/QuartzCore.h>
#implementation TiledLable
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// Initialization code.
FastCATiledLayer *tiledLayer = (FastCATiledLayer *)[self layer];
tiledLayer.levelsOfDetail = 2;
tiledLayer.levelsOfDetailBias = 2;
tiledLayer.tileSize = CGSizeMake(1024.0,1024.0);
tiledLayer.contents = nil;
self.layer.contents = nil;
}
return self;
}
// Set the layer's class to be CATiledLayer.
+ (Class)layerClass
{
return [FastCATiledLayer class];
}
- (void)dealloc
{
((CATiledLayer *)[self layer]).delegate = nil;
[self removeFromSuperview];
[self.layer removeFromSuperlayer];
[super dealloc];
}
#end
I have this super simple example, and I'm not sure why it is not working. drawRect Never gets called. I just want a square to draw and be red. What am I doing wrong?
//Controller.h
#import <Foundation/Foundation.h>
#class CustomView;
#interface Controller : NSObject
#property (nonatomic, retain) CustomView *cv;
#end
//Controller.m
#import "Controller.h"
#import "CustomView.h"
#implementation Controller
#synthesize cv;
- (void) awakeFromNib {
NSLog(#"awakeFromNib called");
CGRect theFrame = CGRectMake(20, 20, 100, 100);
cv = [[CustomView alloc] initWithFrame:theFrame];
UIWindow *theWindow = [[UIApplication sharedApplication] keyWindow];
[theWindow addSubview:cv];
[cv setNeedsDisplay];
}
#end
//CustomView.h
#import <UIKit/UIKit.h>
#interface CustomView : UIView
#end
//CustomView.m
#import "CustomView.h"
#implementation CustomView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
NSLog(#"initWithFrame called");
}
return self;
}
- (void)drawRect:(CGRect)rect {
NSLog(#"drawRect called");
self.backgroundColor = [UIColor redColor];
}
#end
You aren't drawing anything in your drawRect. You are just setting a property on the view. If you have overridden drawRect, nothing will be drawn - try calling [super drawRect:rect] (after setting your background colour) or simply draw the square yourself using:
[[UIColor redColor] set];
[[UIBezierPath bezierPathWithRect:self.bounds] fill];
EDIT:
I see your drawRect is not even being called. I'm not sure of your nib structure, but try adding cv as a subview to self.view in your controller rather than adding it to the window. Also, note that you are not retaining cv (use self.cv = rather than cv =) but this shouldn't be an issue since your view will retain it.
Rather than doing a forward reference to your CustomView class in your Controller implementation:
#class CustomView;
Trying importing the class header file:
#import "CustomView.h"
Because you require access to the API you have defined when you call:
cv = [[CustomView alloc] initWithFrame:theFrame];
A forward reference tells the compiler that there will be an implementation for the class you are using at compile time and it is best used in header files. In implementation files, I find it best to import the header.
here's the current situation:
TestViewController.h:
#import <UIKit/UIKit.h>
#interface TestViewController : UIViewController {
}
#end
TestViewController.m:
#import "TestViewController.h"
#import "draw.h"
#implementation TestViewController
- (void)viewDidLoad {
draw.rectColor = [UIColor colorWithHue:0.6 saturation:0.6 brightness:0.6 alpha:1].CGColor;
[draw setNeedsDisplay];
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)dealloc {
[super dealloc];
}
#end
draw.h:
#import <UIKit/UIKit.h>
#interface draw : UIView {
UIColor* rectColor;
}
#property (retain) UIColor* rectColor;
#end
draw.m:
#import "draw.h"
#implementation draw
#synthesize rectColor;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code.
}
return self;
}
- (void)drawRect:(CGRect)rectangle {
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorRef myColor = [UIColor colorWithHue:0 saturation:1 brightness:0.61 alpha:1].CGColor;
CGContextSetFillColorWithColor(context, myColor);
CGContextAddRect(context, CGRectMake(0, 0, 95.0, 110.0));
CGContextFillPath(context);
}
- (void)dealloc {
[super dealloc];
}
#end
then in the Interface Builder I've created a 90x115 UIView and set it's Class Identity to "draw".
When I run the application (without the two non-compiling lines) it displays a nice red rectangle in the middle of the screen. My goal is it be able to change the color of the rectangle from within my TestViewController. However when I compile the test app I get the following compiler errors:
error: accessing unknown 'setRectColor:' class method
error: object cannot be set - either readonly property or no setter found
warning: 'draw' may not respond to '+setNeedsDisplay'
I know I am missing "a link" between my TestViewController and draw, but can't figure out how to go about implementing it. I have tried various tricks, but nothing worked.
Could someone please explain what needs to be done in order for
draw.rectColor = [UIColor colorWithHue:0.6 saturation:0.6 brightness:0.6 alpha:1].CGColor;
[draw setNeedsDisplay];
to compile and work ?
(I would use this knowledge to create a different method in TestViewController, I am just testing it inside viewDidLoad)
In the code you posted, you set the rectColor property and call setNeedsDisplay: on draw, but draw is your class. You need to do it to the instance. You shouldn't need to create a new property for this because UIViewController defines the view property. Just use self.view instead of draw in your viewDidLoad method. Also, remove the .CGColor at the end of the line.
Second, your drawRect: method ignores that color and uses its own. Change
CGColorRef myColor = [UIColor colorWithHue:0 saturation:1 brightness:0.61 alpha:1].CGColor;
to
CGColorRef myColor = self.rectColor.CGColor;
The big problem here is that you haven't declared a property for draw; you have to do this and link it up to your Interface Builder object if you want to access it. The solution is to create a property that will hold the draw object, and synthesize its setters and getters using #synthesize. (that last piece is why you're getting the error.)
Once you change the code to what I have below, you'll need to make the proper connection in Interface Builder, or else you'll find that your code changes simply have no effect, even though they're error free.
Capitalize your class names (always!), and then try this:
TestViewController.h:
#import <UIKit/UIKit.h>
#class Draw; //forward class declaration
#interface TestViewController : UIViewController {
IBOutlet Draw *drawCopy;
}
#property (nonatomic, retain) Draw *drawCopy;
#end
Then, for TestViewController.m:
#import "TestViewController.h"
#import "Draw.h"
#implementation TestViewController
#synthesize drawCopy;
-(void) viewDidLoad {
self.drawCopy.rectColor = [UIColor colorWithHue:0.6 saturation:0.6 brightness:0.6 alpha:1];
[self.drawCopy setNeedsDisplay];
[super viewDidLoad];
}
- (void)dealloc {
[drawCopy release];
[super dealloc];
}
#end
I think that should do the trick.
you definde UIColor* rectColor; but u write an CGColor too it
draw.rectColor = [UIColor colorWithHue:0.6 saturation:0.6 brightness:0.6 alpha:1].CGColor;
try
self.drawCopy.rectColor = [UIColor colorWithHue:0.6 saturation:0.6 brightness:0.6 alpha:1];