Trouble adding item to UIToolbar - uisplitviewcontroller

I'm working on an app with a split view controller. The master is a subclass of a tab bar controller and is the split view controller delegate. That part seems to work fine, and it does push the correct information to the detail side -- except for the bar button item that the split view controller generates.
I have a UIToolbar that was dragged out in Xcode onto the only detail view controller in the project. I set an outlet to the public API in Xcode using ctrl-drag.
Also declared in the public API is a UIBarButtonItem *splitViewBarButtonItem, declared weak, nonatomic.
Here is the setter for that item:
-(void)setSplitViewBarButtonItem:(UIBarButtonItem *)barButtonItem
{
NSLog(#"%# setSplitViewBarButtonItem to %# (%#)",self,barButtonItem,barButtonItem.title);
//UIToolbar *toolbar = [self toolbar];
UIToolbar *toolbar = self.toolbar;
NSLog(#"toolbar[0] before adding the barButtonItem is %#",toolbar.items[0]);
NSMutableArray *toolbarItems = [toolbar.items mutableCopy];
if (_splitViewBarButtonItem)
{
NSLog(#"Removing _splitViewBarButtonItem from toolbarItems");
[toolbarItems removeObject:_splitViewBarButtonItem];
NSLog(#"toolbarItems[0] is %#",toolbarItems[0]);
}
if (barButtonItem)
{
NSLog(#"#####");
NSLog(#"Now adding %# to toolbarItems",[barButtonItem description]);
[toolbarItems insertObject:barButtonItem atIndex:0];
NSLog(#"toolbarItems[0] is %#",[toolbarItems[0] description]);
NSLog(#"#####");
}
self.toolbar.items = [toolbarItems copy];
NSLog(#"self.toolbar.items[0] is %#",self.toolbar.items[0]);
_splitViewBarButtonItem = barButtonItem;
}
The first time through, it behaves as expected:
2013-04-01 10:33:46.270 SPoT[10389:907] <IViewController: 0x1e066430> setSplitViewBarButtonItem to <UIBarButtonItem: 0x1cd65490> (Text appearing on the button)
2013-04-01 10:33:46.272 SPoT[10389:907] toolbar[0] before adding the barButtonItem is <UIBarButtonItem: 0x1cd65400>
2013-04-01 10:33:46.275 SPoT[10389:907] #####
2013-04-01 10:33:46.277 SPoT[10389:907] Now adding <UIBarButtonItem: 0x1cd65490> to toolbarItems
2013-04-01 10:33:46.278 SPoT[10389:907] toolbarItems[0] is <UIBarButtonItem: 0x1cd65490>
2013-04-01 10:33:46.280 SPoT[10389:907] #####
2013-04-01 10:33:46.288 SPoT[10389:907] self.toolbar.items[0] is <UIBarButtonItem: 0x1cd65490>
However, if I use the button to activate the master, thus making the button disappear and use the master to refresh the detail screen with new data, the transfer of the button is not taking. I've traced the problem to this method, where the button is shown to be available but is not updating. Here's the debugger output from the second run:
2013-04-01 10:33:53.491 SPoT[10389:907] <IViewController: 0x1e09fad0> setSplitViewBarButtonItem to <UIBarButtonItem: 0x1cd65490> (Text appearing on the button)
2013-04-01 10:33:53.492 SPoT[10389:907] toolbar[0] before adding the barButtonItem is (null)
2013-04-01 10:33:53.493 SPoT[10389:907] #####
2013-04-01 10:33:53.494 SPoT[10389:907] Now adding <UIBarButtonItem: 0x1cd65490> to toolbarItems
2013-04-01 10:33:53.495 SPoT[10389:907] toolbarItems[0] is (null)
2013-04-01 10:33:53.496 SPoT[10389:907] #####
2013-04-01 10:33:53.497 SPoT[10389:907] self.toolbar.items[0] is (null)
Note that the debugger trace states, "Now adding ", so the item is available. So why is it not being added?
Edit: Now I'm thinking that since "toolbar[0] before adding the barButtonItem is (null)" that the segue that generated the object id of the new detail controller hasn't fully created that object, specifically, the toolbar property doesn't exist yet. I guess I'll have to figure out how to add the bar button item later in the process.

Not sure this is the best solution, but I figured the reason the bar button item wasn't being added to the title was that the title hadn't yet been added to the new detail VC object provided by the segue. I solved this problem by adding the following line to the detail VC's viewDidLayoutSubviews method:
self.splitViewBarButtonItem = self.splitViewBarButtonItem;
This calls the setter again, but this time after the titlebar exists.

Related

iOS 13 and UiSplitViewController when presenting in Portrait missing DisplayMode Button

I have the same issue as described here
UISplitViewController portrait mode missing UIBarButtonItem
my SplitView contains two NavigationControllers which each contains TableViewController
the Detail tableview controller is the split views delegate there all generated in code
and have a delegate method splitViewController:willChangeToDisplayMode:
and splitViewController:willHideViewController:withBarButtonItem:forPopoverController:
for good measure
I have even tried to add the button my self if it is not there in splitViewController:willChangeToDisplayMode:
still no luck
any suggestions ?
Regards Christian
I Coded around the issue bu putting come code splitViewController:willChangeToDisplayMode: if the display mode is PrimaryHidden and the detail view controller don't contain a the splits view displauModeButtonItem in topmost navigationItem if the detail view controllers leftBarButtonsItems the I just manually add it
This is basically what #canderse said but I am showing the code. There is also a trick if you want your button to have a title. In your DetailViewController override the following method:
-(void)splitViewController:(UISplitViewController *)svc willChangeToDisplayMode:(UISplitViewControllerDisplayMode)displayMode{
//fix for missing navigation button
if(displayMode == UISplitViewControllerDisplayModePrimaryHidden){
self.navigationItem.leftItemsSupplementBackButton = true;
UIBarButtonItem *item=[svc displayModeButtonItem];
[self.navigationItem setLeftBarButtonItem:item animated:YES];
}}
For the button to have title, set your master view controller's title in awakeFromNib:
self.title = NSLocalizedString(#"Title", #"Title");
If you try to set the title in willChangeToDisplayMode, it won't work.

How do I set up a Tab Bar Controller within an existing Navigation Controller?

I'm pretty new to iOS. I'm building an app and am running into an issue. I have a navigation controller with a table view controller atop its stack. When I select a row in that table view controller, what I'd like to see is a collection view with the following:
The nav bar with the name that appears on the selected cell as the navigation item title.
A collection view as the main interface
a tab bar with the collection view, and an imagePickerController
Here's what my code looks like:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NewTabBarController *tbc = [[NewTabBarController alloc] init];
UIImagePickerController *takeAPicture = [[UIImagePickerController alloc] init];
UITabBarItem *tabItem = [takeAPicture tabBarItem];
[tabItem setImage:[UIImage imageWithContentsOfFile:#"CameraIcon.jpg"]];
[tabItem setTitle:#"Take a photo!"];
UICollectionViewFlowLayout *photoFlow = [[UICollectionViewFlowLayout alloc] init];
PhotoCollectionViewController *photoHub = [[PhotoCollectionViewController alloc] initWithCollectionViewLayout:photoFlow];
[tbc setViewControllers:[NSArray arrayWithObjects:photoHub, takeAPicture, nil]];
NSArray *items = [[items accessor] allItems];
Item *item = [items objectAtIndex:[indexPath row]];
[photoHub setItem:item];
[photoHub useLayoutToLayoutNavigationTransitions];
[[self navigationController] pushViewController:tbc animated:YES];
}
Then in my PhotoCollectionViewController implementation I have:
#syntesize item;
- (void)viewDidLoad {
[super viewDidLoad];
UINavigationItem *itemHeader = [self navigationItem];
[itemHeader setTitle:[item itemName]];
UITabBarItem *tabItem = [self tabBarItem];
[tabItem setImage:[UIImage imageWithContentsOfFile:#"itemImage.jpg"]];
[tabItem setTitle:[NSString stringWithFormat:#"Photos of %#", [item itemName]]];
}
My problem is that when I select the cell, The collection view loads, and I can see the cells I have set up in the collection view, but the nav bar item has no title, and the tab bar item has "Photos of (null)" and no image. The "Take a photo!" text appears, but the image does not.
Do you guys have any idea how I can restructure this to make everything flow correctly. I must be doing something wrong in the way I'm utilizing tab and nav controllers.I don't want there to be any tabs until this stage in the app, which is 3 or 4 VCs in already. Should I be using a tab bar controller from the App Delegate onward?
The problem here is that you are pushing tab bar controller onto a navigation controller stack. The view controllers of a tab bar will have a navigation item, but their navigation items aren't shown when the view controller is on screen. Instead, the tab bar controller's navigation item is on screen.
You could use self.tabBarController.navigationItem, but then each view controller will have to modify the navigation item every time it's brought on/off screen, which is really messy.
If you're going to use a UITabBarController, I would recommend either presenting it modally, or having it be the root view controller on your UIWindow. It's tough to get it working right as a view controller in a navigation controller's view controller stack.
Your tab bar item not showing its name is a separate issue. It's because viewDidLoad is getting called before you set your item instance, specifically it's getting called when you call [tbc setViewControllers:[NSArray arrayWithObjects:photoHub, takeAPicture, nil]];
You can confirm this by breakpointing in view did load, where you'll see that item is nil. If you haven't already, you should overload your setItem: method in PhotoCollectionViewController, and have that method also update your UI.

how to present UITabBarController that used UINavigationController from ViewController ouside

i have UiViewController as a LoginPage if it passed then it should show UITabBarController firstTab's ; the first tab inside UINavigationController as RootView.
how can i present firstTab from Login Page; i tried the following but error show :
Code IOS 7 StoryBoard
-(void)successLogin{
HomeTableViewController *vc =[self.storyboard instantiateViewControllerWithIdentifier:#"RootViewInControllerInFirstTabBar"];
[self presentViewController: vc animated:NO completion:nil];
}
i assume that the view that should appear after the login page should have tabs- with the first tab selected. the frst tab should have the home tableVC, which is also the root controller of a navigation controller, displayed.
[Updated]
According to my understanding of the doc, you'll first create the login page.
On successful login, the screen will navigate to a new controller derived from UITabbarViewController. Navigation to the UITabbarViewController depends on your choice, or you can even replace the view on the login screen(entirely your choice). Now on the derivedViewController you will set the viewcontrollers that you want to display on each tab using the following method of the UITabbarViewController.
- (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated
On the first item of the tab bar, you will create a new controller(for profile) which will be the rootviewController of the UINavigationController.

selenium webdriver element inside iframe is clickable but moveToElement results in MoveTargetOutOfBoundsError

I have a page with an iframe. Inside the iframe is a table. When the user moves the mouse over this table, some elements appear. I'd like to click one of those elements.
I think some of my first steps should be to select the iframe, and then moveToElement(table). But this results in a MoveTargetOutOfBoundsError.
The strange thing is that I'm able to select the iframe and click on the table. The click doesn't complain about the element's x,y coordinates but moveToElement complains. Why? (Unfortunately clicking on the table performs an action which causes those buttons I want to disappear so this is not an option.)
And how can I accomplish what I want (select iframe, hover over table, wait for buttons to appear, click one of the buttons)?
version info:
Build info: version: '2.28.0', revision: '18309', time: '2012-12-11 15:53:30'
System info: os.name: 'Windows 7', os.arch: 'amd64', os.version: '6.1', java.version: '1.6.0_37'
Here's the java code that succeeds in clicking the table:
driver.switchTo().defaultContent();
driver.switchTo().frame("frameId");
WebElement e = driver.findElement(By.id("foo"));
e.click();
Here's the java code that complains about the location of the table:
driver.switchTo().defaultContent();
driver.switchTo().frame("frameId");
WebElement e = driver.findElement(By.id("foo"));
Actions builder = new Actions(driver);
builder.moveToElement(e).build().perform(); // error happens in moveToElement()
I think you have to scroll into view:
if (element instanceof Locatable) {
Locatable remoteElement = (Locatable) inputElement;
remoteElement.getLocationOnScreenOnceScrolledIntoView();
}
If you want to hover on an element, you have to extend the above a bit:
if (element instanceof Locatable) {
Locatable hoverItem = (Locatable) element;
hoverItem.getLocationOnScreenOnceScrolledIntoView();
Mouse mouse = ((HasInputDevices) webDriver).getMouse();
mouse.mouseMove(hoverItem.getCoordinates());
}

How to pass an NSString from modal view to parent view

I have a parent view and a modal view with a text box. What I am trying to do is pass whatever is entered into the text box from the modal view and then pass it to a label in the parent view which updates the label to what was entered. I hope that made any sense.
I have been pulling my hair out for a couple of weeks trying to figure this out with no luck. I found many examples and tutorials about segues and passing between views that are being pushed but nothing about modal views and passing back to the parent view.
I have been trying to understand this and need a good example. I kind of understand the prepare for segue concept but for some reason, I just can't figure this one out. Any help on this would be much appreciated and you would be my hero for life lol.
In my project that uses segues, here's how I did it (note that I'm new to iOS, so there's probably "better" ways, and this may be obvious to the iOS veterans):
The short version: define a callback protocol in your modal view controller's .h file. When your modal view controller closes, it checks to see if the presenter implements that protocol and invokes those methods to pass along the data.
So like you said, let's say your modal view controller just gathers a single string value from the user and then they click OK or Cancel. That class might look like this:
#interface MyModalViewController : UIViewController
...
#end
I'm suggesting you add a protocol like this to the same header:
#protocol MyModalViewControllerCallback
-(void) userCancelledMyModalViewController:(MyModalViewController*)vc;
-(void) userAcceptedMyModalViewController:(MyModalViewController*)vc
withInput:(NSString*)s;
#end
Then in MyModalViewController.m, you add a viewDidDisappear with code similar to this:
-(void) viewDidDisappear:(BOOL)animated {
UIViewController* presenter = self.presentingViewController;
// If the presenter is a UINavigationController then we assume that we're
// notifying whichever UIViewController is on the top of the stack.
if ([presenter isKindOfClass:[UINavigationController class]]) {
presenter = [(UINavigationController*)presenter topViewController];
}
if ([presenter conformsToProtocol:#protocol(MyModalViewControllerCallback)]) {
// Assumes the presence of an "accepted" ivar that knows whether they
// accepted or cancelled, and a "data" ivar that has the data that the
// user entered.
if (accepted) {
[presenter userAcceptedMyModalViewController:self withInput:data];
}
else {
[presenter userCancelledMyModalViewController:self];
}
}
[super viewDidDisappear:animated];
}
And finally in the parent view, you implement the new #protocol, e.g. in the .h:
#interface MyParentViewController : UIViewController <MyModalViewControllerCallback>
...
#end
and in the .m:
#implementation MyParentViewController
...
-(void) userCancelledMyModalViewController:(MyModalViewController*)vc {
// Update the text field with something like "They clicked cancel!"
}
-(void) userAcceptedMyModalViewController:(MyModalViewController*)vc
withInput:(NSString*)s {
// Update the text field with the value in s
}
...
#end

Resources