UINavigationItem multiple line prompt text - uinavigationcontroller

Can any body give me the solution for displaying UINavigationItem prompt text in 2 lines?

There is not a built-in way to do this. Below is a work-around that seems to work pretty well that I put together from stackOverflow post UINavigationItem with prompt and activity indicator
Here is a simulator screen shot of what it creates:
Note that since the text is a UILabel you can modify its color, font, or anything else too.
// I have this code in viewDidLoad
UIView *viewContainingPrompt;
UIBarButtonItem *promptButtonItem;
// Configuring the prompt title of the navigation bar so it is present but empty
[self.navigationItem setPrompt: #""];
// We will create a UIBarButtonItem that has a custom view (viewContainingPrompt).
// A subview of viewContainingPrompt will be a UILabel (headerLabel)
// We need to have this "intermediate" view to position the label at the right position
// (the UIBarButtonItem ignores the origin and height of its custom view)
viewContainingPrompt = [[UIView alloc] initWithFrame: CGRectMake(0, 0, 0, 85)];
viewContainingPrompt.autoresizingMask = UIViewAutoresizingFlexibleWidth;
// Choose a width that puts 10 points on either end...
CGFloat labelWidth = self.navigationController.navigationBar.bounds.size.width - 20.0;
// Note that the '-60' below is determined by the width of the back button
// If someone can figure out how to determine this width at runtime this code
// would be much more robust.
UILabel *headerLabel = [[UILabel alloc] initWithFrame: CGRectMake(-60,-8,labelWidth,36)];
headerLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
headerLabel.text = #"A quite long prompt string that will wrap to a second line to demonstrate multiline prompt.";
headerLabel.font = [UIFont systemFontOfSize: 14];
headerLabel.numberOfLines = 0; // Zero gives as many lines as will fit, could be 2
headerLabel.backgroundColor = [UIColor clearColor];
headerLabel.textColor = [UIColor colorWithRed: .1 green: .1 blue: .2 alpha: 0.8f];
headerLabel.shadowColor = [UIColor colorWithRed: 1 green: 1 blue: 1 alpha: 0.5f];
headerLabel.shadowOffset = CGSizeMake( 0, 1 );
headerLabel.textAlignment = UITextAlignmentCenter;
[viewContainingPrompt addSubview: headerLabel];
//[headerLabel release]; // Uncomment if not using ARC
promptButtonItem = [[UIBarButtonItem alloc] initWithCustomView: viewContainingPrompt];
self.navigationItem.leftBarButtonItem = promptButtonItem;
self.navigationItem.leftItemsSupplementBackButton = YES;
//[viewContainingPrompt release]; // Uncomment if not using ARC
//[promptButtonItem release]; // Uncomment if not using ARC
I would appreciate anyone's feedback on how to figure out the width of the back button during execution so that width did not have to be hard coded.
As it is I do not think there are any private APIs or other illegal code contained.

Related

How align 2 uibuttons programmatically in a layout?

I use the KLCPopup library to display a popup in my app.
I have to add 2 buttons horizontally on the bottom of this popup, like the standard iOS UIAlerView. I cannot align this two buttons horizontally.
Here is the result I want:
But here is the result I have:
Here is the code I use to create this popup:
UIView* contentView = [[UIView alloc] init];
contentView.translatesAutoresizingMaskIntoConstraints = NO;
UILabel* dismissLabel = [[UILabel alloc] init];
dismissLabel.translatesAutoresizingMaskIntoConstraints = NO;
dismissLabel.numberOfLines = 0;
[dismissLabel setTextAlignment:NSTextAlignmentCenter];
dismissLabel.lineBreakMode = NSLineBreakByWordWrapping;
dismissLabel.preferredMaxLayoutWidth = 200;
UIButton* dismissButton = [UIButton buttonWithType:UIButtonTypeCustom];
dismissButton.translatesAutoresizingMaskIntoConstraints = NO;
dismissButton.contentEdgeInsets = UIEdgeInsetsMake(10, 20, 10, 20);
[contentView addSubview:dismissLabel];
[contentView addSubview:dismissButton];
UIButton* cancelButton = [UIButton buttonWithType:UIButtonTypeCustom];
cancelButton.translatesAutoresizingMaskIntoConstraints = NO;
cancelButton.contentEdgeInsets = UIEdgeInsetsMake(10, 20, 10, 20);
[contentView addSubview:cancelButton];
NSDictionary* views = NSDictionaryOfVariableBindings(contentView, dismissButton, cancelButton, dismissLabel);
[contentView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(16)-[dismissLabel]-(16)-[dismissButton]-(16)-[cancelButton]-(16)-|"
options:NSLayoutFormatAlignAllCenterX
metrics:nil
views:views]];
[contentView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(18)-[dismissLabel]-(18)-|"
options:0
metrics:nil
views:views]];
// Show in popup
KLCPopupLayout layout = KLCPopupLayoutMake(KLCPopupHorizontalLayoutCenter,
KLCPopupVerticalLayoutCenter);
KLCPopup* popup = [KLCPopup popupWithContentView:contentView
showType:KLCPopupShowTypeFadeIn
dismissType:KLCPopupDismissTypeGrowOut
maskType:KLCPopupMaskTypeDimmed
dismissOnBackgroundTouch:NO
dismissOnContentTouch:NO];
[popup showWithLayout:layout];
I think the problem on my code is the constraint.I've tried many possibilities but I cannot find the right way to do this.
Any advice will be helpful!
Thanks
You've added all three views to the vertical constraint and that's why they are all one after another. Do something like this:
V:|-16-[dismissLabel]
V:|-80-[dismissButton]
V:|-80-[cancelButton]
H:|-18-[dismissLabel]-18-|
H:[dismissButton(50)]-100-[cancelButton(50)]
I haven't tested it but something like that could work. You might have to modify the last H value or maybe add a centering option to it. There are probably better ways where you could group some of those things but this should work too.

