how to change navigation bar background image manually in specific ViewController? - objective-c

i'm trying to change the image background of my navigationbar when i'm in specific ViewController. My app model :
- appDelegate
- tabbarcontroller
-viewcontroller1
-navigationBarController
-viewcontroller2
-viewcontroller3 (*)
-viewcontroller4
-viewcontroller5
I've already implemented this code in appDelegate :
static NSMutableDictionary *navigationBarImages = NULL;
#implementation UINavigationBar(CustomImage)
+ (void)initImageDictionary
{
if(navigationBarImages==NULL){
navigationBarImages=[[NSMutableDictionary alloc] init];
}
}
- (void)drawRect:(CGRect)rect
{
UIColor *color = [UIColor blackColor];
NSString *imageName=[navigationBarImages objectForKey:[NSValue valueWithNonretainedObject: self]];
if (imageName==nil) {
imageName=#"navbar.png";
}
UIImage *image = [UIImage imageNamed:imageName];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
self.tintColor = color;
}
- (void)setImage:(UIImage*)image
{
[navigationBarImages setObject:image forKey:[NSValue valueWithNonretainedObject: self]];
}
#end
after that, i wrote this code in my viewcontroller2 :
[UINavigationBar initImageDictionary];
it's work, my navigation bar is like i wished, however in my viewcontroller3, i wrote :
UIImage *navBarLandscape = [UIImage imageNamed:#"navbar.png"];
[[[self navigationController] navigationBar] setImage:navBarLandscape];
and it doesn't do the trick, i have an error that i can't undertand :
[UIImage length]: unrecognized selector sent to instance 0x5a58130
2010-11-18 18:02:37.170 finalAudi[1463:307] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIImage length]: unrecognized selector sent to instance 0x5a58130'
Do you have an idea?
regards polo.

