Navigating with a UITableView and a detail view - iphone

I am sure this is a straight forward application, but not sure what the best way is (and this is all new). I have a Navigation Controller with a UITableViewController (all running in UITabViewController).
When a user taps a row the App goes to a detailed view. Now I am trying to link left and right swipe gestures to navigating the to previous and next record. But what is the right way to do this from within the detailed view, what is the easiest to get a link back to my TableViewController?
A related question is then how I could link a 'pull down' to the same action as the 'back' button of the Navigation Controller.
I hope the above makes sense. Thanks a million in advance!
I have something working kind-of in the way I like, but it is very clumsy.
When calling the DetailView I pass as parameter the pointer to 'self' and the current 'selectedRow'. Then when a swipe is made I call the function 'moveToNextRecord' on the tabelViewController (with the pointer provided) and have the selectedRow as a parameter. In the tableViewController I then call selectRowAtIndexPath and didSelectRowAtIndexPath.
-(void)moveToNextRecord:(NSIndexPath*) selectedRow{
//[self.navigationController popViewControllerAnimated:YES];
//NSIndexPath *selectedRow = [self.tableView indexPathForSelectedRow];
NSUInteger row = selectedRow.row;
NSUInteger section = selectedRow.section;
++row;
if(row >= [self.tableView numberOfRowsInSection:selectedRow.section])
{
row = 0;
++section;
if(section >= [self.tableView numberOfSections])
{
row = 0;
section = 0;
}
}
[self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section] animated:YES scrollPosition:UITableViewScrollPositionMiddle];
[self tableView:self.tableView didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section]];
}
This seems to work, but the problem is that the next record is slotted after the previous one. This means that the back-button brings me back to the previous record and not back to the table view. So I guess I should tell the ViewController that I don't want to stack them but basically am going back and then select the next row, while showing the animation directly from one detailView to the next. Does that makes sense?
([self.navigationController popViewControllerAnimated:YES] as first fiction does not seem to work as it does not proper flow.)

From the detail view, once you recognize the gesture, then call:
[self.navigationController popViewControllerAnimated:YES];
this will navigate back.

I am moving towards a PageControl solution, as it is a much improved user experience as the page actually moves at the same time the user swipes. With the above suggestion I would need to over-ride the 'back' button, and manually populate the ViewController-stack in order to allow a left-to-right transition when doing a right swipe (and it only happens when the swipe is completed)

Related

Set Previous View Controller As A Property Of The Current View Controller

