using NSMutableArray to change subviews - iphone

I have creates an array of three viewControllers which I would like to swipe between. and have animate across the screen.
So far I have created the array of views, have gesture control and am loading the first view of the array to the view in the viewDidLoad method of the viewController thats holding my animation stuff.
What I have done is added to viewController objects, (current, furutre) when the app first loads I put the first view of the array into the current viewController.. then when I swipe the view I Load the next view int he array into the future viewcontroller and perform an animation.. Then I do the same for the third animation.. however its breaking down, because I am not passing the second view to current then the third view to future before the last animation.. (hope this makes sense.)
Heres the code thats doing what I am doing so far..
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.title = #"Prototype";
//Initalizse the swipe gestuer listener
[self setupLeftSwipeGestureRecognizer];
[self setupRightSwipeGestureRecognizer];
//Initalize all of the swipe views
DetailViewController *DVCA = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:[NSBundle mainBundle]];
DetailViewControllerB *DVCB = [[DetailViewControllerB alloc] initWithNibName:#"DetailViewControllerB" bundle:[NSBundle mainBundle]];
DetailViewControllerC *DVCC = [[DetailViewControllerC alloc] initWithNibName:#"DetailViewControllerC" bundle:[NSBundle mainBundle]];
//Assinge swipeviews to viewArray
viewArray = [NSArray arrayWithObjects:DVCA, DVCB, DVCC, nil];
//Initalize viewcount so it can keep track of which viewController is in view
viewCount = 0;
// set detail View as first view
currentViewController = [viewArray objectAtIndex:viewCount];
[self.view addSubview:currentViewController.view];
}
// Need to change this to work with viewArray
- (void)swipedScreen:(UISwipeGestureRecognizer*)gesture {
//Left swipe
if (gesture.direction == UISwipeGestureRecognizerDirectionLeft) {
//stops swipes from returning any viewCount outside of viewArrays range
if ((viewCount >= 0) || (viewCount >= 2)) {
//Increment for next view
viewCount += 1;
futureViewController = [viewArray objectAtIndex:viewCount];
[self.view addSubview:futureViewController.view];
[futureViewController.view setFrame:CGRectMake(320, 0, self.view.frame.size.width, self.view.frame.size.height)];
[UIView animateWithDuration:0.25 animations:^{
[futureViewController.view setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
[currentViewController.view setFrame:CGRectMake(-320, 0, self.view.frame.size.width, self.view.frame.size.height)];
}];
}
}
//Right swipe -- still need to do this (go back through the view array.
else if (gesture.direction == UISwipeGestureRecognizerDirectionRight){
[UIView animateWithDuration:0.25 animations:^{
[self.detailViewA.view setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
[self.detailViewB.view setFrame:CGRectMake(320, 0, self.view.frame.size.width, self.view.frame.size.height)];
}];
}
}

Sorry but you should use a UInavigationController to switch between views of view controller.
You can stillanimate the frame and not use the classic animation included in uinavigation controlller.
you push and pop view controller in the navigation controller. look for UINavigationController in the apple doc, you dont need to have the navigation bar at the top if that's what you're trying to avoid with your code.

Related

How to prevent scroll the tableHeaderView of UItable view, To stick at the top

In my split view application it is not possible to add search bar to the rootView of the split view
So i added search bar dynamically at the tableHeaderView of the ui table view as folows
searchBar = [[UISearchBar alloc] init];
searchBar.frame=CGRectMake(0, self.tableView.frame.origin.y, self.tableView.frame.size.width, 44);
[searchBar sizeToFit];
self.tableView.tableHeaderView = searchBar;
When Scroll down: iThe tableHeaderView also scrolls down so search bar also scrolls
When Scroll top: The tableHeaderView also scrolls top so search bar also scrolls
I implemented code as follows to resolve this issue this helps only when scrolls down but when we scrolls the table view to topside it again move with the table view
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGRect rect = self.tableView.tableHeaderView.frame;
rect.origin.y = MIN(0, self.tableView.contentOffset.y);
self.tableView.tableHeaderView.frame = rect;
}
I need to stick the tableHeaderView/ Search bar at the top of the view always
How to do this
You can add tabBar separate with tableView
mySearchBar = [[UISearchBar alloc] init];
[mySearchBar setHidden:NO];
mySearchBar.placeholder = #"Search item here";
mySearchBar.tintColor = [UIColor darkGrayColor];
mySearchBar.frame = CGRectMake(0, 0, 320, 44);
mySearchBar.delegate = self;
[mySearchBar sizeToFit];
[mySearchBar setAutocapitalizationType:UITextAutocapitalizationTypeNone];
[self.view addSubview:mySearchBar];
And tableView
UITableView *tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 44, 320, 436)];
[self.view addSubview:tableView];
If You want to add in xib then
Put your searchBar in separate view and put that view above the table view. That means it stays constant.
I'm sure this has been answered before, but assuming you're using UITableViewController, you can make the view property be anything you want. So one approach would be to set up a container view with your search bar at the top and the table below it and make view be this container. By default, tableView returns view, so another detail you'd need to take care of is overriding the tableView property to return the actual table view (that you've stored in an ivar). The code might look something like this:
#synthesize tableView = _tableView;
- (void)loadView
{
[super loadView];
_tableView = [super tableView];
// Container for both the table view and search bar
UIView *container = [[UIView alloc] initWithFrame:self.tableView.frame];
// Search bar
UIView *searchBar = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.frame.size.width, 50)];
// Reposition the table view below the search bar
CGRect tableViewFrame = container.bounds;
tableViewFrame.size.height = tableViewFrame.size.height - searchBar.frame.size.height;
tableViewFrame.origin.y = searchBar.frame.size.height + 1;
self.tableView.frame = tableViewFrame;
// Reorganize the view heirarchy
[self.tableView.superview addSubview:container];
[container addSubview:self.tableView];
[container addSubview:searchBar];
self.view = container;
}

