How to make UINavigationBar taller like in Mail.app - ios

Apple Mail app in thread views has a dynamic, taller than usual navigation bar which collapses when you scroll. Is it possible to achieve same effect using only allowed API calls or is this available only internally for Apple?
Expanded:
Collapsed:

Please check here. The link has different ways to solve the problem.
However following code helped me.
for subview in (self.navigationController?.navigationBar.subviews)! {
if NSStringFromClass(subview.classForCoder).contains("BarBackground") {
var subViewFrame: CGRect = subview.frame
// subViewFrame.origin.y = -20;
subViewFrame.size.height = 100
subview.frame = subViewFrame
}
}

You can able to set it as follows
-(void)layoutSubviews{
[super layoutSubviews];
CGRect rectStatus = [[UIApplication sharedApplication] statusBarFrame];
if (rectStatus.size.height==44.f) {
}else{
if (#available(iOS 11.0, *)) {
for ( UIView*aView in self.subviews) {
if ([NSStringFromClass(aView.classForCoder) isEqualToString:#"_UINavigationBarContentView"]) {
aView.frame = CGRectMake( 0,20,aView.frame.size.width,44);
}
else if ([NSStringFromClass(aView.classForCoder) isEqualToString:#"_UIBarBackground"]) {
aView.frame = CGRectMake(0,0,aView.frame.size.width, 64);
}
}
}
}
}

Related

iOS 13 UITabBar RePosition to Top

I have followed this answer to reposition my tabbar to top of the page. It was working perfect until iOS 13 release. In iOS 13 the tabbar is visible on bottom of the screen. Any other workaround should i have to use?
Does anyone faced the same problem?
Update:
Below piece of code i have used in my app:
- (void) viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
[self.tabBar invalidateIntrinsicContentSize];
// Just a quick fix for making this to happen for iOS versions between 11.0 to 11.1
// Updating the frame in Main queue.
dispatch_async(dispatch_get_main_queue(), ^{
[self changeTabBarPosition];
});
// Set the translucent property to NO then back to YES to
// force the UITabBar to reblur, otherwise part of the
// new frame will be completely transparent if we rotate
// from a landscape orientation to a portrait orientation.
self.tabBar.translucent = NO;
self.tabBar.translucent = YES;
}
- (void)changeTabBarPosition {
CGFloat tabSize = 44.0;
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (UIInterfaceOrientationIsLandscape(orientation)) {
tabSize = 32.0;
}
CGRect tabFrame = self.tabBar.frame;
tabFrame.size.height = tabSize;
tabFrame.origin.y = [UIApplication sharedApplication].statusBarFrame.size.height;
self.tabBar.frame = tabFrame;
}
I found the solution with the help of #Thanh Vu mentioned in his/her answer. Below piece of code fixed my issue.
- (void) viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self.tabBar invalidateIntrinsicContentSize];
CGRect tabFrame = self.tabBar.frame;
tabFrame.size.height = 44.0;
tabFrame.origin.y = 0;
self.tabBar.frame = tabFrame;
// Set the translucent property to NO then back to YES to
// force the UITabBar to reblur, otherwise part of the
// new frame will be completely transparent if we rotate
// from a landscape orientation to a portrait orientation.
self.tabBar.translucent = NO;
self.tabBar.translucent = YES;
}
I just test bellow code on iOS 13. It still work.
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.tabBarController.tabBar.frame = CGRectMake(0, 0, self.view.frame.size.width, self.tabBarController.tabBar.frame.size.height);
}
I get this solution after a lot struggle too, with Swift5 + IOS13.2Sdk. Follow this answer.
class MyUITabBarController:UITabBarController{
override func viewDidLayoutSubviews(){
super.viewDidLayoutSubviews()
var frame = self.tabBar.frame
frame.origin.y = 0
self.tabBar.frame = frame
}
}

iOS 11.2 custom navigation bar infinite loop