So, I am trying to implement a swipe right to go back to the previous view controller feature.
But when I have the following code in my current view controller, I get a black screen
- (void)initPreviousViewController:(GGMainViewController *)previous
{
self.previousViewController = previous;
self.previousViewController.view.frame = self.currentView.bounds; //self.currentView is declared elsewhere (in the init of the current view controller)
[self addChildViewController:self.previousViewController];
[self.currentView addSubview:self.previousViewController.view];
[self.previousViewController didMoveToParentViewController:self];
{
^I call this method within the previous view controller after initializing the current view controller, and before pushing the current view controller
If I change self.previousViewController = previous; to self.previousViewController = [GGMainViewController alloc] init]; it works. However, I don't want to reinitialize the previous controller.
So how do I set the previous view controller as a property of the current view controller.
Oh, I am also an iOS first timer, so if this is not something that is recommended, please let me know.
Rationale behind my thinking:
Normally the user would just click a button, and the UINavigationController would do the trick, but since I am using a swipe functionality, I think the user needs to see the previous view controller behind the current view controller as they swipe the screen.
As requested
How I call the currentViewController from the previousViewController
- (void)displayCurrentViewController:(id)sender
{
GGNextViewController *next = [[GGNextViewController alloc] init];
[next initializeExploreViewController:self]; // If I comment this out, everything is ok (screen is not black,etc. apart from being able to swipe backwards
[self.navigationController pushViewController:next animated:YES];
}
Your using the self.navigationController for pushing the current view controller, So you can call a method when ever the right swipe gesture fired.
Try this code in your Current view controller(GGNextViewController.m)...
1. Add the rightSwipeGestureAction() selector to the gesture recognizer which you have.
2.
-(void)rightSwipeGestureAction
{
[self.navigationController popViewControllerAnimated:YES];
}
It turns out that the following lines were causing the problem. I just decided to comment them out and then it worked, without a black screen.
[self addChildViewController:self.previousViewController];
[self.previousViewController didMoveToParentViewController:self];
I can't just pop it with the navigation controller, because I want to create somewhat of a dragging effect, the user swipes (as they see the previous view controller below) until halfway through the screen, from where it goes to the previous view controller.

When trying to view table view after viewing another, app crashes

i have a tough one for you today. I have two tableViews in my app the first is on the first page. There are two other pages the user drills down to get to the second table view. After i leave the first table view, i can press the back buttons to get back perfectly until i reach the second table view. As soon as i drill down to the second table view and then try to return to the first via pressing the back buttons. As soon as i get to the last back button to return to the first table view, the app crashes. The code for the back buttons is simply:
- (IBAction)goBack:(id)sender {
[self dismissModalViewControllerAnimated:YES];
}
Any Help Would be greatly appreciated!! Thanks everyone!! :D
Whenever I create a modal view controller from a XIB, the automatic #property generator duplicates things in the Dealloc method, thus throwing an EXC_BAD_ACCESS when the view is dismissed. Make sure you aren't releasing something twice.
Sounds like your are releasing something too early. Open you app in instruments (command + i) and run a zombie test.
As soon as you see zombie has been messaged expand the right panel and have a look at the user code (your code) blocks. Indicated by the back person icon.
Double click that and it will indicate what it was trying to access that had already been released.
Are your tableviews being displayed in a modal window? If not, why are you calling [self dismissModalViewControllerAnimated:YES]? Shouldn't you be calling [[self navigationController] popViewControllerAnimated:YES]?
If you're using a UINavigationController, the back button functionality should be provided automatically.
if you are using [[self navigationController] popViewControllerAnimated:YES] to
then for back you write as mentioned below:
(IBAction)goBack:(id)sender {
// Tell the controller to go back
[self.navigationController popViewControllerAnimated:YES];
}
if you are using [self presentmodalviewcontroller: animated:]
then only [self dismissModalViewControllerAnimated:YES] will work
you try this [[self navigationController] popViewControllerAnimated:YES]

iPhone - Update current view before pushing new ViewController on UITableViewCell selected

I have a UITableView with a list of items. On selection of an item I'm navigating to a new view that displays the details of the selected item using:
DetailsVC *detailsView = [[DetailsVC alloc] initWithNibName:#"DetailsVC" bundle:nil];
[self.navigationController pushViewController:detailsView animated:YES];
Now, the details view is getting the data from the remote location so on slow connection it can take a few seconds. What I want to do is display an activity indicator over the selected row on selection.
The problem is the display of the added indicator gets delayed until the next view is ready to navigate to, which makes the indicator usless.
I've tried to add this indicator in those 2 events with the same effect:
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Is there a way to add the indicator (or more general, modify the content of a UITableViewCell) in the moment of selection, before navigation occurs.
As a experiment I've also tried to pop up an alert view in the same two events which resulted in poping up the alert after navigation to the details view.
So it's [[DetailsVC alloc] init...] that takes a few seconds, right? This problem is that any view changes you make don't fully take effect until returning all the way back to the runloop, so even if you setup the indicator before creating your object, it too is waiting for the init to finish to make itself visible. What you need to do is defer the creation of your DetailsVC until after the indicator is setup.
I might be a simpler change to use blocks but I can't recall the details of that off the top of my head (haven't used blocks much since code I've been writing lately has had to stay compatible with 3.x). But to use performSelector is easy too, take those 2 lines you first quoted in your question and put them into its own method, such as:
- (void)pushDetailsView {
DetailsVC *detailsView = [[DetailsVC alloc] initWithNibName:#"DetailsVC" bundle:nil];
[self.navigationController pushViewController:detailsView animated:YES];
}
And where you had those lines before, setup your indicator and then do this (a delay of 0 doesn't mean to called it immediately, but rather ASAP after returning all the way out of the current call stack):
[self performSelector:#selector(pushDetailsView) withObject:nil withDelay:0]
you can call cell = [self rowForIndexPath:indexPath] in one of your functions. and then add the indicator to cells subview
You can either
add the indicator when u select row and push new view when data came
(simultaneously remove indicator at that time) or
Push new view, call web service to get corresponding cell data (in
viewDidLoad or viewWillAppear) and display indicator simultaneously
and when new data comes remove indicator

TableViewController doesn't flash scroll indicators even if the table is bigger that the view

I've got a weird problem with a TableViewController.
In the doc it says that a tableViewController deals also with the method
-flashScrollIndicators when the table is "oversized" respect the visible area.
My app consists in 3 nav controller loaded in a tab controller. Each nav controller has as root view controller a subclass of a table view controller.
Each "model" is populated from a plist file, that loads its contents into an array in the -viewDIdLoad, later everything is passed to the table. Everything is loaded programmatically no IB.
I've found out in my app that when it loads the first view (a nav controller with a table view controller as root) the scroll bar isn't flashing even if the number of cell it's great enough.
If I choose another tab, that loads another nav controller (with a t.v.c. as root) scroll bar isn't shown again. When I press the tab corresponding to the first nav controller loaded the scrollbar flashes.
So I've tried to make it flash programmatically but no way, the code seems simple:
[self.tableView flashScrollIndicators];
I've tried to put it almost everywhere. First in the -viewDidLoad (As suggested in the doc), then in viewDidAppear and in -viewWillAppear.
Also tried use that code tring to cast the view of the t.v.c. as a table view.
[((UITableView*)self.view) flashScrollIndicators];
..without result.
I've started looking at Apple sample and I've found that in Apple's table view custom sample (the one with different times) scroll bar doesn't flash also there.
Tested both on sim and device.
Is a bug?, is there a correct way to show it programmatically?
Can someone help me?
Regards,
Andrea
Or more concisely:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.tableView performSelector:#selector(flashScrollIndicators) withObject:nil afterDelay:0];
}
I had exactly the same problem. I got around it in the end by putting a delayed selector in the viewDidAppear: method. Weirdly, I can set it to 0 seconds and it still works fine.
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self performSelector:#selector(flashTableScrollIndicators) withObject:nil afterDelay:0.0];
}
- (void)flashTableScrollIndicators
{
[self.tableView flashScrollIndicators];
}
It is not displayed when you show section index titles.
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView;
My solution was to send the "flashScrollIndicators()" message with a slight delay using "dispatch_after":
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(0.4 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue(),
{ () -> Void in
myScrollView.flashScrollIndicators()
})

VERY weird UITableViewController.tableview behaviour on scrollToRowAtIndexPath

hey all, I'm very confused here, i've been trying to figure this one out. I have a UIViewController, viewControllerBrowse, with two TableViewController, Designations & Types, I call a second UIViewController, viewControllerSelectLibrary, that makes some SOLite operations and fills two arrays from where the first two TableView feed.
When I'm going to call back viewControllerBrowse, I perform inside a NSThread:
[appDelegate.viewControllerBrowse.tvcTypes.tableView reloadData];
[appDelegate.viewControllerBrowse.tvcTypes.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] animated:YES scrollPosition:UITableViewScrollPositionTop];
[appDelegate.viewControllerBrowse.tvcDesignations.tableView reloadData];
[appDelegate.viewControllerBrowse.tvcDesignations.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] animated:YES scrollPosition:UITableViewScrollPositionTop];
What TRUUUULY puzzles me is that on tvcTypes case, its tableView gets its first row selected and scrolled to the top
BUT, for tvcDesignations, its tableView get ITS FIRST ROW SELECTED BUT IT DOES NOT SCROLL TO THE TOP
the fact that the first row is selected tells me that it's not a problem of reference in the appDelegate, it's as if only half the method is working/??????????????
anyone hit this one before??????
Just a guess, but what happens if you pass NO to animated? I've never seen this behavior specifically, unfortunately, but I have seen some animations cause weird interactions.
Also, which view controller is visible? Either of them?