In each viewController's viewDidLoad try:
/* make sure that we set the image to be centered */
/* you will ahve to make minor adjustments depending on the dimensions of your image. */
UIImageView *logo = [[UIImageView alloc] initWithFrame:CGRectMake(self.navigationController.navigationBar.frame.size.width/2-75,0,150,
self.navigationController.navigationBar.frame.size.height-1)];
[logo setImage:[UIImage imageNamed:#"myImage.png"]];
[self.navigationController.navigationBar addSubview:logo];
[self.navigationController.navigationBar sendSubviewToBack:logo];
and for viewWillAppear: and viewDidDisappear: try:
/* This will ensure that if you have a different image for each view that the previous viewController's navBar image wont stay. */
-(void)viewWillDisappear:(BOOL)animated {logo.hidden = YES;}
-(void)viewWillAppear:(BOOL)animated {logo.hidden = NO ;}
and to make sure that the image stays centered when rotating:
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if(((interfaceOrientation == UIInterfaceOrientationLandscapeLeft) ||
(interfaceOrientation == UIInterfaceOrientationLandscapeRight))){
[logo setFrame:CGRectMake(self.navigationController.navigationBar.frame.size.width/2-75,0,150,self.navigationController.navigationBar.frame.size.height-1)];
}else if(((interfaceOrientation == UIInterfaceOrientationPortrait) ||
(interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown))){
[logo setFrame:CGRectMake(self.navigationController.navigationBar.frame.size.width/2-80,0,150,self.navigationController.navigationBar.frame.size.height-1)];
}
}

thank's to all of you, i was able to fix my problem with this code in appdelegate:
#implementation UINavigationBar(CustomImage)
+ (void)initAppDelegate
{
if (applicationDelegate==Nil) {
applicationDelegate = (finalAudiAppDelegate *)[[UIApplication sharedApplication] delegate];
}
}
- (void)drawRect:(CGRect)rect
{
UIColor *color = [UIColor blackColor];
[[[applicationDelegate backNavBar] objectAtIndex:[applicationDelegate indexBackNavBar]] drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
self.tintColor = color;
}
#end
i'm using one NSMutableArray to stock my navigationBar's background images and one NSInteger (indexBackNavBar), i'm access to them with UIApplication sharedApplication.
Then in my viewcontroller, i just set indexBackNavBar = 1 in viewWillAppear and indexBackNavBar = 0 in viewWillDisappear. Voila!

If I understand correctly, I would recommend looking at the UINavigationBarDelegate and implementing the code to switch the background of the navigation bar there, instead of spreading it across multiple viewControllers.
The delegate has methods that will get called before pushing and popping new views so it might be better from a design perspective

Related

Adding UISearchBar in UINavigationBar with constraints

All,
I want to add UISearchBar to UINavigationbar, I dont dont want to use UISearchController, Just UISearchbar programmatically and it must work in landscape as well.
I tried it is working well in Portrait well, but in Landscape, i have issues in iPhone X width. Can we use Constraints.
Below is the code
CGFloat width = [UIScreen mainScreen].bounds.size.width;
search = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, width - 2 * 44 - 2 * 15, 44)];
search.delegate = self; // search.tintColor = [UIColor redColor];
search.searchBarStyle = UISearchBarStyleMinimal;
search.placeholder = #"Search";
search.translucent = NO;
search.opaque = NO;
search.showsCancelButton = NO;
[search setBackgroundImage:[[UIImage alloc] init]];
//customize textfield inside UISearchBar
#try {
for (id object in [[[search subviews] firstObject] subviews])
{
if (object && [object isKindOfClass:[UITextField class]])
{
UITextField *textFieldObject = (UITextField *)object;
textFieldObject.backgroundColor = [UIColor whiteColor];
textFieldObject.borderStyle = UITextBorderStyleRoundedRect;
textFieldObject.layer.borderColor = (__bridge CGColorRef _Nullable)([brandingObj getValueForKey:navBarTitleColor]);
textFieldObject.layer.borderWidth = 1.0;
break;
}
}
}
#catch (NSException *exception) {
NSLog(#"Error while customizing UISearchBar");
}
#finally {
}
I don't understand why you want to use UISearchDisplayController, its highly configurable and recommended by apple, working with geometry (CGRecr, CGFrame, etc.) to adjust UIKit objects layout could be a pain, use auto layout avoiding UIKits convenience initializers, to adjust later constraints.
Anyway if you want explicitly do with this way, this should work.
#import "ViewController.h"
#interface ViewController ()<UISearchBarDelegate>
#property UISearchBar *searchbar;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_searchbar = [UISearchBar new];
_searchbar.delegate = self;
_searchbar.searchBarStyle = UISearchBarStyleMinimal;
self.navigationItem.titleView = self.searchbar;
// Do any additional setup after loading the view, typically from a nib.
}
Maybe you should need configure appearance , take a look here
Cheers.

cocoa detect object in mouse clicked

