I have a UIView that I'm using as a header, and I've applied a drop shadow to this view. It gets onscreen as I intended, but after a rotation the shadow becomes twice as dark, as though it had been redrawn over top of itself. Subsequent rotations make it even darker. Here is the code for the header and shadow:
self.header = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, HEADER_HEIGHT)];
self.header.backgroundColor = [UIColor whiteColor];
self.header.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth;
// Drop shadow.
self.header.layer.shadowColor = [UIColor blackColor].CGColor;
self.header.layer.shadowOpacity = 0.5;
self.header.layer.shadowRadius = 2.0;
self.header.layer.shadowOffset = CGSizeMake(0, 2);
// self.header.layer.shouldRasterize = YES;
// self.header.layer.rasterizationScale = [UIScreen mainScreen].scale;
This code all occurs in viewWillLayoutSubviews of my View Controller, and call [super willLayoutSubviews] at the beginning of the method. I have tried putting the same code in viewWillAppear:animated to no effect.
While writing this question out, I figured out the solution.
I was re-initializing the header every time viewWillLayout subviews was called.
Aside from being inefficient, this also caused the shadow to draw over itself for some reason.
I fixed this by initializing all of my views in loadView, and doing the frame setting in viewWillLayoutSubviews. This resolved the issue, and is nicer because I am not re-initializing objects that already exist.
Related
I'm trying to rotate a label on my view 90 degrees. I've tried the two following ways to do it and the label just disappears from the screen. I triple checked that the properties are properly attached. Any thoughts?
attempt one:
// rotating labels 90 degrees
self.labelCloseScroll.transform = CGAffineTransformMakeRotation (3.14/2);
attempt two:
CGAffineTransform rotate = CGAffineTransformMakeRotation(3.14/2);
rotate = CGAffineTransformScale(rotate, 1, 1);
[self.labelCloseScroll setTransform:rotate];
I am not 100% sure if it works or not but why are you not using M_PI_2. It's just simple thought that you are assuming Value of Pi to be 3.14 but the exact value is 3.14159...
I did it like this and it worked fine :
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 50, 70)];
lbl.text = #"New";
lbl.backgroundColor = [UIColor clearColor];
lbl.textColor = [UIColor whiteColor];
lbl.highlightedTextColor = [UIColor blackColor];
lbl.font = [UIFont systemFontOfSize:12];
lbl.transform = CGAffineTransformMakeRotation(M_PI_2);
[self.view addSubview:lbl];
You can also check Answers from these Questions :
How to Render a rotated UIlabel
Rotating UILabel at its center
Hope it will be helpful for you.
It may simply be that the view's bounds have become too small for the text. When the text can't be fully displayed in label view in iOS, it simply disappears, rather than remaining on show. Perhaps it's a deliberate Apple policy to prevent apps shipping with clipped text and forcing the dev to fix ;)
It sounds very much as though this is what is happening. You have said the text gets smaller as you rotate it, which indicates you have the shrink text to fit property set on the label view. This will shrink the text as the constraining view reduces in size. But the text will only shrink so much before it disappears.
If the label view itself would seem to be big enough, also be sure to check the bounds of each parent view the label is contained in, up through the view hierarchy.
I'm developing a little iOS component and I have a problem with a semi-transparent view with subviews. This is my scenario:
- one view with a semi-transparent background using [UIColor colorWithRed:green:blue:alpha]
- a little UITableView, with alpha = 1.0, added as a subview to the semi-transparent view
- some other subviews
Everything works well but the problem raises when the UITableView is scrolled up or down, in fact the area of the semi-transparent view around the UITableView loses its transparency becoming darker than its original background color.
Here's an image to explain the problem:
Look at the space with the two arrows...
Can anyone help me with this problem?
Thank you so much for your attention!
Update:
Some code:
_alertBg = [[UIView alloc] initWithFrame:CGRectZero];
_alertBg.backgroundColor = self.backgroundColor;
_alertBg.frame = CGRectMake((_bgView.frame.size.width - 240) / 2, (_bgView.frame.size.height - 260) / 2, 240, 260);
_alertBg.layer.cornerRadius = 8.0;
_alertBg.layer.borderWidth = 2.0;
_alertBg.layer.borderColor = self.borderColor.CGColor;
_alertBg.layer.shadowColor = [UIColor grayColor].CGColor;
_alertBg.layer.shadowOffset = CGSizeMake(0, 3);
_alertBg.layer.shadowOpacity = 0.8;
_alertBg.layer.masksToBounds = YES;
[_bgView addSubview:_alertBg];
_table = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
_table.frame = CGRectMake(10, _titleLabel.frame.origin.y + _titleLabel.frame.size.height + 12, _alertBg.frame.size.width - 20, 150);
_table.layer.cornerRadius = 6.0;
_table.layer.masksToBounds = YES;
_table.delegate = self;
_table.dataSource = self;
[_alertBg addSubview:_table];
From the code above, self.backgroundColor is something like [UIColor colorWithRed:0 green:0 blue:1 alpha:0.7]
I put the available code in a test project, and got the same problem as you have. Commenting out _alertBg.layer.shadowOpacity = 0.5; fixes the issue for me. Maybe someone can clarify why is this an issue, I have limited experience with QuartzCore.
EDIT: Okay, inched closer to the real reason. It seems that if you don't have set the _alertBg.layer.shadowPath property all kinds of crazy things happen when you scroll the table (my guess here is that the table scroll calls a redraw of the _alertBg and the shadow redrawing gets called in quick succession far too many times and you get those visual artifacts).
Adding a shadowPath fixes the problem, so the layer code for the _alertBg should be as following:
_alertBg.layer.cornerRadius = 8.0;
_alertBg.layer.borderWidth = 2.0;
_alertBg.layer.borderColor = [UIColor colorWithRed:0 green:0 blue:1 alpha:0.7].CGColor;
_alertBg.layer.shadowColor = [UIColor grayColor].CGColor;
_alertBg.layer.shadowOffset = CGSizeMake(0, 5);
_alertBg.layer.shadowOpacity = 0.8;
_alertBg.layer.shadowPath = [UIBezierPath bezierPathWithRect:_alertBg.bounds].CGPath;
_alertBg.layer.masksToBounds = YES;
Just fix the shadowPath to your liking and you should be ready to go.
PS: On my Google-quest I found this excellent blog post about shadows, it might be of help.
Maybe match the background colour of tableView with _alertBg?
Its may be problem of dequeueReusableCellWithIdentifier.
just try this..., set dequeueReusableCellWithIdentifier to nil like bellow in cellForRowAtIndexPath method of UITableViewController delegate method
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
Also see my this answer may be you can get some idea from this..
iPhone Hide/Show labels in Uitableview cell
According to the official doc on UIView about the contentMode property:
The content mode specifies how the cached bitmap of the view’s layer is adjusted when the view’s bounds change
What's defined the content in this definition? Is it a sub view or when we have define a background color for a view for example.
My very first guess was that it should apply at least for the subviews in a view, but for example the following code snippet will not give me the expected result when playing with the UIViewContentModeCenter tag:
UIView* redView = [[UIView alloc] initWithFrame:CGRectMake(80, 80, 150, 200)];
redView.contentMode = UIViewContentModeCenter;
redView.backgroundColor = [UIColor redColor];
UIView* greenView = [[UIView alloc] initWithFrame:redView.bounds];
greenView.backgroundColor = [UIColor greenColor];
[redView addSubview:greenView];
redView.frame = CGRectInset(redView.frame, -5, -5);
[self.view addSubview:redView];
I have just set up a redView that will include a greenView. I have also set-up the content mode of the redview to UIViewContentModeCenter - why in the code I wrote the greenView is not centered when I change the frame of its parent? isn't what UIViewContentModeCenter is supposed to do?
Thanks for clarifying!
Ps: You can easily test the above code in the loadView of a simple view controller template project.
From the documentation:
The content mode specifies how the cached bitmap of the view’s layer
is adjusted when the view’s bounds change.
For an image view, this is talking about the image. For a view that
draws its content, this is talking about the drawn content. It does
not affect the layout of subviews.
You need to look at the autoresizing masks in place on the subviews.
Content mode is a red herring here. If you can't achieve the layout
you need using autoresizing masks, then you need to implement
layoutSubviews and calculate the subview positions and frames
manually.
from jrturton's answer to: https://stackoverflow.com/a/14111480/1374512
First read about Content Modes here
In your example you change the frame of the red view. That will invoke layoutSubviews on the view which will reposition the green view according to the layout constraints or autoresizing masks. You haven't specified any. So the frame of the green view will stay the same.
The content mode specifies how the view's layer should update when resizing. Depending on the content mode drawRect will be called or not.
You can test the effect of the different content modes with the following example:
Add a UIView subclass, that draws a circle using this drawRect implementation:
- (void)drawRect:(CGRect)rect
{
// Drawing code
NSLog(#"drawRect %#", NSStringFromCGRect(rect));
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(ctx, self.bounds);
[[UIColor redColor] setFill];
CGContextFillPath(ctx);
}
In the view controller create and add the circle view:
CircleView* circleView = [[CircleView alloc] initWithFrame:CGRectMake(10, 10, 20, 20)];
circleView.contentMode = UIViewContentModeCenter; // <- try different modes here
[self.view addSubview:circleView];
Now lets animate the frame and see what happens:
dispatch_async(dispatch_get_main_queue(), ^{
[UIView animateWithDuration:5 animations:^{
circleView.frame = CGRectMake(10, 10, 100, 200);
}];
});
I'm doing that asynchronously to force CoreGraphics to draw the view at least one time with the original frame.
When you don't set the content mode you end up with a blurry circle, because it just scales up without redrawing. UIViewContentModeCenter makes the small circle stay at the center - also no redraw needed. UIViewContentModeRedraw makes the view draw the view again with the new frame. Actually that happens before the animation starts.
Note that the content mode can affect the drawing performance.
Trying to get UIButtons to decrease height but maintain width when device is rotated.
Here's code from initWithFrame: of the view that contains the buttons.
ParentView.m
self = [super initWithFrame:CGRectMake(0, 0, UIKeyboardPortraitHeightPhone, 320)];
self.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
self.autoresizesSubviews = YES;
// And then on each button I call
myButton.frame = myFrame;
myButton.autoresizingMask = (UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin);
The problem: Before I even rotate the device, the buttons have resized and gotten smaller (in height) than the frame I initialized them to.
Previous research: It looks like I'm having the same problem as this person: Cannot get UIButton autoresizingMask to work, but I followed the advice and got the same unsatisfactory result.
I also looked at the apple docs, which say that the autoresizing mask is only supposed to take effect when the bounds of the parent view change. Obviously either the bounds of my parent view are changing without me realizing it, or something else fishy is going on here.
Any ideas as to what could be the problem?
What is the best way to get round corners on an entire UITableView as seen in Stocks and Spotlight? The grouped style doesn't solve the problem because the round corners scroll away with the cell. I'm trying to clip the view so the corners are always round regardless of scroll position.
I saw another discussion about doing this to a UIImage that suggested masking it with another image. I'm not sure if this would work because I need taps to pass through to the table. This isn't isn't ideal for me because I want the background pattern to show through through the corners.
It's an old question but perhaps you still want to know how to do this.
I reproduced a tableView like in Stocks/Spotlight. The trick is
view.layer.cornerRadius = 10;
For this to work you need to include the QuartzCore into the class that you call that property:
#import <QuartzCore/QuartzCore.h>
I heard that this only works since OS 3.0. But since my application is using core data it wasn't a problem because it was already for OS 3.0 and hight.
I created a custom UIView with a subview with cornerRadius 10 and with
view.backgroundColor = [UIColor clearColor];
Then you have to place an UITableView grouped style in that subview. You need to set the backgroundColor to clearColor and the separatorColor to clearColor. Then you have to position the tableview inside the rounded corner view, this is done by setting the frame size and origin. My loadView class of my custom UIView looks like this:
self.view = [[UIView alloc] init];
self.view.backgroundColor = [UIColor clearColor];
CustomUIViewClass *scherm = [[CustomUIViewClass alloc] init];
CGRect frame;
frame.origin.x = 10;
frame.origin.y = 50;
frame.size.width = 300;
frame.size.height = 380;
scherm.frame = frame;
scherm.clipsToBounds = YES;
scherm.layer.cornerRadius = 10;
[self.view addSubview:scherm];
CustomUITableViewClass *table = [[CustomUITableViewClass alloc] initWithStyle:UITableViewStyleGrouped];
frame.origin.y = -10;
frame.origin.x = -10;
frame.size.width = 320;
frame.size.height = 400;
table.tableView.frame = frame;
[scherm addSubview:table.tableView];
I hope you understand my english, maybe I will write a short blog post about this technique with a sample project, will post the link here when I'm ready.
An easier way to do this is to simply import the QuartzCore framework to your project. #import <QuartzCore/QuartzCore.h> to your tableViewController and just set
myTableView.layer.cornerRadius=5;
This will give you rounded corners without having to add your tableview to a superView or clipping it.
Instead of hacking through the code, here's an easy to mimic the grouped style. This works if all you want is one section.
In Interface Builder:
Set UITableView style to Plain and make the frame with some padding on the left and right, perhaps with x = 10 and width = 300.
Then set the corner radius and color yourself:
#import <QuartzCore/QuartzCore.h>
self.tableView.layer.borderColor = [UIColor colorWithWhite:0.6 alpha:1].CGColor;
self.tableView.layer.borderWidth = 1;
self.tableView.layer.cornerRadius = 4;
Have you tried the "grouped" table view style?
self.tableView.style = UITableViewStyleGrouped;
For further reference, see the Table View Programming Guide. The "About Table Views" chapter has some nice screenshots describing the different styles.
Well, there is alot of approach to solve this problem.
However, in my case, all doesn't work correctly. My table sometimes is smaller than table size.
I will share the way I did. I belive is alot easer and faster than some options above.
Make the first and last item rounded.
Create CAShapeLayer for top(left|right) and bottom(left|right).
shapeTop = [CAShapeLayer layer];
shapeTop.path = [UIBezierPath
bezierPathWithRoundedRect:CGRectMake( 0.0f, 0.0f, 306.0f, 58.0f )
byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight
cornerRadii:CGSizeMake( 6.0f, 6.0f )].CGPath;
shapeBottom = [CAShapeLayer layer];
shapeBottom.path = [UIBezierPath
bezierPathWithRoundedRect:CGRectMake( 0.0f, 0.0f, 306.0f, 58.0f )
byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight
cornerRadii:CGSizeMake( 6.0f, 6.0f )].CGPath;
The table need to be backgroud clearColor;
The cells has to be a colored background;
Set the layer.mask of it
UIView* backgroundView = [[UIView alloc] initWithFrame:CGRectZero];
backgroundView.backgroundColor = [UIColor whiteColor];
cell.backgroundView = backgroundView;
Don't forget #import <QuartzCore/QuartzCore.h>
I recently came across this problem and solved it a different way. Thought I'd share the results with everyone.
I created a rectangular UIView with a clear, rounded-corner interior, and then laid that on top of the UITableView. You can find the full description at my programming blog.
It works exactly the way I want.
Below code for Swift version :
let redColor = UIColor.redColor()
self.tableView.layer.borderColor = redColor.colorWithAlphaComponent(0.9).CGColor
self.tableView.layer.borderWidth = 1;
self.tableView.layer.cornerRadius = 4;
Make sure that you have import QuartzCore in import section.
Here is swift extension:
extension UITableView {
public var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
layer.masksToBounds = true
}
}
}
Used by this way
tableView.cornerRadius = 7.5
UITableViewStyleInsetGrouped
A table view where the grouped sections are inset with rounded corners.
example code:
self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleInsetGrouped];
looks like:
Settings looking table view sections