Since the release of IOS 11.2 my app is encountering an infinite loop when pushing a view controller whose navigation controller has a custom navigation bar height. Did someone find the solution for this problem? Thanks.
-(void)layoutSubviews{
[super layoutSubviews];
float height = 42.5;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
height = 48;
}
imageView.frame = CGRectMake(0, 0, [[UIScreen mainScreen]bounds].size.width, height);
if(UI_USER_INTERFACE_IDIOM() ==UIUserInterfaceIdiomPad){
if(#available(iOS 11.0,*)){
self.frame =CGRectMake(0, 20,[[UIScreen mainScreen]bounds].size.width, 55); // this line provoke the infinite loop
for(UIView *aView in self.subviews){
if([NSStringFromClass([aView class]) isEqualToString: #"_UINavigationBarContentView"]){
aView.frame = CGRectMake(0, 10, aView.frame.size.width, aView.frame.size.height);
}
if([NSStringFromClass([aView class]) isEqualToString: #"_UIBarBackground"]){
aView.frame = CGRectMake(0, 0, aView.frame.size.width, self.frame.size.height );
}
}
}
}
}
I also had the same problem.
I solved by removing this
frame.size.height = customHeight
from layoutSubviews and then adding this
override var frame: CGRect {
get {
return CGRect(x: 0, y: 0, width: super.frame.width, height: customHeight)
}
set (value) {
super.frame = value
}
}
to my UINavigationBar subclass.
I left all other code in layoutSubviews as it was before. (nb)

SetFrame Method doesn't work in ios8

I am using table view with dynamic height.
-(void)ShowTblRoomType
{
// [self.tableView_roomType setTranslatesAutoresizingMaskIntoConstraints:YES];
[self.tableView_roomType setFrame:CGRectMake(self.tableView_roomType.frame.origin.x, self.tableView_roomType.frame.origin.y, self.tableView_roomType.frame.size.width, self.tableView_roomType.rowHeight*self.roomtypeDetails.count)];
self.tableView_roomType.hidden = NO;
//set shadow to uitableview........
self.tableView_roomType.layer.masksToBounds = NO;
self.tableView_roomType.layer.cornerRadius = 8; // if you like rounded corners
self.tableView_roomType.layer.shadowOffset = CGSizeMake(-15, 20);
self.tableView_roomType.layer.shadowRadius = 3;
self.tableView_roomType.layer.shadowOpacity = 0.5;
}
From here I am calling this method
- (IBAction)showRoomTypeDetails:(id)sender
{
if(self.tableView_roomType.hidden == NO){
self.tableView_roomType.hidden = YES;
}else
{
[self ShowTblRoomType];
}
// [self.view_reservation bringSubviewToFront:self.tableView_roomType];
}
it works on below ios 8 but dosn't work on ios8.
on ios8 it shows only one cell.
Appreciate for help

Change height of inputAccessoryView issue

When I change the height of inputAccessoryView in iOS 8, the inputAccessoryView not go to the right origin, but covers the keyboard.
Here are some code snippets:
in table view controller
- (UIView *)inputAccessoryView {
if (!_commentInputView) {
_commentInputView = [[CommentInputView alloc] initWithFrame:CGRectMake(0, 0, [self width], 41)];
[_commentInputView setPlaceholder:NSLocalizedString(#"Comment", nil) andButtonTitle:NSLocalizedString(#"Send", nil)];
[_commentInputView setBackgroundColor:[UIColor whiteColor]];
_commentInputView.hidden = YES;
_commentInputView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
}
return _commentInputView;
}
in CommentInputView
#when the textview change height
- (void)growingTextView:(HPGrowingTextView *)growingTextView willChangeHeight:(float)height {
if (height > _textView_height) {
[self setHeight:(CGRectGetHeight(self.frame) + height - _textView_height)];
[self reloadInputViews];
}
}
in UIView Category from ios-helpers
- (void)setHeight: (CGFloat)heigth {
CGRect frame = self.frame;
frame.size.height = heigth;
self.frame = frame;
}
Finally, i found the answer. In ios8, apple add a NSContentSizeLayoutConstraints to inputAccessoryView and set a constant with 44. You can't remove this constaint, because ios8 use it to calculate the height of inputAccessoryView. So, the only solution is to change value of this constant.
Example
in ViewDidAppear
- (void)viewDidAppear:(BOOL)animated {
if ([self.inputAccessoryView constraints].count > 0) {
NSLayoutConstraint *constraint = [[self.inputAccessoryView constraints] objectAtIndex:0];
constraint.constant = CommentInputViewBeginHeight;
}
}
change inputAccessoryView height when the textview height changed
- (void)growingTextView:(HPGrowingTextView *)growingTextView willChangeHeight:(float)height {
NSLayoutConstraint *constraint = [[self constraints] objectAtIndex:0];
float new_height = height + _textView_vertical_gap*2;
[UIView animateWithDuration:0.2 animations:^{
constraint.constant = new_height;
} completion:^(BOOL finished) {
[self setHeight:new_height];
[self reloadInputViews];
}];
}
That is.
One way you can update the constraint mentioned in Yijun's answer when changing the height of the inputAccessoryView is by overwriting setFrame: on your inputAccessoryView. This doesn't rely on the height constraint being the first in the array.
- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
for (NSLayoutConstraint *constraint in self.constraints) {
if (constraint.firstAttribute == NSLayoutAttributeHeight) {
constraint.constant = frame.size.height;
break;
}
}
}
The first answer didn't totally solve my problem but gave me a huge hint.
Apple did add a private constraint to the accessory view, but you cannot find it in the constraint list of the accessory view. You have to search for it from its superview. It killed my a few hours.
After reading the answer above, which is a great find, I was concerned that relying on the constraint you need to change being [0] or firstObject is an implementation detail that's likely to change under us in the future.
After doing a bit of debugging, I found that the Apple-added constraints on the accessory input view seem to have a priority of 76. This is a crazy low value and not one of the listed enums in the documentation for priority.
Given this low priority value it seems like a cleaner solution to simply conditionally add/remove another constraint with a high priority level, say UILayoutPriorityDefaultHigh when you want to resize the view?
For Xcode 11.2 and swift 5 this function will update inputAccessoryView constraints even in animation block
func updateInputContainerConstraints() {
if let accessoryView = inputAccessoryView,
let constraint = accessoryView.superview?.constraints.first(where: { $0.identifier == "accessoryHeight" }) {
constraint.isActive = false
accessoryView.layoutIfNeeded()
constraint.constant = accessoryView.bounds.height
constraint.isActive = true
accessoryView.superview?.addConstraint(constraint)
accessoryView.superview?.superview?.layoutIfNeeded()
}
}
Try this:
_vwForSendChat is the input accessory view
_txtViewChatMessage is the textview inside input accessory view
-(void)textViewDidChange:(UITextView *)textView {
CGFloat fixedWidth = textView.frame.size.width;
CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
CGRect newFrame = textView.frame;
newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), newSize.height);
if (newFrame.size.height < 40) {
_vwForSendChat.frame = CGRectMake(0, 0, self.view.frame.size.width, 40);
} else {
if (newFrame.size.height > 200) {
_vwForSendChat.frame = CGRectMake(0, 0, self.view.frame.size.width, 200);
} else {
_vwForSendChat.frame = CGRectMake(0, 0, self.view.frame.size.width, newFrame.size.height);
}
}
[self.txtViewChatMessage reloadInputViews];
}