How is this navigation control created

The second image on this page from Apple's user interface design guide show a segmented control inside of a tall navigation bar:
https://developer.apple.com/library/ios/documentation/userexperience/conceptual/mobilehig/Anatomy.html#//apple_ref/doc/uid/TP40006556-CH24-SW1
How has this been done? It seems to me that a UINavigationBar is always 64 pixels high, so I don't understand how they made this taller.
Is it a custom element (which would be surprising in this document), or is there an easy way to achieve this? I'm wondering if it's a UIToolbar... are they merged with the UINavigationBar under iOS 7? If so, how do we do this?
Note that I need to do this in a iPad app, where the UINavigationController is inside a split view controller.
I finally found the solution to this.
I had to override UINavigation bar with my custom subclass in order to change the height. By using the appearance proxy the title and navigation items can be repositioned correctly. Unfortunately the proxy can't be used to shift the back button's arrow up (on iOS 7), so we have to override layoutSubview to handle that.
#define kAppNavBarHeight 66.0
#implementation TATallNavigationBar
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self setupAppearance];
}
return self;
}
- (id)init
{
self = [super init];
if (self) {
[self setupAppearance];
}
return self;
}
- (void)setupAppearance {
static BOOL appearanceInitialised = NO;
if (!appearanceInitialised) {
// Update the appearance of this bar to shift the icons back up to their normal position
CGFloat offset = 44 - kAppNavBarHeight;
[[TATallNavigationBar appearance] setTitleVerticalPositionAdjustment:offset forBarMetrics:UIBarMetricsDefault];
[[UIBarButtonItem appearanceWhenContainedIn:[RRSNavigationBar class], nil] setBackgroundVerticalPositionAdjustment:offset forBarMetrics:UIBarMetricsDefault];
[[UIBarButtonItem appearanceWhenContainedIn:[RRSNavigationBar class], nil] setBackButtonBackgroundVerticalPositionAdjustment:offset forBarMetrics:UIBarMetricsDefault];
[[UIBarButtonItem appearanceWhenContainedIn:[RRSNavigationBar class], nil] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, offset) forBarMetrics:UIBarMetricsDefault];
appearanceInitialised = YES;
}
}
- (CGSize)sizeThatFits:(CGSize)size {
return CGSizeMake(self.superview.frame.size.width, kNavBarheight);
}
- (void)layoutSubviews {
static CGFloat yPosForArrow = -1;
[super layoutSubviews];
// There's no official way to reposition the back button's arrow under iOS 7. It doesn't shift with the title.
// We have to reposition it here instead.
for (UIView *view in self.subviews) {
// The arrow is a class of type _UINavigationBarBackIndicatorView. We're not calling any private methods, so I think
// this is fine for the AppStore...
if ([NSStringFromClass([view class]) isEqualToString:#"_UINavigationBarBackIndicatorView"]) {
CGRect frame = view.frame;
if (yPosForArrow < 0) {
// On the first layout we work out what the actual position should be by applying our offset to the default position.
yPosForArrow = frame.origin.y + (44 - kAppNavBarHeight);
}
// Update the frame.
frame.origin.y = yPosForArrow;
view.frame = frame;
}
}
}
#end
Note that it's easy to specify your subclass in XCode: clicking on the UINavigationController gives you access to the UINavigationBar in the left hand column. Click that and change it's subclass in the inspector.
I've also created a Gist for this:
https://gist.github.com/timothyarmes/7080170

iOS7 UIImagePickerController cancel button disappear

The Cancel button is miss?! How can I fix this? Thank you very much.
if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypePhotoLibrary])
{
if(buttonIndex == 1)
{
self.ctr = [[UIImagePickerController alloc] init];
self.ctr.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
self.ctr.delegate = self;
self.ctr.allowsEditing = YES;
[self presentModalViewController:self.ctr animated:YES];
}
}
Just change the UIImagePickerController navigationBar.tintColor, it should be OK.
self.ctr.navigationBar.tintColor = [UIColor redColor];//Cancel button text color
[self.ctr.navigationBar setTitleTextAttributes:#{UITextAttributeTextColor: [UIColor blackColor]}];// title color
Looks like apple made some mistake with it (iOS 10, Xcode 8) because just changing tint color of UIImagePickerController could not be done, cause, before controller isn't have topItem property, or navigationController property. So have done the changes in UIImagePickerController extension. But I checked navigationController and topItem in those overrided methods: viewDidLoad, viewWillAppear, viewDidAppear. but it still was nil. So i decide to check it in viewWillLayoutSubviews, and voila! It's wasn't nil, so we can set bar tint color of exact rightBarButtomItem here!
Here is example:
extension UIImagePickerController {
open override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
self.navigationBar.topItem?.rightBarButtonItem?.tintColor = UIColor.black
self.navigationBar.topItem?.rightBarButtonItem?.isEnabled = true
}
}
And don't forget to call super.viewWillLayoutSubviews, it's very important ;-)
EDIT: But it still has problems when return to the albums screen..
Change the tintColor
self.navigationBar.topItem?.rightBarButtonItem?.tintColor = UIColor.black
If that doesn't work run through your view controllers to see if there isn't a place where you changed the appearance of the navigation bar and reset the change.

