iOS self.navigationController.toolbar position to top doesn't change - ios

I am trying to change self.navigationController.toolbar position to top instead of a bottom.
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UIToolbarDelegate, UIBarPositioningDelegate>
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
// View did load
- (void)viewDidLoad
{
// Superclass view did load method call
[super viewDidLoad];
// UIToolbarDelegate
self.navigationController.toolbar.delegate = self;
}
- (void)viewDidLayoutSubviews
{
self.navigationController.toolbarHidden = NO;
self.navigationController.toolbar.frame = CGRectMake(self.navigationController.toolbar.frame.origin.x, 64.0f, self.navigationController.toolbar.frame.size.width, self.navigationController.toolbar.frame.size.height);
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:#[#"First", #"Second"]];
segmentedControl.frame = CGRectMake(50.0f, 10.0f, 220.0f, 24.0f);
segmentedControl.selectedSegmentIndex = 1;
[self.navigationController.toolbar addSubview:segmentedControl];
}
- (UIBarPosition)positionForBar:(id <UIBarPositioning>)bar
{
return UIBarPositionTopAttached;
}
#end
The position changes at first, but later gets back to the bottom. Please, help me!

First make sure that toolbar delegate method positionForBar: is get called. If not, then your toolbar delegate is not properly set and you've have to define the UIToolbarDelegate protocol inside your header class.
#interface ExampleViewController : UIViewController <UIToolbarDelegate>
...
#end
Then set the delegate and also change the frames for toolbar. However, for the orientation you might have to reconsider the frames of toolbar.
#implementation ExampleViewController
- (void)viewDidLoad {
[super viewDidLoad];
// set the toolbar delegate
self.navigationController.toolbar.delegate = self;
self.navigationController.toolbarHidden = NO;
// create a toolbar child items
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:#[#"First", #"Second"]];
segmentedControl.frame = CGRectMake(0.0f, 0.0f, self.view.frame.size.with, 24.0f);
segmentedControl.selectedSegmentIndex = 1;
[self.navigationController.toolbar addSubview:segmentedControl];
// set the frames
CGRect toolbarFrame = self.navigationController.toolbar.frame;
toolbarFrame.origin.y = self.navigationController.frame.size.height;
self.navigationController.toolbar.frame = toolbarFrame;
}
// pragma mark - UIToolbarDelegate
- (UIBarPosition)positionForBar:(id <UIBarPositioning>)bar
{
return UIBarPositionTopAttached;
}
#end

In your viewDidLoad method, add:
self.navigationController.toolbar.delegate = self;

Related

UISearchBar placeholder text - align to centre programatically

I am using UISearchBar for search purposes using Objective C. I need the placeholder text of search bar to be aligned to the center of the search bar programatically and when user starts typing, text must be aligned left.
Thanks in Advance
I had a same problem like yours before. I couldn't find any workaround and after all I just used UILabel and UISearchBarDelegate methods.
ViewController.h:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UISearchBarDelegate>
#end
ViewController.m:
#import "ViewController.h"
#interface ViewController () {
UISearchBar *srchBar;
UILabel *customPlaceHolderForSearchBar;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
CGRect frm = CGRectMake(0, 0, self.view.frame.size.width, 80);
srchBar = [[UISearchBar alloc] initWithFrame:frm];
srchBar.delegate = self;
[self.view addSubview:srchBar];
customPlaceHolderForSearchBar = [[UILabel alloc] initWithFrame:frm];
customPlaceHolderForSearchBar.text = #"PlaceHolder text";
customPlaceHolderForSearchBar.textColor = [UIColor grayColor];
customPlaceHolderForSearchBar.textAlignment = NSTextAlignmentCenter;
[self.view addSubview:customPlaceHolderForSearchBar];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
customPlaceHolderForSearchBar.hidden = YES;
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
if (searchBar.text.length < 1) {
customPlaceHolderForSearchBar.hidden = NO;
}
}
#end

Protocols is not working

