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.
Related
I'm new on this, and I would like to get some advice because I don't know what I'm doing wrong.
I want to make an app in xcode, with a UIView with some items, and when you do something, another UIView (smaller than the first) pops up above the first UIView. The popup UIView would be a customized class.
I have started with the UIViewController template and the initial UIView, and I have linked all the items in the .storyboard, and it works. But when I create my own UIView class (from objective-C class), put the second UIView over the first in the storyboard and link it to my class, something goes wrong.
The UIView appears, but when I try to set it to hidden, it doesn't answer. It's like it's not receiving the messages, so I think I don't link it well programmatically and just appears because of the storyboard.
I don't know if I have to create another UIViewController instead of the UIView, or if this is the correct path.
Can anybody explain me a little, or just write a little code snippet with the instantiation of the second view and adding it?
Lots of thanks!!
(I paste some code, of the declaration in .h and instantiation in .m)
#import <UIKit/UIKit.h>
#import "EditView.h"
#interface ReleaseViewController : UIViewController <UIWebViewDelegate, UISearchBarDelegate> {
IBOutlet UIWebView *web;
IBOutlet UISearchBar *search;
IBOutlet EditView *evHack;
}
#property (nonatomic, retain) IBOutlet UIWebView *web;
#property (nonatomic, retain) IBOutlet UISearchBar *search;
#property (nonatomic, retain) IBOutlet EditView *evHack;
#end
- (void)viewDidLoad
{
[super viewDidLoad];
search.delegate = self;
web.delegate = self;
evHack = [evHack initWithFrame:CGRectMake(0, 44, 320, 377)];
[evHack setHidden:YES];
}
EditView Class (I still have nothing):
#import <UIKit/UIKit.h>
#interface EditView : UIView
#end
#import "EditView.h"
#implementation EditView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
NSLog(#"View created");
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
initWithFrame only works when you alloc/init an app. If its already initialized, in this case by the storyboard, just set its frame:
evHack.frame = CGRectMake(0,44, 320, 377);
I don't know what it looks like in IB, But setting its frame in code may be redundant if you set it in IB too. To check whether evHack is hooked up right, NSLog evHack in viewDidLoad. If you get nil back, it's not hooked up right.
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.
i recently got three20 integrated into my app and am trying to override the default toolbar color in TTWebController.
In TTWebController.m:118 I see that this is setting the toolbar's tintColor:
_toolbar.tintColor = TTSTYLEVAR(toolbarTintColor);
So I created my own stylesheet that subclasses TTDefaultStyleSheet and overrides toolbarTintColor
FooStyleSheet.h:
#import <Three20Style/Three20Style.h>
#import <Three20Style/TTStyleSheet.h>
#import <Three20Style/TTDefaultStyleSheet.h>
#interface FooStyleSheet : TTDefaultStyleSheet
#property (nonatomic, readonly) UIColor* toolbarTintColor;
#end
FooStyleSheet.m:
#import "FooStyleSheet.h"
#implementation RaptrStyleSheet
- (UIColor*)toolbarTintColor {
return RGBCOLOR(0, 0, 0); // should override TTDefaultStyleSheet
}
#end
and in my application:didFinishLaunchingWithOptions: i set my default stylesheet
[TTStyleSheet setGlobalStyleSheet:[[[FooStyleSheet alloc] init] autorelease]];
but when I view the TTWebController, it doesn't inherit my tintColor. If I edit TTDefaultStyleSheet.m directly:
- (UIColor*)toolbarTintColor {
return [UIColor blackColor];
}
it works as expected.
Is there something I am overlooking that is preventing my style to be picked up?
thanks,
-norm
In your header file, the #property is unnecessary - does removing this solve your problem?
A little background:
I'm a C# developer starting to mess with the iPhone (have an idea for a simple 2D game). The only MVC programming I've done was for the web (ASP.NET MVC) so although I do have an understanding in MVC, I can't wrap my mind around one thing. Here's an example to illustrate.
Say I have a simple app where all I want to do is display a big circle on the screen. I created a "View Based Application" and it gave me the basic classes to start with:
MVCConfusionAppDelegate
MVCConfusionViewController
Now since I'll be doing some custom drawing (I know I can add a subview and show the circle that way, but this is just a sample of a larger piece) I've added a class called MyCustomView and in Interface Builder set the View of the MVCConfusionViewController to be a MyCustomView.
Now here's the problem. I want to be able to set in code the size of how big the ball on the custom view should be. So I have a property on the MyCusomView like this:
#import <Foundation/Foundation.h>
#interface MyCustomView : UIView {
NSNumber *ballSize;
}
#property(nonatomic,retain)IBOutlet NSNumber *ballSize;
#end
#import "MyCustomView.h"
#implementation MyCustomView
#synthesize ballSize;
-(void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
[[UIColor redColor]set];
float floatValue = [self.ballSize floatValue];
CGRect ballRect = CGRectMake(50.0f, 50.0f,floatValue , floatValue);
CGContextFillEllipseInRect(context, ballRect);
}
#end
Then, here's my MVCConfusionViewController:
#import <UIKit/UIKit.h>
#import "MyCustomView.h"
#interface MVCConfusionViewController : UIViewController {
NSNumber *ballSize;
}
#property(nonatomic,retain)IBOutlet NSNumber *ballSize;
#end
#import "MVCConfusionViewController.h"
#import "MyCustomView.h"
#implementation MVCConfusionViewController
#synthesize ballSize;
- (void)viewDidLoad {
[super viewDidLoad];
MyCustomView *myView = (MyCustomView *)self.view;
myView.ballSize = self.ballSize;
}
And finally, the MVCConfusionAppDelegate:
#import <UIKit/UIKit.h>
#class MVCConfusionViewController;
#interface MVCConfusionAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
MVCConfusionViewController *viewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet MVCConfusionViewController *viewController;
#end
#import "MVCConfusionAppDelegate.h"
#import "MVCConfusionViewController.h"
#import "MyCustomView.h"
#implementation MVCConfusionAppDelegate
#synthesize window;
#synthesize viewController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
viewController.ballSize = [NSNumber numberWithInt:200];
[window addSubview:viewController.view];
[window makeKeyAndVisible];
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
#end
As you can see, there's an ugly cast in my viewDidLoad method. I was hoping I'd be able to make the connection of the ballSize properties in IB, but it won't let me.
So my question simply is, what's the correct way of passing this data from my view controller to my view without doing that cast? I know I'm missing something fundamental, but I just don't see it. Any help would be greatly appreciated!
EDIT: Here's the source code. http://bit.ly/uKyp9 Maybe someone can have a look and see if I'm doing anything wrong.
Are you trying to connect one IBOutlet (in the controller) to another IBOutlet (in the view)? Unfortunately, I don't think it's that easy :-)
You're also storing the data (ballSize) in the controller and the view.
I'd make MVCConfusionViewController a data source for MyCustomView, and then let MyCustomView ask its datasource for the ballSize, inside the -drawRect: method.
#class MyCustomView;
#protocol MyCustomViewDataSource
- (NSNumber *)ballSizeForMyCustomView:(MyCustomView *)view;
#end
#interface MyCustomView {
id<MyCustomViewDataSource> dataSource;
}
#property (nonatomic, assign) IBOutlet id<MyCustomViewDataSource> dataSource;
#end
#implementation MyCustomView
- (void)drawRect:(CGRect) rect {
if (self.dataSource == nil) {
// no data source, so we don't know what to draw
return;
}
float floatValue = [[self.dataSource ballSizeForMyCustomView:self] floatValue];
// ...
}
#end
In Interface Builder, hook MVCConfusionViewController up to the view's dataSource property. Then implement the protocol:
#interface MVCConfusionViewController : UIViewController <MyCustomViewDataSource> {
[...]
}
[...]
#end
#implementation MVCConfusionViewController
- (NSNumber *)ballSizeForMyCustomView:(MyCustomView *)view {
return self.ballSize;
}
#end
This way your view controller could also be the data source for multiple MyCustomViews, because the protocol method takes a MyCustomView as an argument.
If you need more than one ball, have a look at the UITableViewDataSource and implement similar methods, something like:
-(NSInteger)numberOfBallsInMyCustomView:(MyCustomView *)view;
-(NSNumber *)myCustomView:(MyCustomView *) ballSizeAtIndex:(NSInteger)index;
Your view should already be set in IB, so you can use it as is. If you want to use MyCustomView, you can do it like this:
- (void)viewDidLoad {
[super viewDidLoad];
CGRect frame = CGRectMake(0, 0, 320, 480);
MyCustomView *myView = [[MyCustomView alloc] initWithFrame:frame];
myView.backgroundColor = [UIColor greenColor];
self.view = myView;
[myView release];
CGRect rectangle = CGRectMake(20, 20, 20, 20);
[self.view drawRect:rectangle];
}
I couldn't make your drawing code work, I don't know much about that.
One way to avoid the cast would be to add a separate outlet property for the custom view on the controller, and refer to that instead.
In Interface Builder, make an instance of MyCustomView and drag it into the existing view to make it a subview, then attach it to its own outlet on the controller.
I have a view with a subview whose alpha and backgroundcolor I would like to change through the use of declared properties. I have written some code as below and it works fine to change the alpha, but the background color is not changed when the property is set to a new value. Any help would be appreciated please.
#interface MyView : UIView {
float viewAlpha;
UIColor *viewColor;
}
#property (nonatomic, assign, readwrite) float viewAlpha;
#property (nonatomic, retain, readwrite) UIColor *viewColor;
#implementation MyView
#synthesize viewAlpha, viewColor;
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.viewAlpha = 1.0;
self.viewColor = [UIColor whiteColor];
UIView *infoView = [[UIView alloc] initWithFrame:CGRectMake(0,0,50,50)];
infoView.alpha = self.viewAlpha;
infoView.backgroundColor = self.viewColor;
[self addSubview:infoView];
[infoView release];
}
return self;
}
You might need to write a custom setter and flag that your view needs to redraw when it changes. It'd be a good idea to do this for both the alpha and the color.