How to animate dismissal of one view Controller to another using custom animation?

I just figure out how to animate insertion of one viewControll
[self transitiontoViewController:self.filterController duration:.5 options:UIViewAnimationOptionTransitionNone animations:^{
[self.filterController.view resizeandMovewithRect:CGRectMake(0, self.filterController.view.frame.size.height, 0, 0)];
} completion:^(BOOL finished){
}];
Here, resizeAndMovewithRect simply move a view around using this category for UIView
-(void) resizeandMovewithRect:(CGRect)movement
{
CGRect myFrame = self.frame;
CGRect newFrame = CGRectMake(myFrame.origin.x+movement.origin.x, myFrame.origin.y + movement.origin.y, myFrame.size.width + movement.size.width , myFrame.size.height + movement.size.height);
self.frame =newFrame;
}
Now I want to do the opposite. I want self.filterController to be dismissed by moving it off screen.
One way to do so is:
[self transitiontoViewController:self.filterController duration:.5 options:UIViewAnimationOptionTransitionNone animations:^{
[self.filterController.view resizeandMovewithRect:CGRectMake(0, -self.filterController.view.frame.size.height, 0, 0)];
} completion:^(BOOL finished){
}];
If I do this the animation is not drawn at all.
It seems to me that self.filterController is removed from superview at the beginning of the animation. That's why whatever happen to self.filterController is not seen. So I do it this way
[UIView animateWithDuration:.5 animations:^{
[self.filterController.view resizeandMovewithRect:CGRectMake(0, -self.filterController.view.frame.size.height, 0, 0)];
} completion:^(BOOL finished){
[self transitiontoViewController:self.last2ViewsInTheContainer[0] duration:0 options:UIViewAnimationOptionTransitionNone animations:^{
} completion:nil];
}];
So I animate rolling up self.filterController.view first before I call [self transitiontoViewController
However, if I do it this way, then by the time the self.filterController.view is rolled up, the view that's replacing it is not added yet to superview. So that one is not seen.
How should I do it anyway?
I have found the answer. Turns out no views are removed till the end. The issue is that the new viewController is added to the top of the stack.
So when adding self.filterController, things are simple. It's already in front while the from view is in the back.
When pulling out self.filterController, that backView is in front hiding self.filterController. So the solution is to simply readd self.filterController to the superview and we'll see the animation.
Final code:
[self transitiontoViewController:self.last2ViewsInTheContainer[0] duration:.5 options:UIViewAnimationOptionTransitionNone animations:^{
[self.filterController.view.superview addSubview:self.filterController.view]; //Put the filterControllerView at the front
[self.filterController.view resizeandMovewithRect:CGRectMake(0, -self.filterController.view.frame.size.height, 0, 0)];
} completion:nil];

Sharekit customise modelview button colour

Lovin' Sharekit
Have custom backgrounds happening for the toolbars, but want to change the button colour in the modal view that displays which link to share (ie the Twitter link model view)...just can't find which file to add my customise nav bar button bar code to
Been trying but can't seem to find right combo... anyone know?
- (void)viewDidLoad
{
[super viewDidLoad];
/*
Colour the Nav Bar buttons
*/
[self.navigationController.navigationBar applyCustomTintColor];
}
In SHKConfig.h
Amend
#define SHKBarTintColorRed 219 /255.0
#define SHKBarTintColorGreen 83 /255.0
#define SHKBarTintColorBlue 106 /255.0
Add / 255.0 to your number(s)
This pre-divides our RGB color into the floating point percentage for a UIColor
In SHK.m
Amend showViewController function
// Wrap the view in a nav controller if not already
if (![vc respondsToSelector:#selector(pushViewController:animated:)])
{
UINavigationController *nav = [[[UINavigationController alloc] initWithRootViewController:vc] autorelease];
if ([nav respondsToSelector:#selector(modalPresentationStyle)])
nav.modalPresentationStyle = [SHK modalPresentationStyle];
if ([nav respondsToSelector:#selector(modalTransitionStyle)])
nav.modalTransitionStyle = [SHK modalTransitionStyle];
nav.navigationBar.barStyle = nav.toolbar.barStyle = [SHK barStyle];
// Added code
UIColor* c = [UIColor colorWithRed:SHKBarTintColorRed green:SHKBarTintColorGreen blue:SHKBarTintColorBlue alpha:1.0];
[(UINavigationController *)vc navigationBar].tintColor = c;
// End added code
[topViewController presentModalViewController:nav animated:YES];
self.currentView = nav;
}
// Show the nav controller
else
{
if ([vc respondsToSelector:#selector(modalPresentationStyle)])
vc.modalPresentationStyle = [SHK modalPresentationStyle];
if ([vc respondsToSelector:#selector(modalTransitionStyle)])
vc.modalTransitionStyle = [SHK modalTransitionStyle];
[topViewController presentModalViewController:vc animated:YES];
[(UINavigationController *)vc navigationBar].barStyle =
[(UINavigationController *)vc toolbar].barStyle = [SHK barStyle];
// Added code
UIColor* c = [UIColor colorWithRed:SHKBarTintColorRed green:SHKBarTintColorGreen blue:SHKBarTintColorBlue alpha:1.0];
[(UINavigationController *)vc navigationBar].tintColor = c;
// End added code
self.currentView = vc;
}
This tints all navigationBar buttons (including the Cancel button)
Viola!

Resources