I know it sounds like this question has a simple answer, but hear me out. Although UIStatusBar is a subclass of UIView, you can't use the addSubview method to add a subview to it because it doesn't use it. The same goes for UIStatusBarWindow. Neither the view or window have a viewcontroller, so I can't hook into that in any way.
Here is the relevant section of code. The line where I call the addSubviews method on self is the issue, because addSubviews isn't a method of UIStatusBar.
#import <CoreGraphics/CoreGraphics.h>
#interface UIStatusBar : UIView
#end
%hook UIStatusBar
- (void)layoutSubviews {
//Round corners under status bar
CGFloat radius = 15;
CGRect wholeScreen = [[UIScreen mainScreen] bounds];
UIView *roundedCorners = [[UIView alloc] initWithFrame: CGRectMake(-radius, 20-radius, wholeScreen.size.width+2*radius, wholeScreen.size.height-20+2*radius)];
roundedCorners.layer.borderWidth = radius;
roundedCorners.layer.cornerRadius = 2*radius;
roundedCorners.layer.borderColor = UIColor.blackColor.CGColor;
roundedCorners.userInteractionEnabled = NO;
[self addSubView:roundedCorners];
}
%end
Is there another way I can add the subview? The reason I'm trying to do it this way is so that, whenever the status bar is hidden, my roundedCorners view is also hidden. I could hide it whenever the status bar is hidden, but due to different apps using many different methods of hiding the status bar that doesn't work out as well as I hoped.
I think a solution here is to use the notifications delivered whenever the status bar's height changes.
Using either/both:
UIApplicationWillChangeStatusBarFrameNotification
UIApplicationDidChangeStatusBarFrameNotification
or you can also use the AppDelegate methods that get called when the status bar changes frame:
-application:willChangeStatusBarFrame:
-application:didChangeStatusBarFrame:
You can in these methods adjust your rounded corners according to the status bar's new frame. Hopefully this solves you problem!
I have a table view cell and when tapped it will:
animate it's height (so I need a beginUpdates/endUpdates call)
animate the alpha of a subview
When I have beginUpdates/endUpdates call, the cell animates it's height perfectly, but the alpha of the subview keeps "jumping" to the target value without animating. When I remove beginUpdates/endUpdates and try to animate the alpha regularly, it animates well, but this time I don't have the cell expanding height animation.
Here is my code:
-(void)handleTap{
isExpanded = !isExpanded;
if(isExpanded){
self.heightConstraint.constant = SCREEN_WIDTH;
}else{
self.heightConstraint.constant = CLOSED_HEIGHT;
}
ULFeedView *feedView = [self nearestAncestorOfClass:[UITableView class]];
float faderTargetAlpha = isExpanded ? 0 : 1;
self.opaque = NO;
self.contentView.opaque = NO;
self.fader.opaque = NO;
[feedView beginUpdates];
[UIView animateWithDuration:0.5 animations:^{
self.fader.alpha = faderTargetAlpha;
}];
[feedView endUpdates];
}
(I think variable and method names are self explanatory, ULFeedView is my custom table view class, and the code is in the custom cell class)
I've tried animating the height constraint of my cell like I do with other views (UIView animateWith... layoutIfNeeded method): no luck.
I've tried moving the alpha animation between beginUpdates and endUpdates no luck.
I've tried using different animation methods (animate with duration/delay etc), no luck.
I've tried setting opaque to NO explicitly (following my own answer https://stackoverflow.com/a/27680493/811405 on another question), no luck.
I've tried with different Opaque, Clears Graphic Context, Clip Subviews settings, they don't seem to change anything at all.
Also, some interesting observations:
The (only) subview of the view animates it's alpha correctly.
When I'm setting the alpha from 1 to 0, the background color of the view that I'm animating jumps from 1 to 0 at the beginning of the animation.
When I'm setting the alpha from 0 to 1, the background color of the view that I'm animating jumps from 0 to 1 at the end of the animation.
I've tried setting a background color on the subview of the view that I'm animating too, and the above observations apply.
Why would this happen and how I do I animate both the background color of the view and the cell height at the same time? (I am targeting ≥ iOS 8.0)
Okay, after investigating a little bit, I've came up with a solution:
Seems that background colors don't play well with table view animations. Table view updates seem to mess up everything about background colors of any views inside the cell.
I've subclassed UIView and added a custom property called fade color (I could actually also use background color but I wanted to completely move away from it):
IB_DESIGNABLE
#interface ULFaderView : UIView
#property IBInspectable UIColor *fadeColor;
#end
I've set the fade color on Interface Builder. And in code I've implemented custom drawing:
#implementation ULFaderView
- (void)drawRect:(CGRect)rect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextClearRect(ctx, rect);
CGContextSetFillColorWithColor(ctx, self.fadeColor.CGColor);
CGContextFillRect(ctx, rect);
}
#end
And it renders a background perfectly, duplicating the background color behavior. Yet as it's not the "background color property" which table view messes up, it doesn't conflict with any animations and acts as a "solid bitmap whatever content inside the view". Animating the alpha now works smooth as ever, while the table view also animates the height at the same time.
I have a UIButton (created in interface builder), that I'm turning into a circle by setting button.layer.borderRadius = button.frame.size.width / 2.0; (programatically, in viewDidAppear:). However, the viewController it belongs to is presented modally with an animation. Since viewDidAppear isn't called until after the transition animation has finished, the button is square until then, which makes the sudden change quite jarring.
I can't set the radius in viewDidLoad, since the button properties are incorrect then (the width is too large), which I think is because autolayout constraints haven't been properly resolved yet. I tried to rectify this by calling [self.view setNeedsLayout] in viewDidLoad, and then setting the cornerRadius, but the button width was still wrong. What I don't understand is, during the animation, everything otherwise renders correctly, suggesting that the autolayout constraints /have/ been resolved, or that iOS does something else in the name of quick animations (like storing a snapshot preview to use for the animation).
Any suggestions?
The result of trying to set the corner radius in viewDidLoad:
You can get the width in the function
- viewDidLayoutSubviews.
Apple Documentation here.
Override the UIButton and make its layoutSubviews method like this:
- (void)layoutSubviews {
[super layoutSubviews];
self.layer.cornerRadius = self.bounds.size.width/2.f;
}
Then whenever the button's size changes it will adjusts its value.
Also add it in buttonWithType: and initWithFrame: as I'm not sure if the layoutSubviews is called after init.
Your controls get the constraints and frame set after viewDidLoad amd after viewDidLoad you can get your requirements in viewwilllayoutsubviews or in viewdidlayoutsubviews before viewDidAppear
what about
-(void) viewWillAppear:(BOOL)animated
Sorry I didn't get you well. As your screenshot explains that your image isn't being circular.For that you can try:(1) layer.cornerRadius = btn.frame.size.width/2; or layer.CornerRadius = 50(if width is 100)
layer.masksToBounds = YES;
layer.borderWidth = 1.5; or whatever you want
layer.borderColor = [UIColor whiteColor];
If still you get problem, then share your constraints that you added on button and also the code where you are doing this.
Im trying port my app to iOS7, but my custom TableViewController is showing the last row (cell) under the TabBar :(
Im searching a lot for it, but i dont find any solution. Can anyone help me?
My Custom Table View class
The error is shown in the blow screenshot (only is showing a part of last product because im draging to up to show the hidden product under the tabbar):
Thanks.
I've got the same problem and solved it using storyboard.
At Tab Bar Controller, go to attribute inspector, Simulated Metrics, and set the Bottom Bar to Opaque Tab Bar. That's it!
See image bellow for description.
Saudações! (Greetings!)
I found the answer to your question on another post, answered by dariaa, here:
Tab Bar covers TableView cells in iOS7
It worked great for me.
Please no credit for me, because I'm not the original guy who solved it.
In your custom TableViewController, add these two lines under [super viewDidLoad]:
- (void)viewDidLoad
{
[super viewDidLoad];
self.edgesForExtendedLayout = UIRectEdgeAll;
self.tableView.contentInset = UIEdgeInsetsMake(0., 0., CGRectGetHeight(self.tabBarController.tabBar.frame), 0);
}
My friends, I cannot tell you how badly I struggled from this. Not a single re-configuration of Story Board never helped me. The issue was exactly like in Original Post, I've managed to fix it using:
for swift 3
self.edgesForExtendedLayout = []
for objective-c
self.edgesForExtendedLayout = NO;
2 lines in viewDidLoad and that's it !
self.edgesForExtendedLayout = UIRectEdgeAll;
self.tableview.contentInset = UIEdgeInsetsMake(0.0f, 0.0f, CGRectGetHeight(self.tabBarController.tabBar.frame), 0.0f);
In iOS 7 viewController uses full height. There is a property introduced as
self.automaticallyAdjustsScrollViewInsets = NO;
set it to no. then check, or set UIEdgeInset if is not set right after it.
UIEdgeInsetsMake(top, left, bottom, right)
See here
https://developer.apple.com/library/ios/documentation/userexperience/conceptual/TransitionGuide/AppearanceCustomization.html
Edit: try also this
self.edgesForExtendedLayout = UIRectEdgeNone;
The root cause of this problem is that automaticallyAdjustsScrollViewInsets is effective only on the First scroll view in your VC's view Hierarchy. It is not documented by Apple, but it is the only way the VC will detect the scroll view needing to be modified unless you're using a UITableViewController.
So in order to fix your issue without manually adjusting the insets, do this:
Make sure "Adjust Scroll View Insets" is checked.
Make sure that the tableView is the first subview in the view Hierarchy.
(Move it upwards above all other elements)
UIViewController has two new properties to assist you : topLayoutGuide and bottomLayoutGuide. They return the height of the parent view controller's controls you need to avoid. In this case, bottomLayoutGuide will return the offset of the tab bar.
Your custom view controller is probably overriding a method and not invoking super's implementation where this would be done for you. I am guessing you are installing AutoLayout constraints or setting a view's frame manually to fill the view. You just need to include the value from [bottomLayoutGuide length] to your layout calculation. If you support rotation, you should update that value in willAnimateRotationToInterfaceOrientation:duration:.
UINavigationController and UITabBarController both have a transparency flag that can be set programmatically or in the storyboard.
The UINavigationController also has two flags that control if the content extends under the top or bottom bar. Again you can set them programmatically or in the storyboard. This will apply to all subviews.
Each UIViewController can set its own preference in code. The property is called edgesForExtendedLayout and you can set up all combinations.
Using those properties will allow AutoLayout and Springs'n'Struts to adjust the views the way you want them regardless of the device.
There are a lot more new properties in UIViewController that you will want to have a look at.
Try the following:
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])
self.edgesForExtendedLayout = UIRectEdgeBottom;
I've got the same problem. One solution to it is to make the ToolBar not Translucent. Here's how to do it:
First select the tool bar from the document viewer
like here
Then uncheck Translucent like here
Hope this helps.
Thanks.
The problem was masked using:
-(void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 112, 0);
}
But it doesn't solve, because on each iPhone and on each app tableview i have a different space on bottom.
So this is a poor solution.
I dont know a way to solve it.
I solved my problem now, changing my BaseTableViewController to inherit from UIViewController to UITableViewController.
But using a TableView inside a UIViewController is not solved :(
Thanks.
maybe is not a right answer, also for that reason I post this answer so you can tell me if this answer could be a possible solution.
In my case, I like the translucent effect, so I have added a footer in the table and I have modified the scrollIndicators.
- (void)viewDidLoad
{
// Do any additional setup after loading the view.
[super viewDidLoad];
UIView *footer = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.agendaItemsTable.frame.size.width, self.tabBarController.tabBar.frame.size.height)];
self.agendaItemsTable.tableFooterView = footer;
self.agendaItemsTable.scrollIndicatorInsets = UIEdgeInsetsMake(0, 0, self.tabBarController.tabBar.frame.size.height, 0);
}
What do you think?
I had the same problem, and the up-voted answers did not solve it. See my answer to a similar question, Tab Bar covers TableView cells in iOS7.
I solved the issue by manually setting the table view's frame in the table view controller's viewWillAppear: method to the height of the screen - (status bar height + nav bar height + tab bar height).
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Adjust height of tableview (does not resize correctly in iOS 7)
CGRect tableViewFrame = self.tableView.frame;
tableViewFrame.size.height = [self heightForTableView];
self.tableView.frame = tableViewFrame;
}
- (CGFloat)heightForTableView
{
return CGRectGetHeight([[UIScreen mainScreen] bounds]) -
(CGRectGetHeight([[UIApplication sharedApplication] statusBarFrame]) +
CGRectGetHeight(self.navigationController.navigationBar.frame) +
CGRectGetHeight(self.tabBarController.tabBar.frame));
}
If anyone finds a better solution to this problem, please share!
For those like xarly who want the translucent effect, and for an Autolayout solution (without setting frames), see my answer here https://stackoverflow.com/a/26419986/1158074
I had a similar problem with collection view. Changing the collection view frame and content inset below fixed it for me...
guard let cv = collectionView,
let tabBar = tabBarController?.tabBar else { return }
// Resize collection view for tab bar
let adjustedFrame = CGRect(origin: cv.frame.origin,
size: CGSize(width: cv.frame.width, height: cv.frame.height - tabBar.frame.height))
cv.frame = adjustedFrame
// Adjust content inset for tab bar
let adjustedContentInsets = UIEdgeInsetsMake(0, 0, tabBar.frame.height, 0)
cv.contentInset = adjustedContentInsets
cv.scrollIndicatorInsets = adjustedContentInsets
Good luck!
I'm transitioning an application to iOS 7 which has been fairly smooth, there's one thing I cannot figure out.
I have a view controller with a couple buttons that I display with a UIPopoverController.
It looks to me like the popover controller is doing something to clip the content of it's view controller to be rounded.
iOS6 (I want this):
iOS7 (something changed):
I'm using custom popover controller background class described here http://blog.teamtreehouse.com/customizing-the-design-of-uipopovercontroller
Here's my specific version of that background class http://pastebin.com/fuNjBqwU
Does anyone have any idea what to change to get it back to my iOS 6 look?
In popover content controller:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.view.superview.layer.cornerRadius = 0;
}
I tried getting #OneSman7's solution to work, but the view with the cornerRadius wasn't the direct superview of the contentViewController.view instance. Instead, I had to walk up the view hierarchy searching for the one whose cornerRadius is no 0 and reset it (which is just a UIView instance, no special class name to check for). A less than ideal solution, but seems to work so far.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0")) {
UIView *view = self.view;
while (view != nil) {
view = view.superview;
if (view.layer.cornerRadius > 0) {
view.layer.cornerRadius = 2.0;
view = nil;
}
}
}
}
Perhaps you could just replace your background view's contentViewInsets with:
+ (UIEdgeInsets)contentViewInsets{
return UIEdgeInsetsZero;
}
And then just give your contentViewController's view some extra padding on its edges, so that even though the corners will still be rounded, they won't contain any of your popover content so the rounding effect won't be visible.