There is a lot of questions about how to replace the default back button with a custom back button, but none that I know of about how to replace a custom back button with the default.
I have a web view that when [self.webView canGoBack] == YES, a custom back button appears. But after you go back all the way, that custom back button is still there, rather than the default. Is there something I can do to replace my custom back button with the default when [self.webView canGoBack] == NO?
Here is my relevant code:
#interface MerchViewController () <UIWebViewDelegate>
#property UIWebView *webView;
#end
#implementation MerchViewController
- (instancetype)init
{
self = [super init];
if (self) {
self.navigationItem.title = #"Merchandise";
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
UIWebView *webView = [[UIWebView alloc] init];
webView.scalesPageToFit = YES;
self.view = webView;
self.webView = webView;
webView.delegate = self;
[self setURL];
}
- (void)updateBackButton {
if ([self.webView canGoBack]) {
{
[self.navigationItem setHidesBackButton:YES animated:NO];
//UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"backTickets"] style:UIBarButtonItemStylePlain target:self action:#selector(backWasClicked:)];
UIBarButtonItem *backItem = [[UIBarButtonItem alloc] backButtonWith:#"Back" tintColor:[UIColor orangeColor] target:self andAction:#selector(backWasClicked:)];
backItem.tintColor = [UIColor orangeColor];
[self.navigationItem setLeftBarButtonItem:backItem animated:NO];
}
}
else {
/*
[self.navigationItem setHidesBackButton:YES animated:NO];
//UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"backTickets"] style:UIBarButtonItemStylePlain target:self action:#selector(backWasClicked:)];
UIBarButtonItem *backItem = [[UIBarButtonItem alloc] backButtonWith:#"Fan Zone" tintColor:[UIColor orangeColor] target:self andAction:#selector(openMenu:)];
backItem.tintColor = [UIColor orangeColor];
[self.navigationItem setLeftBarButtonItem:backItem animated:NO];
*/
}
}
- (void)webViewDidStartLoad:(UIWebView *)webView {
[self updateBackButton];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[self updateBackButton];
[_spinner stopAnimating];
}
- (void)backWasClicked:(id)sender {
if ([self.webView canGoBack]) {
[self.webView goBack];
}
}
- (void)setURL
{
NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:#"https://www.lawlorscustom.com/omaha-lancers-hockey"]];
NSLog(#"loadRequest: %#", req);
[(UIWebView *)self.view loadRequest:req];
}
#end
The "else" portion in "updateBackButton" is commented out because if I don't comment it out, when the view first loads there are two back buttons overlapping.
After struggling for a while, the answer was to do:
[self.navigationItem setHidesBackButton:NO animated:NO];
self.navigationItem.leftBarButtonItem = self.navigationItem.backBarButtonItem;
Related
In my app, I use the old GKImage library for adding pictures and being able to custom crop them easily. This works pretty well, except when it comes to iPad. On iPhone, everything works great. The main issue is this:
When I use an iPad, none of the barButtonItems are clickable.
Here is my code for this view:
- (void)_actionCancel{
[self.navigationController popViewControllerAnimated:YES];
}
- (void)_actionUse{
NSLog(#"PRESSED");
_croppedImage = [self.imageCropView croppedImage];
[self.delegate imageCropController:self didFinishWithCroppedImage:_croppedImage];
}
- (void)_setupNavigationBar{
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self
action:#selector(_actionCancel)];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Use"
style:UIBarButtonItemStylePlain
target:self
action:#selector(_actionUse)];
}
- (void)_setupCropView{
self.imageCropView = [[GKImageCropView alloc] initWithFrame:self.view.bounds];
[self.imageCropView setImageToCrop:sourceImage];
[self.imageCropView setResizableCropArea:self.resizeableCropArea];
[self.imageCropView setCropSize:cropSize];
[self.view addSubview:self.imageCropView];
}
#pragma mark -
#pragma Super Class Methods
- (id)init{
self = [super init];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad{
[super viewDidLoad];
self.title = #"Choose Photo";
[self _setupNavigationBar];
[self _setupCropView];
[self.navigationController setNavigationBarHidden:NO];
}
- (void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
self.imageCropView.frame = self.view.bounds;
}
The code used to present this controller is:
self.imagePicker = [[GKImagePicker alloc] init];
self.imagePicker.cropSize = CGSizeMake(280, 280);
self.imagePicker.delegate = self;
self.imagePicker.imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentViewController:self.imagePicker.imagePickerController animated:YES completion:nil];
Is it an issue with presenting the view controller?
Have tried [[self jotNotes] resignFirstResponder]; , have tried [self endEditing:YES];
So I have my NoteViewController, which inherits UIViewController, and tries to implement the delegate like so
#interface NOTEController : UIViewController <UITextViewDelegate>
#end
#implementation NOTEController
-(id)init {
self = [super init];
if (self) {
// self.delegate = self; //doesnt let me set this, so i assume i do not do that here
NOTEControllerView * mainView = [[NOTEControllerView alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.view = mainView; //just a plain custom uiview subclass its boring and not special
}
return self;
}
#end
and then in the mainView, i have a bunch of sub-views that are basically a square with a UITextView inside.
the squares class is like this, and they're the ones im trying to dismiss the keyboard from, heres where i set the delegate, the dismissKB method, and the UITextView code. Currently, it will log my keyboard method when pressing the done button, but the keyboard is still present. Would really appreciate if anyone could help me understand why
#interface NOTESubview : UIView <UITextFieldDelegate>
#property (nonatomic, weak) id<UITextFieldDelegate> delegate;
-(UITextView *)jotNotes;
#end
#implementation NOTESubview
-(id)initWithFrame:(CGRect)arg1 {
self = [super initWithFrame:arg1];
if (self) {
self.delegate = self;
[self addSubview:[self jotNotes]];
}
return self;
}
-(UITextView *)jotNotes {
UITextView * jotNotes = [[UITextView alloc] initWithFrame:CGRectMake(0, self.frame.size.height/5.7, self.frame.size.width, self.frame.size.height - self.frame.size.height/5.7)];
UIToolbar* keyboardTextViewBar = [[UIToolbar alloc] init];
keyboardTextViewBar.barStyle = UIBarStyleDefault;
[keyboardTextViewBar sizeToFit];
UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
UIBarButtonItem* doneButton = [[UIBarButtonItem alloc] initWithTitle:#"Done"
style:UIBarButtonItemStylePlain target:self
action:#selector(dismissKB:)];
[keyboardTextViewBar setItems:[NSArray arrayWithObjects:flexSpace, doneButton, nil]];
jotNotes.inputAccessoryView = keyboardTextViewBar;
jotNotes.delegate = self.delegate;
return jotNotes;
}
-(void)dismissKB:(UIBarButtonItem *)sender {
//this will log, so im not sure why it wont resign the board no matter what i try
NSLog(#"keyboard attempted to dismiss by %#", sender);
[[self jotNotes] resignFirstResponder];
}
I suspect that when the dismissKB method is called, its actually not the one who is currently the first responder.
However, there's a trick where you can just "dismiss the keyboard" from anywhere in your app. You might wanna give it a try:
[[[[UIApplication sharedApplication] delegate] window] endEditing:YES];
Add the following line where you are trying to dismiss the keyboard:
[self endEditing:YES];
So I have a navigation bar that has a "Back" button on it and a UISearchBar to the right of this:
![enter image description here][1]
When the UISearchBar opens/shows, the cancel button hides/shows:
![enter image description here][2]
What I want is when the UISearchBar opens, I want it to basically "cover" the back button. When it closes, I want it so "uncover" the back button. Here is my code so far:
#import "SearchViewController.h"
#interface SearchViewController ()
#end
- (void)viewDidLoad {
[super viewDidLoad];
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])
self.edgesForExtendedLayout = UIRectEdgeNone;
UISearchBar *searchBar = [UISearchBar new];
searchBar.showsCancelButton = NO;
[searchBar sizeToFit];
searchBar.delegate = self;
self.navigationItem.titleView = searchBar;
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:nil style:UIBarButtonItemStylePlain target:self action:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
[searchBar setShowsCancelButton:YES animated:YES];
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
[searchBar setShowsCancelButton:NO animated:YES];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
[searchBar resignFirstResponder];
[searchBar setShowsCancelButton:NO animated:YES];
}
#end
What I've tried was to do: self.navigationItem.hidesBackButton = NO/YES; in the searchBarTextDidBeginEditing/searchBarTextDidEndEditing but this leaves the spot where the back button was empty:
![enter image description here][3]
Is there a way I can have the search bar extend over the back button? Thanks!
Try to do it by
self.navigationItem.leftBarButtonItem=nil;
self.navigationItem.hidesBackButton=YES;
or
self.navigationItem.backBarButtonItem=nil;
Updated code :
#interface SearchViewController ()
{
UIBarButtonItem *backButtonItem;
UIBarButtonItem *negativeSpacer;
}
#end
#implementation SearchViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
UISearchBar *searchBar = [UISearchBar new];
searchBar.showsCancelButton = NO;
[searchBar sizeToFit];
searchBar.delegate = self;
self.navigationItem.titleView = searchBar;
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:nil style:UIBarButtonItemStylePlain target:self action:nil];
self.navigationItem.backBarButtonItem=nil;
self.navigationItem.hidesBackButton=YES;
UIButton *backButton = [[UIButton alloc] initWithFrame: CGRectMake(0, 0, 70.0f, 21.0f)];
UIImage *backImage = [UIImage imageNamed:#"Back.png"];
[backButton setImage:backImage forState:UIControlStateNormal];
[backButton setTitleEdgeInsets:UIEdgeInsetsMake(10.0, 10.0, 10.0, 0.0)];
[backButton setTitle:#"Back" forState:UIControlStateNormal];
[backButton addTarget:self action:#selector(backButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
negativeSpacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
[negativeSpacer setWidth:-15];
self.navigationItem.leftBarButtonItems = [NSArray arrayWithObjects:negativeSpacer,backButtonItem,nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
[searchBar setShowsCancelButton:YES animated:YES];
self.navigationItem.leftBarButtonItems = nil;
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
[searchBar setShowsCancelButton:NO animated:YES];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
[searchBar resignFirstResponder];
[searchBar setShowsCancelButton:NO animated:YES];
self.navigationItem.leftBarButtonItems = [NSArray arrayWithObjects:negativeSpacer,backButtonItem,nil];
}
- (IBAction)backButtonPressed:(id)sender{
[self.navigationController popViewControllerAnimated:YES];
}
I have a small problem.
Basically, I have a UIWebView that is located under the navigation bar, so I need to scroll down to view the contents, and it scrolls up at the end. How Do I make the UIWebView appear right below the navigation bar?
#import "RootViewController.h"
#implementation RootViewController
- (void)viewDidLoad {
[super viewDidLoad];
webview=[[UIWebView alloc]initWithFrame:self.view.bounds];
NSString *url=#"http://localhost/";
NSURL *nsurl=[NSURL URLWithString:url];
NSURLRequest *nsrequest=[NSURLRequest requestWithURL:nsurl];
[webview loadRequest:nsrequest];
[self.view addSubview:webview];
navBar = [[UINavigationBar alloc] init];
navBar.frame = CGRectMake(0, 0, self.view.frame.size.width, 44);
UINavigationItem*navItem = [[[UINavigationItem alloc] initWithTitle:#"iPaint"] autorelease];
UIBarButtonItem*leftButton = [[[UIBarButtonItem alloc] initWithTitle:#"Left" style:UIBarButtonItemStylePlain target:self action:#selector(rightButtonPressed)] autorelease];
navItem.leftBarButtonItem = leftButton;
UIBarButtonItem*rightButton = [[[UIBarButtonItem alloc] initWithTitle:#"Right" style:UIBarButtonItemStylePlain target:self action:#selector(rightButtonPressed)] autorelease];
navItem.rightBarButtonItem = rightButton;
navBar.barStyle = UIBarStyleDefault;
navBar.items = [NSArray arrayWithObject:navItem];
[self.view addSubview:navBar];
}
-(void)leftButtonPressed{
//Code Here
}
-(void)rightButtonPressed{
//Code Here
}
#end
main.mm Code:
int main(int argc, char **argv) {
NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init];
int ret = UIApplicationMain(argc, argv, #"comvlad1kwebApplication", #"comvlad1kwebApplication");
[p drain];
return ret;
}
// vim:ft=objc
I am using Theos, so I don't have an Xcode, therefore I need to manually do it.
Thank you.
EDIT: Here is a link to a screenshot: http://i.imgur.com/aQ4yuyp.png
The main issue is that you are creating a UINavigationBar manually. What you want is to be using a UINavigationController, which is a view controller that manages a stack of other view controllers and navigation between them. In your application delegate, you probably have code that looks something like this:
// Assuming that your UIApplication Delegate has a _viewController ivar which is properly memory-managed.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
_viewController = [[RootViewController alloc] init];
[_window addSubview:_viewController.view];
[_window makeKeyAndVisible];
}
That snippet of code creates an instance of RootViewController and sets it to be the main view controller in the application. What you want instead is to put a RootViewController inside a UINavigationController, like this:
// Assuming that your UIApplication Delegate has a _viewController ivar which is properly memory-managed.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
_viewController = [[RootViewController alloc] init];
UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:_viewController] autorelease];
[_window addSubview:navController.view];
[_window makeKeyAndVisible];
}
Once you've created a UINavigationController subclass, you should remove the UINavigationBar from your RootViewController, as it is no longer necessary.
You shouldn't set frame of views, based on controller's view's frame in viewDidLoad method. Set frame of webView and NavigationBar on viewWillAppear.
Also, probably you would want to use UINAvigationController, instead of adding UINavigationBar manually
#import "RootViewController.h"
#implementation RootViewController
- (void)viewDidLoad {
[super viewDidLoad];
webview=[[UIWebView alloc]initWithFrame:CGrectZero];
NSString *url=#"http://localhost/";
NSURL *nsurl=[NSURL URLWithString:url];
NSURLRequest *nsrequest=[NSURLRequest requestWithURL:nsurl];
[webview loadRequest:nsrequest];
[self.view addSubview:webview];
navBar = [[UINavigationBar alloc] init];
UINavigationItem*navItem = [[[UINavigationItem alloc] initWithTitle:#"iPaint"] autorelease];
UIBarButtonItem*leftButton = [[[UIBarButtonItem alloc] initWithTitle:#"Left" style:UIBarButtonItemStylePlain target:self action:#selector(rightButtonPressed)] autorelease];
navItem.leftBarButtonItem = leftButton;
UIBarButtonItem*rightButton = [[[UIBarButtonItem alloc] initWithTitle:#"Right" style:UIBarButtonItemStylePlain target:self action:#selector(rightButtonPressed)] autorelease];
navItem.rightBarButtonItem = rightButton;
navBar.barStyle = UIBarStyleDefault;
navBar.items = [NSArray arrayWithObject:navItem];
[self.view addSubview:navBar];
}
- (void)viewWillAppear:(BOOL)animated{
navBar.frame = CGRectMake(0, 0, self.view.frame.size.width, 44);
CGRect r = self.view.bounds;
r.origin.y = CGRectGetMaxY(navBar.frame);
r.size.width = r.size.width - CGRectGetMaxY(navBar.frame);
[webView setFrame:r];
}
-(void)leftButtonPressed{
//Code Here
}
-(void)rightButtonPressed{
//Code Here
}
#end
I have some weird problem adding UISegmentedControl in toolbar on iPad. I have created a UINavigationController with the root controller which has the following methods:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
UINavigationController *navigationController = [self navigationController];
navigationController.toolbar.barStyle = UIBarStyleBlackOpaque;
navigationController.toolbarHidden = NO;
}
- (NSArray *)toolbarItems
{
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:NULL];
return [NSArray arrayWithObjects:[self segmentedControlItem], flexibleSpace, nil];
}
- (UISegmentedControl *)segmentedControl
{
if (_segmentedControl) {
return _segmentedControl;
}
NSArray *items = [NSArray arrayWithObjects:#"Segment 1", #"Segment 2", nil];
_segmentedControl = [[UISegmentedControl alloc] initWithItems:items];
_segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
return _segmentedControl;
}
- (UIBarButtonItem *)segmentedControlItem
{
UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc] initWithCustomView:self.segmentedControl];
buttonItem.style = UIBarButtonItemStyleBordered;
return buttonItem;
}
But after the controller appears the segmentedControl is not visible on toolbar. How to fix it? I am already checked that the segmentedControl exists in toolbar items, it has size, it is not hidden, but nevertheless I cannot see it.
(lldb) po [[[[[self navigationController] toolbar] items] objectAtIndex:0] customView]
(id) $3 = 0x08e39a10 <UISegmentedControl: 0x8e39a10; frame = (7 8; 300 30); opaque = NO; layer = <CALayer: 0x8e63230>>
I have a workaround. It seems is not safe to overwrite the - (NSArray *)toolbarItems if you want to add UISegmentedControl in the toolbar. It is better to add some method to configure the toolbar somewhere after the controller did load.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self configureToolbar];
}
- (void)configureToolbar
{
UINavigationController *navigationController = [self navigationController];
navigationController.toolbar.barStyle = UIBarStyleBlackOpaque;
navigationController.toolbarHidden = NO;
// Add toolbar items here
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:NULL];
self.toolbarItems = [NSArray arrayWithObjects:[self segmentedControlItem], flexibleSpace, nil];
}
This approach allows you to get the result