ViewController with subviews, UIScrollView not scrollable first time

Im using a UIViewController with several subviews from XIBs, (ViewController's views), they are chosen between using UISegmentedControl. One of these views are containing a UIScrollView. The problem is that the UIScrollView is not scrollable the first time this subview is added. If I choose another segment/view and then the one with the UIScrollView again, now it's scrollable.
The UIScrollView is added in IB only. This is some of the codes for the views and UISegmentedControl in MainViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
nameSubViewController = [[NameSubViewController alloc] initWithNibName:#"NameSubViewController" bundle:nil];
nameSubView = (NameSubView *)[nameSubViewController view];
priceSubViewController = [[PriceSubViewController alloc] initWithNibName:#"PriceSubViewController" bundle:nil];
priceSubView = (PriceSubView *)[priceSubViewController view];
[self.view addSubview:nameSubView];
currentView = nameSubView;
}
- (void) segmentAction:(id)sender
{
segmentedControl = sender;
if([segmentedControl selectedSegmentIndex] == 0) {
[currentView removeFromSuperview];
[self.view addSubview:nameSubView];
currentView = nil;
currentView = nameSubView;
}
if([segmentedControl selectedSegmentIndex] == 1) {
[currentView removeFromSuperview];
[self.view addSubview:priceSubView];
currentView = nil;
currentView = priceSubView;
}
In this code, let's say segment 1 (priceSubView) contains the UIScrollView. If I choose this segment, the UIScrollView does not react on the scrolling unless I choose segment 0 (nameSubView) again and re-select segment 1.
What is causing this and how to fix it?
If you need to scroll at first load.
You need to add the scrollView at firstLoad.
You are adding the scroll view after changing the segment control, that's why it's not scrolling. Check it out.
Change viewDidLoad like:
- (void)viewDidLoad
{
[super viewDidLoad];
nameSubViewController = [[NameSubViewController alloc] initWithNibName:#"NameSubViewController" bundle:nil];
nameSubView = (NameSubView *)[nameSubViewController view];
priceSubViewController = [[PriceSubViewController alloc] initWithNibName:#"PriceSubViewController" bundle:nil];
priceSubView = (PriceSubView *)[priceSubViewController view];
[self.view addSubview:priceSubView];
currentView = priceSubView;
}

tabBarController set to nil when changing view but always in the window

I'm currently using a tableview inside a navigation controller, inside a tab bar controller. When i'm on the detail view of the table view, i want to "swipe" between Detail view, so i have implemented a UISwipeGesture with UIViewAnimations to swipe right/left.
Everything is working, but I have a little problem... When i'm on a Detail View loaded from the table view, the self.tabBarController element is here, i have my tab bar so i can add an actionsheet on it. But when i swipe, the self.tabBarController is nil now... I don't know why... Maybe because of the navigation Controller ?
Here is my code :
- (id) init
{
if (self = [super init]) {
CGRect fullScreenRect=[[UIScreen mainScreen] applicationFrame];
UIScrollView *scrollView=[[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, fullScreenRect.size.width, 367.)];
scrollView.contentSize=CGSizeMake(320,100);
scrollView.delegate = self;
self.view=scrollView;
self.myView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 367.)];
self.ButtonSizeM.tag = 0;
self.ButtonSizeP.tag = 0;
self.ContentIV = [[UIImageView alloc] init];
}
return self;
}
- (void) handleSwipeLeft {
if (!((self.ancient.tableView.indexPathForSelectedRow.section == ([self.ancient numberOfSectionsInTableView:self.ancient.tableView] - 1)) && (self.ancient.tableView.indexPathForSelectedRow.row == [self.ancient tableView:self.ancient.tableView numberOfRowsInSection:(self.ancient.tableView.indexPathForSelectedRow.section)]-1)))
{
NSIndexPath *whereToGo;
if (self.ancient.tableView.indexPathForSelectedRow.row == [self.ancient tableView:self.ancient.tableView numberOfRowsInSection:(self.ancient.tableView.indexPathForSelectedRow.section)]-1) {
whereToGo = [NSIndexPath indexPathForRow:0 inSection:(self.ancient.tableView.indexPathForSelectedRow.section)+1];
}
else {
whereToGo = [NSIndexPath indexPathForRow:(self.ancient.tableView.indexPathForSelectedRow.row)+1 inSection:self.ancient.tableView.indexPathForSelectedRow.section];
}
CCFASimpleDetail *nextView = [[CCFASimpleDetail alloc] init];
nextView = [self.ancient tableView:self.ancient.tableView prepareViewForIndexPath:whereToGo];
[nextView performSelectorOnMainThread:#selector(affichageEnPlace) withObject:nil waitUntilDone:YES];
float width = self.myView.frame.size.width;
float height = self.myView.frame.size.height;
[nextView.view setFrame:CGRectMake(width, 0.0, width, height)];
[self.view addSubview:nextView.view];
[UIView animateWithDuration:0.5f delay:0 options:UIViewAnimationCurveEaseInOut animations:^{
[nextView.view setFrame:self.view.frame];
[self.myView setFrame:CGRectMake(-width, 0.0, width, height)];
} completion:^(BOOL finished) {
[self.myView removeFromSuperview];
[self.ancient.tableView selectRowAtIndexPath:whereToGo animated:NO scrollPosition:UITableViewScrollPositionTop];
}
];
}
}
I you could help me to find my tab bar after swiping :) ?
When you add the view here:
[self.view addSubview:nextView.view];
the UINavigation controller does not know about it, and does not set the navigationBar nad tabBar properties for you.
What you can do is have the view get its superview (which will be self.view), then ask that view for the tabBarController and tabBar from that.
I just solved my problem by adding
[self.ancient.navigationController popViewControllerAnimated:NO];
[self.ancient.navigationController pushViewController:nextView animated:NO];
on the completion block !

TableView frame not resizing properly when pushing a new view controller and the keyboard is hiding

I must be missing something fundamental here. I have a UITableView inside of a NavigationViewController. When a table row is selected in the UITableView (using tableView:didSelectRowAtIndexPath:) I call pushViewController to display a different view controller. The new view controller appears correctly, but when I pop that view controller and return the UITableView is resized as if the keyboard was being displayed. I need to find a way to have the keyboard hide before I push the view controller so that the frame is restored correctly. If I comment out the code to push the view controller then the keyboard hides correctly and the frame resizes correctly.
The code I use to show the keyboard is as follows:
- (void) keyboardDidShowNotification:(NSNotification *)inNotification {
NSLog(#"Keyboard Show");
if (keyboardVisible) return;
// We now resize the view accordingly to accomodate the keyboard being visible
keyboardVisible = YES;
CGRect bounds = [[[inNotification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
bounds = [self.view convertRect:bounds fromView:nil];
CGRect tableFrame = tableViewNewEntry.frame;
tableFrame.size.height -= bounds.size.height; // subtract the keyboard height
if (self.tabBarController != nil) {
tableFrame.size.height += 48; // add the tab bar height
}
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(shrinkDidEnd:finished:contextInfo:)];
tableViewNewEntry.frame = tableFrame;
[UIView commitAnimations];
}
The keyboard is hidden using:
- (void) keyboardWillHideNotification:(NSNotification *)inNotification {
if (!keyboardVisible) return;
NSLog(#"Keyboard Hide");
keyboardVisible = FALSE;
CGRect bounds = [[[inNotification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
bounds = [self.view convertRect:bounds fromView:nil];
CGRect tableFrame = tableViewNewEntry.frame;
tableFrame.size.height += bounds.size.height; // add the keyboard height
if (self.tabBarController != nil) {
tableFrame.size.height -= 48; // subtract the tab bar height
}
tableViewNewEntry.frame = tableFrame;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(_shrinkDidEnd:finished:contextInfo:)];
tableViewNewEntry.frame = tableFrame;
[UIView commitAnimations];
[tableViewNewEntry scrollToNearestSelectedRowAtScrollPosition:UITableViewScrollPositionMiddle animated:YES];
NSLog(#"Keyboard Hide Finished");
}
I trigger the keyboard being hidden by resigning first responser for any control that is the first responder in ViewWillDisappear. I have added NSLog statements and see things happening in the log file as follows:
Show Keyboard
ViewWillDisappear: Hiding Keyboard
Hide Keyboard
Keyboard Hide Finished
PushViewController (an NSLog entry at the point I push the new view controller)
From this trace, I can see things happening in the right order, but It seems like when the view controller is pushed that the keyboard hide code does not execute properly.
Any ideas would be really appreciated. I have been banging my head against the keyboard for a while trying to find out what I am doing wrong.
-- Added didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
switch (indexPath.section) {
case 0: // Required Info
// removed to simplify
case 1: // Optional Info
switch (indexPath.row) {
case 0:
[self showTextDetailPicker: #"Enter a description"
tag: tDescriptionPicker
sourceTarget: self.newRecord
fieldSource: #selector(description)];
break;
default:
break;
}
break;
default:
break;
}
}
- (void) showTextDetailPicker: (NSString*) titleText tag:(int)tagID sourceTarget:(NSObject*)target fieldSource:(SEL)selector{
FieldEditorViewController *fe = [[FieldEditorViewController alloc] init];
fe.titleText = titleText;
fe.fieldText = [target performSelector: selector];
fe.tag = tagID;
// Replace default back button with one that just says 'Back'
UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc]
initWithTitle:#"Back"
style:UIButtonTypeInfoLight
target:nil action:nil];
[[self navigationItem] setBackBarButtonItem: newBackButton];
[newBackButton release];
[fe setDelegate: self];
[self.navigationController pushViewController:fe animated:YES];
[fe release];
}
Right before you push your view controller, find the first responder and call resign. Use the category from this SO post to see how to find the first responder recursively (not sure if you're already doing this).
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UIView *fp = [[self view] findFirstResponder];
[fp resignFirstResponder];
// Push new view controller here.
NextViewController *controller = [[NextViewController alloc] init];
[[self navigationController] pushViewController:controller animated:YES];
[controller release], controller = nil;
}
The other thing to keep in mind is that your table view is getting resized automatically because your root view controller is derived from UITableViewController (or so it seems). If you make your root view controller a regular UIViewController that contains a UITableView, you can manipulate the frame of the table view manually more easily--at least that's been my experience.

iPhone Pushing View Controller in a left direction

I have an app that has a centre view with two views off to each side of it. I want to have two navigation bar buttons, left and right which push a new navigation controller onto the view from the left or the right.
When you change views by pushing a new view using the pushviewController: method of NavigationController, the view appears to slide in from the right. how do i change this to slide in from the left?
I have done change animation direction when we push viewcontroller.
you can change animation type here [animation setSubtype:kCATransitionFromRight];
ViewController *elementController = [[ViewController alloc] init];
// set the element for the controller
ViewController.element = element;
// push the element view controller onto the navigation stack to display it
CATransition *animation = [CATransition animation];
[[self navigationController] pushViewController:elementController animated:NO];
[animation setDuration:0.45];
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromRight];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]];
[[elementController.view layer] addAnimation:animation forKey:#"SwitchToView1"];
[elementController release];
Instead of using a navigation controller, I would just move the view.
CGRect inFrame = [currentView frame];
CGRect outFrame = firstFrame;
outFrame.origin.x -= inFrame.size.width;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
[newView setFrame:inFrame];
currentView setFrame:outFrame];
[UIView commitAnimations];
I don't think you can explicitly define sliding direction in UINavigationControllers. What you might be able to do is pop the current view off the navigation stack to show the prior view, which would animate in the manner you want. However this may be complex if you want to have different view controllers appear depending on what you do on the current view.
If your workflow is not too complicated, you can hold a reference to the prior view controller in the current view controller. depending on what you do on the current view (like select a table view cell), you can change whatever data you need in the prior view controller, and then call
[self.navigationController popViewController];
or whatever the correct method is (i think that's pretty close to how it is). that would let you move down the nav stack with the animation you want, which works if your nav stack has a set number of views on it.
to what Reed Olsen said: you must only hook up one button, that starts the slide up to the same method and add a BOOL that tracks if the view is shown or not. all you need to do is set the origin properly.
- (IBAction)slideMenuView
{
CGRect inFrame = [self.view frame];
CGRect outFrame = self.view.frame;
if (self.viewisHidden) {
outFrame.origin.x += inFrame.size.width-50;
self.viewisHidden = NO;
} else {
outFrame.origin.x -= inFrame.size.width-50;
self.viewisHidden = YES;
}
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[self.menuView setFrame:inFrame];
[self.view setFrame:outFrame];
[UIView commitAnimations];
}
To get the "pointy" type button you need to use a different method.
In your AppDelegate:
UITableViewController *first = [[RootViewController alloc] initWithStyle:UITableViewStylePlain];
UITableViewController *second = [[SomeOtherViewController alloc] initWithStyle:UITableViewStylePlain];
NSArray *stack = [NSArray arrayWithObjects: first, second, nil];
UINavigationController *nav = [[UINavigationController alloc] init];
[nav setViewControllers:stack animated:NO];
You can inherit RTLNavigationController:UINavigationController and overwrite these functions.
- (void) pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
DummyViewController*dvc = [[DummyViewController alloc] init];
[super pushViewController:viewController animated:NO];
[super pushViewController:dvc animated:NO];
[dvc release];
[super popViewControllerAnimated:YES];
}
and
- (UIViewController *)popViewControllerAnimated:(BOOL)animated
{
UIViewController *firstViewController = [super popViewControllerAnimated:NO];
UIViewController *viewController = [super popViewControllerAnimated:NO];
[super pushViewController:viewController animated:animated];
return firstViewController;
}
And in application delegate:
navCon = [[RTLNavigationController alloc] init];
rootViewController = [[RootViewController alloc] initWithNibName:#"RootViewController" bundle:nil];
rootViewController.contextDelegate = self;
DummyViewController *dvc = [[DummyViewController alloc]init];
[navCon pushViewController:dvc animated:NO];
[dvc release];
[navCon pushViewController:rootViewController animated:NO];
[self.window addSubview:navCon.view];
Pushing will be from left to right and popping from right to left