Hi I am adding one custom button programmatically on navigation bar and i have written all button properties in my background class and i am calling this method from my main class
And here I have used protocols for getting button touching event in my main class from background class but it's not working using protocols
my code:-
background class:-
BackGroundClass.h
#import <UIKit/UIKit.h>
#protocol buttonprotocol<NSObject>
#required
- (void) buttonTapped;
#end
#interface BackGroundClass : UIViewController
#property (nonatomic, weak) id<buttonprotocol> delegate;
#end
BackGroundClass.m
#import "BackGroundClass.h"
#interface BackGroundClass ()
#end
#implementation BackGroundClass
#synthesize delegate;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)backbutton: (UINavigationItem *)navigationitem
{
UIImage* image3 = [UIImage imageNamed:#"back.png"];
CGRect frameimg = CGRectMake(15,5,25,25);
UIButton *someButton = [[UIButton alloc] initWithFrame:frameimg];
[someButton setBackgroundImage:image3 forState:UIControlStateNormal];
[someButton addTarget:self action:#selector(Back_btn:)
forControlEvents:UIControlEventTouchUpInside];
[someButton setShowsTouchWhenHighlighted:YES];
UIBarButtonItem *mailbutton =[[UIBarButtonItem alloc] initWithCustomView:someButton];
navigationitem.leftBarButtonItem = mailbutton;
}
- (void)Back_btn :(id)sender
{
[delegate buttonTapped];
}
#end
main class:-
mainclass.h
#import <UIKit/UIKit.h>
#import "BackGroundClass.h"
#interface mainclass : UIViewController<buttonprotocol>
mainclass.m
#import "mainclass.h"
#import "BackGroundClass.h"
#interface mainclass ()
{
BackGroundClass * bg;
}
#end
#implementation mainclass
- (void)viewDidLoad {
[super viewDidLoad];
bg = [[BackGroundClass alloc]init];
[bg backbutton:self.navigationItem];
}
- (void)buttonTapped
{
NSLog(#"ok it's 2");
}
but that above button tapped a method isn't called what I did wrong?
When you are creating the object of your BackGroundClass class, then you are not setting the delegate of the class to self, thats why your delegate method is not calling, try it like this
bg = [[BackGroundClass alloc]init];
bg.delegate = self;
First of all, using Class in class names is bad practice. As for View Controllers you should use either ViewController or VC postfix for your class names.
For example, the proper names of your Objective-C classes would be: BackgroundViewController, MainViewController
Secondly, ViewController instances are used to react to user interaction with the view attached to this ViewController and provide visible changes based on Data component of MVC work.
So, there is no reason to use second, in your case BackgroundViewController (BackgroundClass).
For more info about MVC pattern, please refer this link:
Apple's MVC articles
As there is no need in external ViewController we also should remove the delegate using and place all logic inside this main View Controller.
Thirdly, as mentioned in Apple's Mobile HIG, buttons should have a height around 44px, so your back button's size of 25x25 would make most users experience hard trying to tap on it.
At last, you should receive the class with code similar to it:
MainViewController.h
#import <UIKit/UIKit.h>
#interface MainViewController : UIViewController
#end
MainViewController.m
#import "MainViewController.h"
#implementation MainViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIImage *icon = [UIImage imageNamed:#"back.png"];
static CGFloat defaultButtonSize = 44.; // Default button's tap area size
CGSize buttonSize = CGSizeMake(defaultButtonSize, defaultButtonSize);
// The size image should take inside the button
CGSize imageSizeInsideButton = CGSizeMake(25., 25.);
CGRect frameimg = CGRectMake(15., 5., defaultButtonSize, defaultButtonSize);
UIButton *someButton = [[UIButton alloc] initWithFrame:frameimg];
[someButton setImage:icon forState:UIControlStateNormal];
[someButton addTarget:self
// No need to put colon after method name,
// since you have no use of control that triggered action
action:#selector(backButtonClicked)
forControlEvents:UIControlEventTouchUpInside];
someButton.showsTouchWhenHighlighted = YES;
// Calculate edge insets so image will take the size
// you specified dozen of lines before
CGFloat imageVerticalPaddingInButton = (buttonSize.height - imageSizeInsideButton.height) / 2.;
CGFloat imageHorizontalPaddingInButton = (buttonSize.height - imageSizeInsideButton.height) / 2.;
// Apply it to button
someButton.imageEdgeInsets = UIEdgeInsetsMake(imageVerticalPaddingInButton,
imageHorizontalPaddingInButton,
imageVerticalPaddingInButton,
imageHorizontalPaddingInButton);
UIBarButtonItem *mailbutton =[[UIBarButtonItem alloc] initWithCustomView:someButton];
self.navigationItem.leftBarButtonItem = mailbutton;
}
// As stated in "addTarget", there is no "sender" since you don't really need it
// If you ever would need the use of it,
// don't forget to put colon in "addTarget" UIButton's method
// and place something like :(UIButton *)buttonThatClicked
// after methodName
- (void)backButtonClicked {
// Get back to your previous view controller or do whatever you like there
[self.navigationController popViewControllerAnimated:YES];
}
#end
But if you want to use this thing in as many View Controllers as possible, then you should create the category:
UIViewController+CustomBackButton.h
#import <UIKit/UIKit.h>
#interface UIViewController (CustomBackButton)
- (void)setBackButtonImage:(UIImage *)image withSize:(CGSize)size target:(id)target selector:(SEL)selector;
#end
UIViewController+CustomBackButton.m
#import "UIViewController+CustomBackButton.h"
#implementation UIViewController (CustomBackButton)
- (void)setBackButtonImage:(UIImage *)image withSize:(CGSize)size target:(id)target selector:(SEL)selector {
static CGFloat defaultButtonSize = 44.;
CGSize buttonSize = CGSizeMake(defaultButtonSize, defaultButtonSize);
CGRect frameimg = CGRectMake(15., 5., defaultButtonSize, defaultButtonSize);
UIButton *someButton = [[UIButton alloc] initWithFrame:frameimg];
[someButton setImage:image forState:UIControlStateNormal];
[someButton addTarget:target
action:selector
forControlEvents:UIControlEventTouchUpInside];
someButton.showsTouchWhenHighlighted = YES;
CGFloat imageVerticalPaddingInButton = (buttonSize.height - size.height) / 2.;
CGFloat imageHorizontalPaddingInButton = (buttonSize.height - size.height) / 2.;
someButton.imageEdgeInsets = UIEdgeInsetsMake(imageVerticalPaddingInButton,
imageHorizontalPaddingInButton,
imageVerticalPaddingInButton,
imageHorizontalPaddingInButton);
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithCustomView:someButton];
self.navigationItem.leftBarButtonItem = backButton;
}
#end
And then your View Controller's implementation file will be much cleaner.
MainViewController.m
#import "MainViewController.h"
#import "UIViewController+CustomBackButton.h"
#implementation MainViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIImage *icon = [UIImage imageNamed:#"back.png"];
CGSize iconSize = CGSizeMake(25., 25.);
[self setBackButtonImage:icon
withSize:iconSize
target:self
selector:#selector(backButtonClicked)];
}
- (void)backButtonClicked {
// Get back to your previous view controller or do whatever you like there
[self.navigationController popViewControllerAnimated:YES];
}
#end
And then you can use this on every ViewController to customize your back button.

