Determine if current screen has visible navigation bar - ios

I have a singlton object. Is there any simple way to determine if current screen contains a navigation bar within singlton methods?
The singleton is UIView subclass. It's designed for showing prorgess activity, e.g. network exchange. It looks like black rectangle dropping down from top and hiding when the work is done. Why singleton? It's easy to call it from any place of code
The followed snippet is showing the initialization of activity singleton and published here just for better understaning my idea.
-(void) showUpdatingView:(NSString *) msg {
[self initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 44)];
activity = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite] autorelease];
activity.frame = CGRectMake(5, 10, 22, 22);
labelView = [[[UILabel alloc] initWithFrame:CGRectMake(35, 10, [UIScreen mainScreen].bounds.size.width - 10, 22)] autorelease];
labelView.font = [UIFont boldSystemFontOfSize:12];
labelView.backgroundColor = [UIColor clearColor];
labelView.textColor = [UIColor whiteColor];
labelView.text = msg;
[self addSubview:activity];
[self addSubview:labelView];
self.backgroundColor = [UIColor blackColor];
self.alpha = 0.7;
}
The activity can be called by
[[ActivitySingleton getInstance] showUpdatingView:#"Getting data."];
it's not all.
The singleton is being created in AppDelegate object and the view is added to
inlineActivity = [[CHInlineActivityView alloc] initView];
[self.window.rootViewController.view addSubview:inlineActivity];
I know it may look crazy. But when I was designing it seemed to me reasonable

if you have all in one navigationController:
BOOL navHidden = self.window.rootViewController.navigationController.navigatonBarHidden;
if you don't it is a bit harder.. you could check the window's subviews and see if you can find a UINavigationBar
id navbar = [self.window firstSubviewOfKind:[UINavigationBar class] withTag:NSNotFound];
BOOL navHidden = navbar == nil;
#implementation NSView (findSubview)
- (NSArray *)findSubviewsOfKind:(Class)kind withTag:(NSInteger)tag inView:(NSView*)v {
NSMutableArray *array = [NSMutableArray array];
if(kind==nil || [v isKindOfClass:kind]) {
if(tag==NSNotFound || v.tag==tag) {
[array addObject:v];
}
}
for (id subview in v.subviews) {
NSArray *vChild = [self findSubviewsOfKind:kind withTag:tag inView:subview];
[array addObjectsFromArray:vChild];
}
return array;
}
#pragma mark -
- (NSView *)firstSubviewOfKind:(Class)kind withTag:(NSInteger)tag {
NSArray *subviews = [self findSubviewsOfKind:kind withTag:tag inView:self];
return subviews.count ? subviews[0] : nil;
}
#end

Related

SearchBar moves when active

I have a UIViewController with a SegmentedControl, UITableView and a UISearchController. The SegmentedControl is at the top of the main View with the tableView just beneath it. The searchController's searchBar is placed in the tableView.tableHeaderView and looks like this:
When the searchBar is tapped (made active) it moves down leaving a gap just above:
Also, if the searchBar is active and then the segmentedConrol is tapped (filtering the table data and reloading the tableView) then the tableView loads but with a gap at the top. (I have purposely set the searchBar to hidden when the 'Category' filter is selected.
If the segmentedControl 'Category' is selected when the searchBar is not active this is how it looks (and should look):
I need two things (I think they are related), 1) for the searchBar to NOT move when active and 2) for the searchBar to not be present when 'Category' is selected and for the tableView to have no gap at the top.
.h:
#interface ExhibitorViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, UISearchControllerDelegate, UISearchBarDelegate, UISearchResultsUpdating>
{
// DATA
NSMutableArray *arrayOfExhibitors;
NSMutableArray *arrayOfExhibitorsFiltered;
NSMutableArray *arrayOfCategories;
NSMutableArray *arrayOfCategoriesFiltered;
// VARS
int selectedSegment;
float searchBarHeight;
float tableViewY;
NSString *currentCategory;
CGRect tableViewStartRect;
// UI
UISegmentedControl *segmentedControl;
UIView *categorySelectedView;
UIView *headerView;
}
#property (nonatomic, strong) UITableView *tableView;
#property (nonatomic, strong) UISearchController *searchController;
#property (nonatomic, readonly) NSArray *searchResults;
#property (strong, nonatomic) NSString *sponsorsOnly;
#end
.m:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:NO animated:NO];
if (selectedSegment == 0) {
self.searchController.searchBar.hidden = FALSE;
}
if (!_searchController.searchBar.superview) {
self.tableView.tableHeaderView = self.searchController.searchBar;
}
}
-(void)loadTableView
{
[self printStats:#"loadTableView START"];
searchBarHeight = self.searchController.searchBar.frame.size.height;
Settings *settingsInstance = [Settings new];
if(!_tableView) {
segmentedControl = [UISegmentedControl new];
segmentedControl = [[UISegmentedControl alloc]initWithItems:[NSArray arrayWithObjects:#"Exhibitor", #"Category", nil]];
[segmentedControl setFrame:CGRectMake(0, 0, self.view.frame.size.width, 35)];
segmentedControl.selectedSegmentIndex = 0;
[segmentedControl addTarget:self action:#selector(segmentedControlHasChangedValue) forControlEvents:UIControlEventValueChanged];
self.automaticallyAdjustsScrollViewInsets = YES;
self.edgesForExtendedLayout = UIRectEdgeNone;
self.searchController.hidesNavigationBarDuringPresentation = NO;
//self.definesPresentationContext = NO;
float tvX = self.view.frame.origin.x;
float tvY = self.view.frame.origin.y + segmentedControl.frame.size.height;
float tvWidth = self.view.frame.size.width;
float frameHeight = self.view.frame.size.height;
float tvHeight = self.view.frame.size.height - segmentedControl.frame.size.height;
tableViewStartRect = CGRectMake(tvX, tvY, tvWidth, tvHeight);
_tableView = [UITableView new];
_tableView = [[UITableView alloc] initWithFrame:tableViewStartRect];
//_tableView.contentInset = UIEdgeInsetsMake(0, 0, 44, 0);
_tableView.separatorColor = [UIColor clearColor];
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.view addSubview:segmentedControl];
[self.view addSubview:_tableView];
[_tableView setTag:1];
[_tableView setDataSource:self];
[_tableView setDelegate:self];
}
if (!categorySelectedView) {
float levelOneStart = (0);
categorySelectedView = [[UIView alloc] initWithFrame:CGRectMake(0, levelOneStart, self.view.frame.size.width, (screenHeight * 0.05))];
[categorySelectedView setBackgroundColor:[UIColor grayColor]];
[categorySelectedView setTag:4];
MyLabel *catSelectedLabel = [[MyLabel alloc] initWithFrame:categorySelectedView.frame];
[catSelectedLabel setFont:[UIFont systemFontOfSize:[settingsInstance getFontSizeFor:#"Label"]]];
[catSelectedLabel setTag:5];
[catSelectedLabel setBackgroundColor:[UIColor lightTextColor]];
[catSelectedLabel setTextColor:[UIColor darkGrayColor]];
UIButton *categoryBackButton = [[UIButton alloc] initWithFrame:CGRectMake((screenWidth * 0.6), levelOneStart, (screenWidth * 0.4), (screenHeight * 0.05))];
[categoryBackButton setTitle:#"^ Back ^" forState:UIControlStateNormal];
[categoryBackButton setTitleColor:[UIColor darkGrayColor] forState:UIControlStateNormal];
[categoryBackButton addTarget:self action:#selector(resetTableViewCategories) forControlEvents:UIControlEventTouchUpInside];
[catSelectedLabel addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(resetTableViewCategories)]];
[categoryBackButton.titleLabel setFont:[UIFont systemFontOfSize:[settingsInstance getFontSizeFor:#"Label"]]];
[categorySelectedView addSubview:catSelectedLabel];
[categorySelectedView addSubview:categoryBackButton];
[categorySelectedView setHidden:TRUE];
}
if (!headerView) {
headerView = [[UIView alloc] initWithFrame:CGRectMake(0, (0), screenWidth, (searchBarHeight))];
[headerView addSubview:categorySelectedView];
[self.view addSubview:headerView];
[headerView setBackgroundColor:[UIColor purpleColor]];
[self.view sendSubviewToBack:headerView];
}
[self.view setTag:11];
tableViewY = _tableView.frame.origin.y;
[self printStats:#"loadTableView END"];
}
-(UISearchController*)searchController
{
if (!_searchController) {
_searchController = [[UISearchController alloc]initWithSearchResultsController:nil];
_searchController.searchResultsUpdater = self;
_searchController.dimsBackgroundDuringPresentation = NO;
_searchController.searchBar.delegate = self;
[_searchController.searchBar sizeToFit];
}
return _searchController;
}
-(void)segmentedControlHasChangedValue
{
[self.searchController setActive:NO];
if ((segmentedControl.selectedSegmentIndex == 0)) {
selectedSegment = 0;
currentCategory = #"";
[self resetTableViewExhibitors];
[_tableView setContentOffset:CGPointMake(0, -1) animated:NO];
} else {
selectedSegment = 1;
[self resetTableViewCategories];
[_tableView setContentOffset:CGPointMake(0, -1) animated:NO];
//[_tableView setContentOffset:CGPointMake(0, 56) animated:NO];
[_tableView setTableFooterView:nil];
}
[_tableView reloadData];
}
I have tried changing the insets of various views and forcing a manual changes to the frames of various views (this is the closest thing to a fix but seems very hacky). What am I doing wrong?
Edit: Have also tried :
-(void)segmentedControlHasChangedValue
{
[self.searchController setActive:NO];
if ((segmentedControl.selectedSegmentIndex == 0)) {
selectedSegment = 0;
currentCategory = #"";
[self resetTableViewExhibitors];
[_tableView setContentOffset:CGPointMake(0, -1) animated:NO];
} else {
selectedSegment = 1;
[_searchController dismissViewControllerAnimated:NO completion^() {
[self resetTableViewCategories];
[_tableView setContentOffset:CGPointMake(0, -1) animated:NO];
[_tableView setTableFooterView:nil];
}];
}
[_tableView reloadData];
}
Because you use UISearchController so searchBar will always move when it actives. To avoid it, use UISearchBar. And when you use UISearchBar, it's easy to hide when you select Category tab

Use of UIView to abstract away common UI (much like a "partial" in web) drawRect vs init vs layoutSubviews

I'm trying to make my View Controllers leaner by abstracting common UI away into UIView subclasses and just instantiating them in my VCs, much like I would create HTML templates in web dev.
Here is my VC:
- (void)addEmptyView {
self.emptyHomeView = [[PLOTEmptyHomeView alloc] initWithFrame:CGRectMake(0, 10, self.view.bounds.size.width, self.view.bounds.size.height - 113) andUser:self.userModel.user];
[self.view addSubview:self.emptyHomeView];
}
And the UIView I subclass and instantiate:
- (id)initWithFrame:(CGRect)frame andUser:(NSDictionary *)user {
self = [super initWithFrame:frame];
if(self){
self.user = user;
[self drawUI];
}
return self;
}
- (void)drawUI {
self.arrowUp = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"arrow-up"]];
CGRect arrowUpFrame = self.arrowUp.frame;
arrowUpFrame.origin.x = self.bounds.size.width - 60;
arrowUpFrame.size.width = 33.75;
arrowUpFrame.size.height = 33;
self.arrowUp.frame = arrowUpFrame;
[self addSubview:self.arrowUp];
self.welcome = [[UILabel alloc] initWithFrame:CGRectMake(0, 167.5, self.bounds.size.width, 22.5)];
NSArray *nameParts = [self.user[#"name"] componentsSeparatedByString:#" "];
self.welcome.text = [NSString stringWithFormat:#"Hey %#", nameParts[0]];
self.welcome.font = [UIFont fontWithName:#"Avenir-Light" size:24];
self.welcome.textColor = [UIColor plotPlaceholderGrey];
self.welcome.textAlignment = NSTextAlignmentCenter;
[self addSubview:self.welcome];
}
Now this code all works fine, but for my own understanding, am I abusing the init method? I'm also aware of layoutSubviews & drawRect in UIView but i'm not sure if I should be using them in the above scenario?
Any pointers are appreciated...
Your not abusing of init method, but you have to declare all your ui objects and all their properties without define the frame and in the layoutsubviews, you define the frame of all your object. It's my way to declare an custom view.
- (id)initWithFrame:(CGRect)frame andUser:(NSDictionary *)user {
self = [super initWithFrame:frame];
if(self){
self.user = user;
self.arrowUp = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"arrow-up"]];
[self addSubview:self.arrowUp];
self.welcome = [[UILabel alloc] init];
NSArray *nameParts = [self.user[#"name"] componentsSeparatedByString:#" "];
self.welcome.text = [NSString stringWithFormat:#"Hey %#", nameParts[0]];
self.welcome.font = [UIFont fontWithName:#"Avenir-Light" size:24];
self.welcome.textColor = [UIColor plotPlaceholderGrey];
self.welcome.textAlignment = NSTextAlignmentCenter;
[self addSubview:self.welcome];
}
return self;
}
- (void)layoutSubviews {
CGRect arrowUpFrame = self.arrowUp.frame;
arrowUpFrame.origin.x = self.bounds.size.width - 60;
arrowUpFrame.size.width = 33.75;
arrowUpFrame.size.height = 33;
self.arrowUp.frame = arrowUpFrame;
self.welcome.frame =CGRectMake(0, 167.5, self.bounds.size.width, 22.5)];
}
Hope it will help you.
Optimally, you can instantiate and add subviews in your method as shown, but do actual layout involving frames in layoutSubviews. The code you have will work as is, but if your initialize would be from a nib or something that doesn't provide the core frame (or autolayout was involved) you may not truly know the proper bounds/frame at init time. Often layout code is dependent on other factors that may change so layoutSubviews is a more proper location.

iOS 7 UITableView inside a popover

I have a UITableView which has some custom styling. This table view appears in two places in the app, one of which is inside a UIPopoverController. However when the tableview is inside the popover it takes on the default tableview styling as stated in the UI Transition Guide under "Popover".
The problem I have is that there appears to be nowhere to change this behaviour. Regardless of where I try and modify properties of the tableview the view inside the popover doesn't change.
Anyone dealt with this issue before or have any ideas?
Here is the init method of LibraryProductView where I create the table view:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.sectionOrdering = [NSArray arrayWithObjects:
[NSNumber numberWithInt:LIBRARY_PRODUCT_SECTION_DESCRIPTION],
[NSNumber numberWithInt:LIBRARY_PRODUCT_SECTION_DOCUMENTS],
[NSNumber numberWithInt:LIBRARY_PRODUCT_SECTION_ACTIVE_INGREDIENTS],
[NSNumber numberWithInt:LIBRARY_PRODUCT_SECTION_RELATED_PRODUCTS],
[NSNumber numberWithInt:LIBRARY_PRODUCT_SECTION_RELATED_DOCUMENTS], nil];
self.backgroundColor = [UIColor whiteColor];
self.tableView = [[UITableView alloc] initWithFrame:CGRectInset(self.bounds, 10, 0) style:UITableViewStyleGrouped];
self.tableView.backgroundColor = [UIColor whiteColor];
self.tableView.dataSource = self;
self.tableView.delegate = self;
self.tableView.separatorColor = [UIColor clearColor];
self.tableView.showsVerticalScrollIndicator = NO;
[self addSubview:self.tableView];
}
return self;
}
Here is where the containing view (LibraryProductView) is added to the popover:
- (IBAction)didTouchInformationButton:(id)sender
{
if (_infoPopover != nil && _infoPopover.isPopoverVisible)
{
[_infoPopover dismissPopoverAnimated:YES];
return;
}
CGSize preferredSize = CGSizeMake(600.0f, 500.0f);
LibraryProductViewController* productController = [[[LibraryProductViewController alloc] initWithPreferredSize:preferredSize] autorelease];
productController.filterByMyCompany = NO;
productController.product = _activityInput.product;
UINavigationController* nav = [[[UINavigationController alloc] initWithRootViewController:productController] autorelease];
nav.title = _activityInput.product.name;
RELEASE(_infoPopover);
_infoPopover = [[UIPopoverController alloc] initWithContentViewController:nav];
_infoPopover.popoverContentSize = CGSizeMake(preferredSize.width, preferredSize.height + 46);
[_infoPopover presentPopoverFromRect:_infoButton.frame inView:_infoButton permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
}
The LibraryProductView is created within viewDidLoad method of LibraryProductViewController.
- (void)viewDidLoad
{
[super viewDidLoad];
self.libraryProductView = [[LibraryProductView alloc] initWithFrame:(usingPreferredSize ? CGRectMake(0.0, 0.0, preferredSize.width, preferredSize.height) : self.view.bounds)];
self.libraryProductView.dataSource = self;
self.libraryProductView.delegate = self;
[self.view addSubview:self.libraryProductView];
}
To set properties for the TableView you might do so in
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
[tableView setBackgroundColor:[UIColor redcolor]];
[tableView setSeparatorColor: [UIColor blueColor]];
return 1;
}
This, of course, assumes you have set UITableViewDataSource in your .h file

Permanet view on window objective c

I need to add a UIView to the main window, the UIView consists in a view with some buttons.
The problem is, the buttons i put inside that view, is not responding for the touch events,
like it have some view in front of it.
That view need to be a singleton class, cause i need to respond the touchevent in any class.
Heres the code for the UIView :
+ (MenuBarView *)sharedMenuBar
{
static MenuBarView *sharedSingleton;
#synchronized(self) {
if (!sharedSingleton) sharedSingleton = [[MenuBarView alloc] init];
return sharedSingleton;
}
}
-(id)init
{
self = [super init];
if(self)
{
self.userInteractionEnabled = YES;
backgroundBarImage = [UIImage imageNamed:#"Barra.png"];
UIImageView * backgroundBar = [[UIImageView alloc]initWithImage:backgroundBarImage];
backgroundBar.contentMode = UIViewContentModeCenter;
backgroundBar.backgroundColor = [UIColor clearColor];
[backgroundBar setFrame:CGRectMake(0, 0, backgroundBarImage.size.width, backgroundBarImage.size.height)];
[self addSubview:backgroundBar];
UIButton * rootBTN = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[rootBTN setFrame:CGRectMake(0, 8, 100, 40)];
[rootBTN addTarget:self action:#selector(selectedBarButton:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:rootBTN];
UIImage * localizacaoIMG = [UIImage imageNamed:#"Localizador"];
UIImageView * localizacaoView = [[UIImageView alloc]initWithImage:localizacaoIMG];
localizacaoView.contentMode = UIViewContentModeScaleAspectFill;
[localizacaoView setFrame:CGRectMake(backgroundBar.frame.origin.x+130, 8, localizacaoIMG.size.width, localizacaoIMG.size.height)];
[backgroundBar addSubview:localizacaoView];
UIButton * localizacaoBTN = [UIButton buttonWithType:UIButtonTypeCustom];
[localizacaoBTN setFrame:CGRectMake(backgroundBar.frame.origin.x+110, 8, 60, 40)];
localizacaoBTN.tag = 1;
[self addSubview:localizacaoBTN];
}
return self;
}
//The event handling method
-(void)selectedBarButton:(UIButton *)sender
{
NSLog(#"OK");
[self.delegate selectedMenuBar:sender.tag];
}
and heres the implementation on the AppDelegate :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[InitialViewController alloc] init];
self.navController = [[EzMallNavViewController alloc]initWithRootViewController:self.viewController];
self.window.rootViewController = self.navController;
[self.window makeKeyAndVisible];
if(IS_IPOD)
{
[[MenuBarView sharedMenuBar]setFrame:CGRectMake(0, self.window.frame.size.height-51, [MenuBarView sharedMenuBar].frame.size.width, [MenuBarView sharedMenuBar].frame.size.height)];
}
else
{
[[MenuBarView sharedMenuBar]setFrame:CGRectMake(0, self.window.frame.size.height, [MenuBarView sharedMenuBar].frame.size.width, [MenuBarView sharedMenuBar].frame.size.height)];
}
[MenuBarView sharedMenuBar].delegate = self;
[self.window addSubview:[MenuBarView sharedMenuBar]];
return YES;
}
#pragma mark MenuBarDelegateMethods
-(void)selectedMenuBar:(int) tag
{
NSLog(#"Here");
}
It looks like your menu view has a zero size frame so no touches are detected. The buttons appear on screen because the menu view isn't set to clip drawing to its bounds.
Try to set different color for different views and analyze the view hierarchy ,it might be possible that you have added the view in wrong order .

Can I set image as a title to UINavigationBar?

Is it possible to set some image as title of Navigation bar?
I think NYTimes application used a Navigation bar and title is look like image file (the reason why it's seems UINavigationBar is because they use right button to search).
You can use an UIImageView for the UINavigationItem.titleView property, something like:
self.navigationItem.titleView = myImageView;
I find that a transparent .png at about 35px in height has worked well.
- (void)awakeFromNib {
//put logo image in the navigationBar
UIImageView* img = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"logo.png"]];
self.navigationItem.titleView = img;
[img release];
}
You can do it right from storyboard (as of Xcode 7):
Create a view outside main view of view controller. It can be a nested view or just an image
Add navigation item to your view controller
Ctrl+ drag from navigation item and drop on outside view
4.select title view
I have created a custom category for UINavigationBar as follows
UINavigationBar+CustomImage.h
#import <UIKit/UIKit.h>
#interface UINavigationBar (CustomImage)
- (void) setBackgroundImage:(UIImage*)image;
- (void) clearBackgroundImage;
- (void) removeIfImage:(id)sender;
#end
UINavigationBar+CustomImage.m
#import "UINavigationBar+CustomImage.h"
#implementation UINavigationBar (CustomImage)
- (void) setBackgroundImage:(UIImage*)image {
if (image == NULL) return;
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(110,5,100,30);
[self addSubview:imageView];
[imageView release];
}
- (void) clearBackgroundImage {
NSArray *subviews = [self subviews];
for (int i=0; i<[subviews count]; i++) {
if ([[subviews objectAtIndex:i] isMemberOfClass:[UIImageView class]]) {
[[subviews objectAtIndex:i] removeFromSuperview];
}
}
}
#end
I invoke it from my UINavigationController
[[navController navigationBar] performSelectorInBackground:#selector(setBackgroundImage:) withObject:image];
This line will work for you, I always use this
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:#"imageNavBar.png"] forBarMetrics:UIBarMetricsDefault];
I modified the UINavigationBar+CustomImage.m to have the title still visible to the user. Just use insertSubview: atIndex: instead of addSubview:
UINavigationBar+CustomImage.m
#import "UINavigationBar+CustomImage.h"
#implementation UINavigationBar (CustomImage)
- (void) setBackgroundImage:(UIImage*)image {
if (image == NULL) return;
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(0, 0, 320, 44);
[self insertSubview:imageView atIndex:0];
[imageView release];
}
- (void) clearBackgroundImage {
NSArray *subviews = [self subviews];
for (int i=0; i<[subviews count]; i++) {
if ([[subviews objectAtIndex:i] isMemberOfClass:[UIImageView class]]) {
[[subviews objectAtIndex:i] removeFromSuperview];
}
}
}
#end
This also works well too
[self.navigationController.navigationBar.topItem setTitleView:[[UIImageView alloc]initWithImage:[UIImage imageNamed:#"YourLogo"]]];
Do it quickly using storyboard and #IBDesignable:
#IBDesignable class AttributedNavigationBar: UINavigationBar {
#IBInspectable var imageTitle: UIImage? = nil {
didSet {
guard let imageTitle = imageTitle else {
topItem?.titleView = nil
return
}
let imageView = UIImageView(image: imageTitle)
imageView.frame = CGRect(x: 0, y: 0, width: 40, height: 30)
imageView.contentMode = .scaleAspectFit
topItem?.titleView = imageView
}
}
}
Then in attributes inspector just select an image:
and wait a second for result:
So setting view is there where it should be... in storyboard.
For those who have the same error but in Xamarin Forms, the solution is to create a Renderer in iOS app and set the image like so :
[assembly: Xamarin.Forms.ExportRenderer(typeof(Xamarin.Forms.Page), typeof(MyApp.Renderers.NavigationPageRenderer))]
namespace MyApp.Renderers
{
#region using
using UIKit;
using Xamarin.Forms.Platform.iOS;
#endregion
public class NavigationPageRenderer : PageRenderer
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
SetTitleImage();
}
private void SetTitleImage()
{
UIImage logoImage = UIImage.FromFile(ResourceFiles.ImageResources.LogoImageName);
UIImageView logoImageView = new UIImageView(logoImage);
if (this.NavigationController != null)
{
this.NavigationController.NavigationBar.TopItem.TitleView = logoImageView;
}
}
}
}
Hope it helps someone!
I modified the UINavigationBar+CustomImage code to properly work without leaking memory.
- (void)setBackgroundImage:(UIImage *)image
{
if (! image) return;
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
[self addSubview:imageView];
[imageView release];
}
- (void) clearBackgroundImage
{
// This runs on a separate thread, so give it it's own pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *mySubviews = self.subviews;
// Move in reverse direction as not to upset the order of elements in the array
for (int i = [mySubviews count] - 1; i >= 0; i--)
{
if ([[mySubviews objectAtIndex:i] isMemberOfClass:[UIImageView class]])
{
[[mySubviews objectAtIndex:i] removeFromSuperview];
}
}
[pool release];
}
The following is how you would do this in (Xamarin's) MonoTouch with C#.NET
Create a UIViewConvrtoller that is in a NavigationController then call this at any time:
someNiceViewControllerYouMade.NavigationController.NavigationBar
.InsertSubview(new UIImageView
(MediaProvider.GetImage(ImageGeneral.navBar_667x44)),0);
Note: MediaProvider is just a class that fetches images.
This example allows for the view to fill the full Navigation Bar , and lets the text for the items caption appear too.
If your buttons disappear when you navigate back and forth the navigation, this fixed it for me:
NSArray *mySubviews = navigationBar.subviews;
UIImageView *iv = nil;
// Move in reverse direction as not to upset the order of elements in the array
for (int i = [mySubviews count] - 1; i >= 0; i--)
{
if ([[mySubviews objectAtIndex:i] isMemberOfClass:[UIImageView class]])
{
NSLog(#"found background at index %d",i);
iv = [mySubviews objectAtIndex:i];
[[mySubviews objectAtIndex:i] removeFromSuperview];
[navigationBar insertSubview:iv atIndex:0];
}
}
Just use
[navController.navigationBar insertSubview:myImage atIndex:0] ;
where myImage is of type UIImageView
and navController is of type UINavigationController
ios5.0 introduced a heap of features to customise the appearance of standard elements. If you didn't want to use an ImageView for the title, an alternative would be to customise the appearance of all UINavbars using a background image and a custom font/colour.
- (void) customiseMyNav
{
// Create resizable images
UIImage *portraitImage = [[UIImage imageNamed:#"nav_bar_bg_portrait"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
UIImage *landscapeImage = [[UIImage imageNamed:#"nav_bar_bg_landscape"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
// Set the background image
[[UINavigationBar appearance] setBackgroundImage:portraitImage forBarMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setBackgroundImage:landscapeImage forBarMetrics:UIBarMetricsLandscapePhone];
// set the title appearance
[[UINavigationBar appearance] setTitleTextAttributes:
[NSDictionary dictionaryWithObjectsAndKeys:
[UIColor colorWithRed:50.0/255.0 green:150.0/255.0 blue:100/255.0 alpha:1.0],
UITextAttributeTextColor,
[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.6],
UITextAttributeTextShadowColor,
[NSValue valueWithUIOffset:UIOffsetMake(0, -1)],
UITextAttributeTextShadowOffset,
[UIFont fontWithName:#"Arial-Bold" size:0.0],
UITextAttributeFont,
nil]];
}
In MonoTouch you can use this:
this.NavigationItem.TitleView = myImageView;
Add image to naviagtionBar with SWIFT that scales to fit and clips to bounds. You can call this function inside the view controllers viewDidLoad() function.
func setupNavigationBarWithTitleImage(titleImage: UIImage) {
let imageView = UIImageView(image: titleImage)
imageView.contentMode = .ScaleAspectFit
imageView.clipsToBounds = true
navigationItem.titleView = imageView
}

Resources