iOS6 automaticly adds contentInset to UITableView when keyboard shows up?

On iPhone, I found when keyboard shows up, the system will set contentInset of tableView to UIEdgeInsets(0, 0, 216, 0) , because the keyboard height is 216. I think this is convienent when design an app only for the newest iOS, in the past, I have to calculate tableView size when keyboard came up by myself.
But I have to support iOS5, so I wanna know how to disable this automatic "favor" for me ? If I set
self.searchTipsController.tableView.contentInset = UIEdgeInsetsZero; , the scroll indicator will not show. At last I have to detect system version to do handle it separately.
And I want to know from what version this feature begins? 6.0 or 6.1?
- (void) keyboardSizeChange:(NSNotification *)aNotification
{
NSDictionary* d = [aNotification userInfo];
CGRect r = [[d objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
if(r.origin.y<[UIScreen mainScreen].bounds.size.height)
{
CGRect convertRect = [self.view convertRect:r fromView:[UIApplication sharedApplication].keyWindow];
CGRect viewBounds = self.view.bounds;
CGRect tipsFrame = CGRectMake(0, 0, viewBounds.size.width, convertRect.origin.y);
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"6.1"))
{
}else
{
self.searchTipsController.view.frame = tipsFrame;
self.searchTipsController.tableView.contentInset = UIEdgeInsetsZero;
}
}
}
I change my code, when keyboard raises, remove the tableview then add it back, this time it looks right..
- (void) keyboardSizeChange:(NSNotification *)aNotification
{
NSDictionary* d = [aNotification userInfo];
CGRect r = [[d objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
if(r.origin.y<[UIScreen mainScreen].bounds.size.height)
{
CGRect convertRect = [self.view convertRect:r fromView:[UIApplication sharedApplication].keyWindow];
CGRect viewBounds = self.view.bounds;
CGRect tipsFrame = CGRectMake(0, 0, viewBounds.size.width, convertRect.origin.y);
self.searchTipsController.view.frame = tipsFrame;
self.searchTipsController.tableView.contentInset = UIEdgeInsetsZero;
[self.searchTipsController.view removeFromSuperview];
[self.view addSubview:self.searchTipsController.view];
}
}
But I still hope some one can answer my question, thanks.

Resources