Editing bounds of UIView when presenting hides keyboard in iOS 8

I present a small "login" UIViewController as a UIModalPresentationFormSheet with custom bounds. In the viewWillLayoutSubviews method, I change the size of the view to (300,250). This has worked in iOS 5/6/7 but no longer works in 8.
When the view is presented and a UITextField is tapped, the app becomes unresponsive (not frozen, just not responding to touches). Almost as if the keyboard is presented but not appearing. Delegate methods ARE called correctly. If I remove the self.view.superview.bounds = CGRectMake(0, 0, 300, 250); from the viewWillLayoutSubviews method the keyboard works, but the view is now a full sized UIModalPresentationFormSheet style.
This only happens in iOS 8, so I can only assume its an issue with the way the keyboard is presented and the way I am masking/resizing the view, but I'm at a loss as to the solution.
Presenting ViewController -
UserLoginViewController *loginVC = [[UserLoginViewController alloc] initWithNibName:#"UserLoginViewController" bundle:nil];
loginVC.modalPresentationStyle = UIModalPresentationFormSheet;
loginVC.delegate = self;
[self presentViewController:loginVC animated:YES completion:nil];
Editing the view bounds -
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
self.view.superview.layer.cornerRadius = 10.0;
self.view.superview.layer.masksToBounds = YES;
self.view.superview.bounds = CGRectMake(0, 0, 300, 250);
}
In iOS8 You shouldn't change superview bounds in viewWillLayoutSubviews because it causes infinite loop.
EDIT:
in iOS8 property preferredContentSize works well.
You should change your code in that way:
UserLoginViewController *loginVC = [[UserLoginViewController alloc] initWithNibName:#"UserLoginViewController" bundle:nil];
loginVC.modalPresentationStyle = UIModalPresentationFormSheet;
loginVC.delegate = self;
if(IS_IOS8)
{
loginVC.preferredContentSize = CGSizeMake(300, 250);
}
[self presentViewController:loginVC animated:YES completion:nil];
Editing the view bounds -
- (void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
self.view.superview.layer.cornerRadius = 10.0;
self.view.superview.layer.masksToBounds = YES;
if(!IS_IOS8)
{
self.view.superview.bounds = CGRectMake(0, 0, 300, 250);
}
}
Another way, which gives you more customization options is to use UIPresentationController and UIViewControllerTransitioningDelegate. Take a look at my code below.
Parent view controller:
_aboutViewController = [[AboutViewController alloc] init];
_aboutViewController.modalPresentationStyle = UIModalPresentationFormSheet;
if(IS_IOS8)
{
if(aboutTransitioningDelegate == nil)
{
aboutTransitioningDelegate = [[AboutTransitioningDelegate alloc] init];
}
_aboutViewController.transitioningDelegate = aboutTransitioningDelegate;
_aboutViewController.modalPresentationStyle = UIModalPresentationCustom;
}
[self presentViewController:_aboutViewController animated:YES completion:nil];
AboutViewController.m
#import "AboutViewController.h"
#interface AboutViewController ()
#end
#implementation AboutViewController
- (void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
if(IS_IOS8)
{
return;
}
CGSize displaySize = CGSizeMake(320, 462);
self.view.superview.bounds = CGRectMake(0, 0, displaySize.width, displaySize.height);
}
#end
AboutTransitioningDelegate.h:
#interface AboutTransitioningDelegate : NSObject <UIViewControllerTransitioningDelegate>
#end
AboutTransitioningDelegate.m:
#import "AboutTransitioningDelegate.h"
#import "AboutPresentationController.h"
#implementation AboutTransitioningDelegate
-(UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source
{
return [[AboutPresentationController alloc] initWithPresentedViewController:presented presentingViewController:presenting];
}
#end
AboutPresentationController.h
#import <UIKit/UIKit.h>
#interface AboutPresentationController : UIPresentationController
#end
AboutPresentationController.m
#import "AboutPresentationController.h"
#implementation AboutPresentationController
-(CGRect)frameOfPresentedViewInContainerView
{
CGSize displaySize = CGSizeMake(320, 462);
if([[Config sharedInstance] latestVersionFromAppstoreInstalled])
{
displaySize = CGSizeMake(320, 416);
}
CGRect r = CGRectZero;
r.size = displaySize;
r.origin.y = self.containerView.bounds.size.height/2 - displaySize.height/2;
r.origin.x = self.containerView.bounds.size.width/2 - displaySize.width/2;
return r;
}
-(void)containerViewWillLayoutSubviews
{
[super containerViewWillLayoutSubviews];
self.presentedView.frame = [self frameOfPresentedViewInContainerView];
}
#end
ProjectName-Prefix.pch
#define IS_IOS8 ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8)
The simplest way to call containerViewWillLayoutSubviews() is to call:
containerView?.setNeedsLayout()

iOS setting view variable from view controller programmatically

I've created a view with a variable and loaded it in the loadView method of a view controller. How do I pass a value to the view variable from the view controller after the loadView method has been called?
LocationView.m
#import "LocationView.h"
#implementation LocationView
#synthesize locationTitle;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
locationTitle = [[UILabel alloc]initWithFrame:CGRectMake(10, 10, 300, 20)];
[self addSubview:locationTitle];
}
return self;
}
LocationViewController.m
#import "LocationViewController.h"
#import "LocationView.h"
#interface LocationViewController ()
#end
#implementation LocationViewController
- (void)loadView
{
CGRect frame = [[UIScreen mainScreen] bounds];
LocationView *locationView = [[LocationView alloc] initWithFrame:frame];
[self setView:locationView];
}
- (void)viewDidLoad
{
[super viewDidLoad];
How do I pass a value to locationTitle here?
}
You've already set up the locationTitle property for LocationView objects, so you can just access that. The only thing you need to do beforehand is keep a reference to the LocationView object around in an instance variable so you can access it from any instance method.
#implementation LocationViewController {
LocationView *_locationView;
}
- (void)loadView
{
CGRect frame = [[UIScreen mainScreen] bounds];
_locationView = [[LocationView alloc] initWithFrame:frame];
[self setView:_locationView];
}
- (void)viewDidLoad
{
[super viewDidLoad];
_locationView.locationTitle = #"Test";
}
#end
Alternatively, since you are assigning the custom view to the view controllers main view, you could cast that:
- (void)viewDidLoad
{
[super viewDidLoad];
((LocationView *)self.view).locationTitle = #"Test";
}