I created a custom object (NSImageView) to display images and I use addSubview: self.view to add
I want to determine if the mouse click in it.
How do I do?
Thank you.
NSImage *Image = [NSImage imageNamed:#"oneimage.jpg"];
NSImageView *ImageView = [[NSImageView alloc] init];
[ImageView setImage:Image];
[self.window addSubview:ImageView];
[ImageView_IconToAdd setAcceptsTouchEvents:YES];
[ImageView_IconToAdd setWantsRestingTouches:YES];
-(void)mouseDragged:(NSEvent *)theEvent {
id clickedObject = [self hitTest:[theEvent locationInWindow]];
if ([clickedObject isKindOfClass:[NSImageView class]]) {
NSLog(#"Clicked an ImageView");
} else if ([clickedObject isKindOfClass:[NSView class]]) {
NSLog(#"Clicked a WebView");
}
}
But error:
No visible #interface for 'WindowImage' declares the selector 'hitTest:'
And can't get Object!

Does it make sense to add ATMHud to tabBarController.view

When i try to add ATMHud to uitableviewcontroller subview it does work but it doesn't disable the scrolling and if the tableview is not on top i can't see the hud view. What i did was added to teh tabBarController.view that works but i want find out if this is a good idea or later on i might have issues with it.
Another question is tabBarController.view frame is that the whole screen or just the bottom part. How come atmhud shows in the middle of the screen?
Thanks in advance!
Yan
============
Found a blog post that shows how to reset self.view and add tableview separately in uitableviewcontroller
UITableViewController and fixed sub views
- (void)viewDidLoad {
[super viewDidLoad];
if (!tableView &&
[self.view isKindOfClass:[UITableView class]]) {
tableView = (UITableView *)self.view;
}
self.view = [[[UIView alloc] initWithFrame:
[UIScreen mainScreen].applicationFrame] autorelease];
self.tableView.frame = self.view.bounds;
self.tableView.contentInset = UIEdgeInsetsMake(44.0, 0.0, 0.0, 0.0);
[self.view addSubview:self.tableView];
UIView *fixedBar = [[UIView alloc] initWithFrame:
CGRectMake(0.0, 0.0, self.view.bounds.size.width, 44.0)];
fixedBar.backgroundColor = [UIColor colorWithRed:
0.0 green:1.0 blue:0.0 alpha:0.7];
[self.view addSubview:fixedBar];
[fixedBar release];
}
After this when add hud to self.view you will be able to disable the tableview on the bottom.
Let me know if this a good way to setup the tableview
The problem with using the tab bar is that the hud is now modal, and the user cannot change the tab.
It sounds like the tableview is not your primary viewm, as it can get "covered up". If its not the primary view, then add the ATMHud to self.view. If the tableView is the same as self.view, then add a new transparent view to it, then add the HUD to that view.
The tabBarController.view is the view that hosts the tabbed views - if you want to see its size (or frame) log it using NSStringFromCGRect(self.tabBarController.frame);
EDIT: I just did a test, the ATMHud DOES block the UI. All I can think of is that you have not inserted it where you need to (at the top of current view's subviews.) I have a demo project where I do this:
hud = [[ATMHud alloc] initWithDelegate:self];
[self.view addSubview:hud.view];
[hud setCaption:#"Howdie"];
[hud setActivity:YES];
[hud show];
[hud hideAfter:5];
A button under the hud is not active - in fact nothing in the view is active (probably the Nav Bar would be live though)
If you want an ARCified and field tested version, you can grab it here
EDIT2: The solution to your problem is below. Note that ATMHud blocks clicks from getting to the table, and the code below stops the scrolling:
- (void)hudWillAppear:(ATMHud *)_hud
{
self.tableView.scrollEnabled = NO;
}
- (void)hudDidDisappear:(ATMHud *)_hud
{
self.tableView.scrollEnabled = YES;
}
Dump the views:
#import <QuartzCore/QuartzCore.h>
#import "UIView+Utilities.h"
#interface UIView (Utilities_Private)
+ (void)appendView:(UIView *)v toStr:(NSMutableString *)str;
#end
#implementation UIView (Utilities_Private)
+ (void)appendView:(UIView *)a toStr:(NSMutableString *)str
{
[str appendFormat:#" %#: frame=%# bounds=%# layerFrame=%# tag=%d userInteraction=%d alpha=%f hidden=%d\n",
NSStringFromClass([a class]),
NSStringFromCGRect(a.frame),
NSStringFromCGRect(a.bounds),
NSStringFromCGRect(a.layer.frame),
a.tag,
a.userInteractionEnabled,
a.alpha,
a.isHidden
];
}
#end
#implementation UIView (Utilities)
+ (void)dumpSuperviews:(UIView *)v msg:(NSString *)msg
{
NSMutableString *str = [NSMutableString stringWithCapacity:256];
while(v) {
[self appendView:v toStr:str];
v = v.superview;
}
[str appendString:#"\n"];
NSLog(#"%#:\n%#", msg, str);
}
+ (void)dumpSubviews:(UIView *)v msg:(NSString *)msg
{
NSMutableString *str = [NSMutableString stringWithCapacity:256];
if(v) [self appendView:v toStr:str];
for(UIView *a in v.subviews) {
[self appendView:a toStr:str];
}
[str appendString:#"\n"];
NSLog(#"%#:\n%#", msg, str);
}
#end

Add UIImageView as a subview to UIKeyboard - userInteractionEnabled?

I have a little problem with adding a subview to my UIKeyboard. I can successfully locate my keyboard and add an uiimageview to it, but unfortunately the button under the image view still can be touched. I just wanted to make it a color overlay, which would hide the unneeded keys and also make them untouchable :)
Here is my code, what am I doing wrong? The UIImageView displays correctly, but the buttons still can be tapped... :(
- (UIView *)findKeyboard {
// Locate non-UIWindow.
UIWindow *keyboardWindow = nil;
for (UIWindow *testWindow in [[UIApplication sharedApplication] windows]) {
if (![[testWindow class] isEqual:[UIWindow class]]) {
keyboardWindow = testWindow;
break;
}
}
// Locate UIKeyboard.
UIView *foundKeyboard = nil;
for (UIView __strong *possibleKeyboard in [keyboardWindow subviews]) {
// iOS 4 sticks the UIKeyboard inside a UIPeripheralHostView.
if ([[possibleKeyboard description] hasPrefix:#"<UIPeripheralHostView"]) {
possibleKeyboard = [[possibleKeyboard subviews] objectAtIndex:0];
}
if ([[possibleKeyboard description] hasPrefix:#"<UIKeyboard"]) {
foundKeyboard = possibleKeyboard;
break;
}
}
return foundKeyboard;
}
- (void)keyboardWillShow:(NSNotification *)note {
UIImageView *overlayView;
UIView *keyboardView = [self findKeyboard];
UIImage *img = [UIImage imageNamed:#"keyboardOverlay.png"];
overlayView = [[UIImageView alloc] initWithImage:img];
[overlayView setUserInteractionEnabled:NO];
UIView *newView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, overlayView.frame.size.width, overlayView.frame.size.height)];
newView.userInteractionEnabled = NO;
newView.multipleTouchEnabled = NO;
[newView addSubview:overlayView];
[keyboardView insertSubview:newView atIndex:40];
}
User interaction being disabled means that touches are passed straight through. Enable it, but don't have any gesture recognisers or actions, and it will swallow all touches.

Couldn't UIToolBar be transparent?

I try the following code, but it doesn't work.
[helloToolbar setBackgroundColor:[UIColor clearColor]];
To make a completely transparent toolbar, use the method described here. In a nutshell, create a new TransparentToolbar class that inherits from UIToolbar, and use that in place of UIToolbar.
TransarentToolbar.h
#interface TransparentToolbar : UIToolbar
#end
TransarentToolbar.m
#implementation TransparentToolbar
// Override draw rect to avoid
// background coloring
- (void)drawRect:(CGRect)rect {
// do nothing in here
}
// Set properties to make background
// translucent.
- (void) applyTranslucentBackground
{
self.backgroundColor = [UIColor clearColor];
self.opaque = NO;
self.translucent = YES;
}
// Override init.
- (id) init
{
self = [super init];
[self applyTranslucentBackground];
return self;
}
// Override initWithFrame.
- (id) initWithFrame:(CGRect) frame
{
self = [super initWithFrame:frame];
[self applyTranslucentBackground];
return self;
}
#end
(code from the blog post linked above)
In iOS 5, simply call setBackgroundImage and pass a transparent image.
Here's how I do it (I dynamically generate transparent image):
CGRect rect = CGRectMake(0, 0, 1, 1);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
CGContextFillRect(context, rect);
UIImage *transparentImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[toolbar setBackgroundImage:transparentImage forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
The best you can do is using
[helloToolbar setBarStyle:UIBarStyleBlack];
[helloToolbar setTranslucent:YES];
This will get you a black but translucent toolbar.
Transparent (iOS 5.0):
[toolbar setBackgroundImage:[[UIImage alloc] init] forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
Translucent:
[toolbar setBarStyle:UIBarStyleBlack];
[toolbar setTranslucent:YES];
A cumulative solution for all devices, from oldest iOS 3.0 (iPhone 1) to newest iOS 6.1 (iPad mini).
#implementation UIToolbar (Extension)
- (void)drawRect:(CGRect)rect
{
if (CGColorGetAlpha(self.backgroundColor.CGColor) > 0.f)
{
[super drawRect:rect];
}
}
- (void)setTransparent
{
//iOS3+
self.backgroundColor = [UIColor clearColor];
//iOS5+
if ([self respondsToSelector:#selector(setBackgroundImage:forToolbarPosition:barMetrics:)])
{
[self setBackgroundImage:[[UIImage new] autorelease] forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
}
//iOS6+
if ([self respondsToSelector:#selector(setShadowImage:forToolbarPosition:)])
{
[self setShadowImage:[[UIImage new] autorelease] forToolbarPosition:UIToolbarPositionAny];
}
}
#end
When you want a transparent toolbar, call setTransparent on it.
When you want a non-transparent toolbar, set a backgroundColor of your choice or add an imageView by yourself.
Another solution would be to define a category for UIToolbar:
#implementation UIToolbar(Transparent)
-(void)drawRect:(CGRect)rect {
// do nothing in here
}
#end
In the IB set the toolbar as Black Translucent and non opaque.
We've just noticed that overriding drawRect doesn't work anymore with iOS 4.3. It's not called anymore (edit: seems to be only in Simulator). Instead drawLayer:inContext: is called.
A great solution was posted here
Now you can set each UIToolbar object transparent, by setting its tintColor to [UIColor clearColor] :)
With iOS 5 the following works:
UIToolbar *bar = [[UIToolbar alloc] initWithFrame:CGRectZero];
if (bar.subviews.count > 0)
[[[bar subviews] objectAtIndex:0] removeFromSuperview];
This is because the background is now a subview. This code is safe even with new iterations of iOS, but it may stop working. This is not private API usage, your app is safe to submit to the store.
Make sure you remove the backgroundView before adding any UIBarButtonItems to the bar. Or my code will not work.
I just tested the following with iOS 4.3 on simulator and phone, seems to work fine. Subclass UIToolbar, provide one method:
- (void)drawRect:(CGRect)rect
{
[[UIColor colorWithWhite:0 alpha:0.6f] set]; // or clearColor etc
CGContextFillRect(UIGraphicsGetCurrentContext(), rect);
}
toolbar.barStyle = UIBarStyleBlackTranslucent;
This works in iOS5.1 with pretty minimal effort. I am matching up the size, as only the background will have the same frame size as the toolbar itself. You could use other criteria, of course.
Enjoy.
Create a subclass of UIToolbar as follows:
.h:
#import <UIKit/UIKit.h>
#interface UIClearToolbar : UIToolbar
#end
.m:
#import "UIClearToolbar.h"
#implementation UIClearToolbar
- (void)layoutSubviews {
// super has already laid out the subviews before this call is made.
[self.subviews enumerateObjectsUsingBlock:^(UIView* obj, NSUInteger idx, BOOL *stop) {
if (CGSizeEqualToSize(self.frame.size, obj.frame.size) ||
self.frame.size.width <= obj.frame.size.width) { // on device, the background is BIGGER than the toolbar.) {
[obj removeFromSuperview];
*stop = YES;
}
}];
}
#end
Thanks #morais for your solution - here's the code translated to MonoTouch:
public class TransparentToolbar : UIToolbar
{
public TransparentToolbar()
{
init();
}
public TransparentToolbar(RectangleF frame) : base(frame)
{
init();
}
void init()
{
BackgroundColor=UIColor.Clear;
Opaque=false;
Translucent=true;
}
public override void Draw(RectangleF rect)
{
}
}