Am not sure where an wrong. I have an UIImageView in Storyboard, which am connecting with an IBOutlet to the code. I want to add a shadow (during runtime) to the UIImageView. And am using this code snippet for that (got this help from a stackoverflow post) :
-(void) awakeFromNib {
self.imageViewTopBar.layer.shadowColor = [UIColor blueColor].CGColor;
self.imageViewTopBar.layer.shadowOffset = CGSizeMake(0, 5);
self.imageViewTopBar.layer.shadowOpacity = 1.0;
self.imageViewTopBar.layer.shadowRadius = 3.0;
//self.imageViewTopBar.layer.masksToBounds = YES;
//self.imageViewTopBar.clipsToBounds = NO;
self.imageViewTopBar.layer.shouldRasterize = YES;
}
but it simply doesn't work. Any help please? I don't see any reason why it shouldn't work.
My environment : XCode 4.5.2, iOS 5, iPhone 4
You should use -viewDidLoad to do this, check out this post: Accessing View in awakeFromNib?
Try putting it into viewDidLoad. I assume you've included the quartzcore framework. I think it would throw compiler error if not...
Do you have checked, in the xib, clipToBounds to YES?
If YES you should uncheck the clipToBounds and reorganize your view hierarchy.
Normally when i have an imageView with a shadow i use this hierarchy
(aImageView) ClipToBounds=YES
|
|
(aView) Shadow setted here
|
|
(Superview)
aView has the same frame size of the aImageView
Related
I'm trying to create a uiview programmatically and adding it to a stack_view which was also programmatically created and added to the view.
This is the code:
the .h
#interface ViewController : UIViewController
#property (strong, nonatomic, nullable) UIStackView * stack;
#end
the .m
#implementation viewController
#synthesize stack;
- (void) viewDidLoad {
[super viewDidLoad];
CGRect * vframe = self.view.frame;
// - Option 1
stack = [[UIStackView alloc] initWithFrame:CGRectMake(vframe.origin.x, 100,vframe.size.width,300)];
stack.axis = UILayoutConstraintAxisHorizontal;
stack.aligment = UIStackViewAligmentTop;
stack.distribution = UIStackViewDistributionFill;
[self.vew addSubview:stack];
// Option 2
// stack.traslateAutorezisingMaskIntoConstraints = NO;
// [stack.leadingAnchor constraintsEqualToAnchor: self.view.leadingAnchor].active = YES;
// [stack.topAnchor constraintsEqualToAnchor: self.view.topAnchor constant: 100].active = YES;
UIView * pView = [[UIView alloc] init];
pView.backgroundColor = [UIColor blueColor];
[stack addArrangedSubview:pView];
}
#end
This code does not show the view at all, I've tried to prove the option 2 (appeared commented in the code) and it does not work either. It is not supposed that the view, upon inserted in the stack, will get the size of the stack, since the distribution of it is "Fill"?. None of this work either even if I define Pview with frame=CGRectMakeRect(0,0,self.view.frame.size.width,100), for instance.
What am I doing wrong?
EDIT: I already fix the misspelled in the code (the * in the CGRect and the self.vew instead of self.view). I made these mistakes when I was manually copying the code, I did not copy and paste the code; tha's is why is made them and that's why the original code compile well
To diagnose this first test the pView. Init it with a fixed size like CGRectMake(100,100,100,100) and add it directly to the viewContoller's view. You should be able to see it no problem if not you have a deeper issue.
If that goes well try the UIStackView with a fixed size. Color its background to see it better if you need. If you still dont see it then double check it still has the correct frame in viewDidAppear of the viewController. It might have adjusted itself after creation. If that is correct go to Debug -> View Debugging -> Capture View Heirachy in Xcode after you have it up in the simulator. If you dont see it there then there was an issue adding it as a subview (note the typo [self.vew addSubview:stack];)
If that goes well then there is a problem with [stack addArrangedSubview:pView]. Similar to the previous step, loop through all the arrangedSubviews in UIStackView in viewDidAppear of its viewController.
CGRect vframe = self.view.frame;
In viewDidLoad, your self.view.frame has not been calculated yet. You need to do this in viewDidLayoutSubviews or viewDidAppear. both of these will get called multiple times so be careful.
EDIT:
As suggested below by danh (I overlooked it) you should remove * from the above line , also, you have several misspelling in your code, don't know how this code really even compiled for you.
I just updated my Xcode ver from 7.3 to 8.0 and some buttons borders disappeared.
The code looks fine, so I really don't know what happened to the layers.
btw - in some other controllers I can see the layers borders.
self.button.layer.borderColor = borderColor.CGColor;
self.button.layer.borderWidth = 2;
self.button.layer.cornerRadius = CGRectGetHeight(self.button.frame) / 2;
before: (The image is only for example - the borders looks different at real time)
now:
The reason is that XCode 8 introduces a new way to zoom in Storyboards.
Before XCode 8, in the view controller life cycle, frames were not known in viewDidLoad (or in properties didSet). You had to wait until viewDidLayoutSubviews (which is when Autolayout had finished applying the constraints to determine the frames of every subview in the main view.
But bounds were accessible before that: they were just set to the size of the IBOutlet in the storyboard.
In XCode 8, things are different : due to their new zooming system, even the boundsare not correct before ViewDidLayoutSubviews (they may exist but with dummy values like 1000 x 1000).
In conclusion :
you can use such things as cornerRadius in viewDidLoad or in the IBOutlet
didSet, as long as you use a fixed value
if you need to define your cornerRadius based on bounds, then do so in viewDidLayoutSubviews, or use NSLayoutConstraints (their value is fixed and known from Autolayout)
if you need to use cornerRadius in views (like UITableViewCell or UICollectionViewCell subclasses), then you can either do so in layoutSubviews (but then you need to give either a fixed value or a NSLayoutConstraint constant to cornerRadius), or in awakeFromNib(in that case, just add self.layoutIfNeeded before doing anything frame- or boounds-related, in order to force the cell to recalculate its subviews' frame).
I think problem in it:
CGRectGetHeight(self.button.frame) / 2;
When you set corner i think height button don't have value or value to larger border will don't show. You can try change it to
self.button.layer.cornerRadius = 15;
If work, I think you can check your logic and set it when height button get right value.
Try this and check:
#import <QuartzCore/QuartzCore.h>
self.button.layer.borderColor = [UIColor whiteColor].CGColor;
self.button.layer.borderWidth = 2;
self.button.layer.cornerRadius = 5; // Change this value on your requirement
self.button.clipsToBounds = YES;
To force view frame to be calculated, you can try with layoutIfNeeded.
For example for a label in a UITableViewCell :
override func awakeFromNib() {
super.awakeFromNib()
self.layoutIfNeeded()
self.qualityIndexLabel.makeRound()
}
use dispatch_after
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.8 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.button.layer.borderColor = borderColor.CGColor;
self.button.layer.borderWidth = 2;
self.button.layer.cornerRadius = CGRectGetHeight(self.button.frame) / 2; });
the RoundedRect is deprecated use UIButtonTypeSystem instead.
see https://developer.apple.com/reference/uikit/uibutton?language=objc for more information.
I have hours trying to solve this and researching about this problem without results. This is my problem:
I'm using a ViewController in a existing project and over this I use an UIIMageView and a UIView at the same level. Then I set them alpha value in these two elements (alpha = 0.5) using Interface Builder. When I run the project on Simulator the alpha value not make effect and they looks like with their alpha value = 1. I made this same procedure in a new project and when I run the alpha effect is visible. I tried check/uncheck opaque option, set alpha value programatically as property or using method setAlpha, as well as set opaque value with code and it doesn't works. This problem happens with device too.
Anyone have a solution?
Check whether you import
#import <UIKit/UIKit.h>
UIIMageView.alpha = 0.4;
OR check with this
UIImage *wheelImage = [UIImage imageNamed:#"wheel#2x.png"];
UIImageView *imageView = [[UIImageView alloc]initWithImage:wheelImage];
imageView.frame = CGRectMake(50, 50, wheelImage.size.width, wheelImage.size.height);
imageView.alpha = 0.2;
[self.view addSubview:imageView];
Did you forget to connect your outlet in the storyboard and the property?
I'm creating a preview from something that people can configure in settings. They can choose a color in settings.
My view hierarchy:
Settings (Choose color for tree, and preview tree)
Choose color for tree (Here the user can choose for colors of the tree, with a save button)
I have an unwindSegue for my save button, that calls the setupCell method. But the background gradient layer of my UIView does not want to change.
Code:
- (IBAction)setupCellSegue:(UIStoryboardSegue *)segue{
[self setupCell];
}
-(void)setupCell{
//Corners
self.Preview.layer.cornerRadius = 25;
self.Preview.layer.masksToBounds = YES;
//Background
self.Preview.backgroundColor = [UIColor clearColor];
CAGradientLayer *grad = [CAGradientLayer layer];
grad.frame = self.Preview.bounds;
grad.colors = [[[Kleuren sharedInstance] kleurenArray] objectForKey:[standardDefaults objectForKey:#"Kleur"]];
[self.Preview.layer insertSublayer:grad atIndex:0];
//Text
self.optionOutlet.textColor = [Kleuren.sharedInstance.tekstKleurenArray objectForKey:[standardDefaults objectForKey:#"TekstKleur"]];
}
EDIT:
Here is the NSLog from my sublayers from the view. How can i replace the old CAGradientLayer with the new one? Tried this:
[self.Preview.layer replaceSublayer:0 with:grad];
(
"<CAGradientLayer: 0xcce9eb0>",
"<CALayer: 0xccef760>"
)
EDIT 2:
After trying some more, i've noticed that the CAGradientLayer is just added and added on top? Maybe this is the problem?
(
"<CAGradientLayer: 0x170220100>",
"<CAGradientLayer: 0x170220e20>",
"<CAGradientLayer: 0x170029f40>",
"<CALayer: 0x17803d960>"
)
EDIT 3:
View hierarchy, so the View that is highlighted in the screenshot is the one with the background.
EDIT 4:
Tried this: but now it doesn't have a CALayer anymore:
[[self.Preview layer] replaceSublayer:[[[self.Preview layer] sublayers] objectAtIndex:0] with:grad];
So I would get the following error:
2014-07-08 18:57:18.365 ///[3324:60b] View hierarchy unprepared for constraint.
Constraint: <NSIBPrototypingLayoutConstraint:0xe88e0b0 'IB auto generated at build time for view with fixed frame' UILabel:0xe88dae0.left == UIView:0xe88da50.left + 20>
Container hierarchy:
<UIView: 0xe88da50; frame = (59 54; 202 202); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0xe88dab0>>
| <CAGradientLayer: 0xe88cd50> (layer)
View not found in container hierarchy: <UILabel: 0xe88dae0; frame = (20 20; 162 162); text = 'Option'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0xe88db90>>
That view's superview: NO SUPERVIEW
So it seems to be that because the CALayer is deleted, the UILabel gives this error because it doesn't have a superview.
Try adding
[self.Preview.layer setNeedsDisplay];
after setupCell. This should redraw the layer
Not immediately sure what your issue is.
The first thing that jumped out at me is that in your first EDIT, you misused replaceSublayer:with:. See the documentation for that method for details, but basically you used an integer literal when you need to pass a CALayer - I'm surprised the compiler didn't complain. The declaration of that method is:
- (void)replaceSublayer:(CALayer *)oldLayer with:(CALayer *)newLayer
To use this method correctly, you'll want to hold onto a reference to the gradient layer. Maybe make a new property called grad and store it there. Later, when you want to replace it, pass self.grad into replaceSublayer:with: as oldLayer.
After you've fixed that, here are some things to check:
Are you sure setupCell gets called when you think it does? Set a breakpoint there to check.
Are you sure that when you recalculate the gradient layer, the colors have changed? Use a breakpoint to examine the value of grad.colors each time you pass through setupCell.
Found it, I've placed my CAGradientLayer *grad; in my implementation declaration between the {}
By placing the declaration in my implementation of my class. I could re-use the declaration, and not making a new instance each time by putting it in the setupCell.
#implementation class {
CAGradientLayer *grad
}
-(void)setupCell{
// Do stuff here with the gradient layer.
}
I do not know that this is the right explanation but it works. Was the last thing I came up on!
I am transitioning an app project from iOS-6.1 and xcode4 to iOS-7 and xcode5. My original iOS-6.1 routine to draw on a transparent UIView above an UIImageView does not work in iOS7. Here is what I have done and how I have fixed it. I'm hoping someone can tell me how to do it better!
Using InterfaceBuilder, I create a square (320 x 320) UIImageView on my View Controller view. I then make a 320 x 320 UIView directly above it and use Interface Builder Attributes Inspector to make it transparent.
Then I link up the setters and getters in Interface Builder. The UIImageView #property is (nonatomic, retain). I then subclass the now-transparent UIView and do my drawing in drawRect.
In iOS6.1 this works just fine. In iOS-7 I have a problem.
(Several, actually). As a side note, in xcode5 I cannot get the Attributes Inspector to appear when I select the UIView, when I try to make the UIView transparent. Could this be a bug, perhaps in my installation of xcode5, or is the xcode5 Attributes Inspector no longer supporting UIViews?
So I make the UIView transparent programmatically in iOS-7. I'm doing it here in the UIView's drawRect, which is probably overkill, but I'm still trying to figure out what's going on:
self.backgroundColor = [UIColor clearColor];
self.opaque= NO;
self.window.backgroundColor = [UIColor clearColor];
and then I have to make the UIImageView appear, also in drawRect, using this code
UIImage *myImage = [UIImage imageNamed:#"myImage.png"];
CGRect imageRect;
imageRect.origin.x = self.bounds.origin.x + 10;
imageRect.origin.y = self.bounds.origin.y + 10;
imageRect.size.width = 300;
imageRect.size.height = 300;
[myImage drawInRect:imageRect];
And things are now fine. I get what I want which is my drawing on top of the image. But, it seems like a terrible performance hit to be calling myImage every time drawRect needs to be called.
Can anybody see why my original method of displaying the UIImageView once does not work in iOS-7? Has anybody a better solution to my expensive show-the-image-every-time method?
Thanks in advance
TFR