iOS trouble loading an image file to view from view controller programmatically

I have a view with a property that should take an NSString from my view controller and display an image. If I hard code locationImageFile with "320x213-1.png" in my view, the image displays properly, but if I try to set locationImageFile from my view controller, the image doesn't appear. I feel like I'm missing something pretty basic. Side note: I seem to be able to set the locationTitle property from my view controller without any problems.
LocationViewController.m
#import "LocationViewController.h"
#import "LocationView.h"
#implementation LocationViewController
{
LocationView *_locationView;
}
- (void)loadView
{
CGRect frame = [[UIScreen mainScreen] bounds];
_locationView = [[LocationView alloc] initWithFrame:frame];
[self setView:_locationView];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
_locationView.locationTitle.text = aLocation.name;
_locationView.locationImageFile = #"320x213-1.png";
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
LocationView.m
#import "LocationView.h"
#implementation LocationView
#synthesize locationTitle;
#synthesize locationImageFile;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self setBackgroundColor: [UIColor blueColor]];
// Image container
UIImage *locationImage = [UIImage imageNamed:locationImageFile];
UIImageView *locationImageContainer = [[UIImageView alloc] initWithImage:locationImage];
[locationImageContainer setTranslatesAutoresizingMaskIntoConstraints:NO];
locationImageContainer.backgroundColor = [UIColor yellowColor];
[self addSubview:locationImageContainer];
// Text line
locationTitle = [[UILabel alloc]init];
[locationTitle setTranslatesAutoresizingMaskIntoConstraints:NO];
locationTitle.backgroundColor = [UIColor whiteColor];
[self addSubview:locationTitle];
}
return self;
}
#end
I think this is because the loadView method are invoke earlier than viewDidLoad method.
so when you set _locationView.locationImageFile = #"320x213-1.png";,the containerView's image are not being set.
You can consider declare locationImageContainer as a property of locationView , and set it's image directly.like
_locationView.locationImageContainer.image = [UIImage imageNamed:#"320x213-1.png"];
instead of setting locationImageFile as a property.
When LocationView is initialized, the value of the instance variable locationImageFile equals nil. Override the setter of the locationImageFile property inside LocationView.m like this:
- (void)setLocationImageFile:(NSString *)aLocationImageFile
{
locationImageFile = aLocationImageFile;
locationImageContainer.image = [UIImage imageNamed:aLocationImageFile];
}
You can try, doing it like this:
_locationView.locationImageFile = [UIImage imageNamed:locationImageFile];
if you did it like this:
_locationView.locationImageFile = locationImageFile;

Resources