Each tab in UITabController has many view controllers - ios

I want to design an app with UI like this:
At bottom, I know it is UITabbarController. In each tab, it has many view controllers like BEAT, TOP, FUN... Each tab has different view controllers.
When scroll horizontal, can change from BEAT to TOP to FUN...
How can I design like that? What view controller should I use? It seems like UIPageController in UITabController, but with UIPageController, I don't know how to replace dots at bottom (.) by BEAT, TOP, FUN... at top.
Thanks for your help.

Alternative solution is to add UISwipeGesture(Left/Right) on view and upon swipe action you can push or pop view controllers.
In ViewController.h
#property (retain, nonatomic) UISwipeGestureRecognizer * leftSwipe;
#property (retain, nonatomic) UISwipeGestureRecognizer * rightSwipe;
In ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
[self setupSwipeGestures];
}
-(void)setupSwipeGestures
{
_leftSwipe=[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(next)];
[_leftSwipe setDirection:UISwipeGestureRecognizerDirectionLeft];
_rightSwipe =[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(previous)];
[_rightSwipe setDirection:UISwipeGestureRecognizerDirectionRight];
[self.view addGestureRecognizer:_leftSwipe];
[self.view addGestureRecognizer:_rightSwipe];
}
- (void) previous
{
// perform pop to get previous viewController
// i.e [self.navigationController popViewControllerAnimated:YES];
}
- (void) next
{
// perform push to get next viewController
// i.e [self.navigationController pushViewController:viewController animated:YES];
}
If you want to use above code in every Controller, then you may define your own viewController and paste above code in it, after that inherit all of your viewControllers where you need above functionality.

You can use XLPagerTabStrip library in each tab of your tab controller. Awesome library, even gives you the swiping feature similar to android which can enable you to swipe through individual page sections as well as keeping tab property.

Related

Toggle edit mode in another ViewController

I have a ViewController (with a container view) embedded in a Navigation controller. The container contains a pageViewController with one of the 'pages' being a TableViewController (with UITableView outlet: 'aTableView'). I want to trigger the edit mode in the tableViewController when tapping a custom editButton in the navigation bar. When I create a custom editutton in the tableViewController the edit mode works as expected, but when I use the custom editButton in the navigation bar the setEditing bool value remains zero even when I setEditing to YES in the editButton selector. Here's the code:
ViewController.m
-(void)viewDidLoad {
self.editBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[self.editBtn setFrame:CGRectMake(0, 0, 40, 22)];
[self.editBtn addTarget:self action:#selector(goToToggleEdit:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *editButton=[[UIBarButtonItem alloc]initWithCustomView:self.editBtn];
self.navigationItem.rightBarButtonItem = editButton;
}
-(void)goToToggleEdit:(id)sender
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
TableViewController *tvc = [storyboard instantiateViewControllerWithIdentifier:#"aTableViewController"];
if(something==foo){
[tvc toggleEdit];
}
}
aTableViewController.h
#interface aTableViewController : UITableViewController <UITextFieldDelegate> {
IBOutlet UITableView *aTableView;
}
-(void) toggleEdit ;
#end
aTableViewController.m
-(void)toggleEdit {
[aTableView setEditing:YES animated:YES];
NSLog(aTableView.editing ? #"Yes" : #"No"); // --> logss 'No'.
if (aTableView.editing){
//do something
}
else {
//do something else
}
}
How can I efficiently trigger the edit mode in the tableViewController this way?
Edit
#Bagrat Kirakosian pointed out to me that my view hierarchy (Navigation Controller > View Controller (with containter) > Page View Controller (in container) > Table View Controller) might be the problem. I just want to create a Navigation Bar (with an edit button) that is fixed, therefore I can't embed the Table View Controller directly in a Navigation Controller.
Thanks.
UPDATE: Solution
I have accepted #sebastien's solution although both #sebastien's and #Bagrat's solution work great. #Bagrat's answer includes direct access to the Table View Controllers, while #sebastien's solution calls edit mode in the pageViewController. I think, considering the tricky hierarchy, the latter is a bit more secure.
Here is the code for my View Controller that totally work fine. be sure you configure your bar button in the right method of View Controller lifecycle. Also be sure that your #selector is properly implemented in your code.
In the same View Controller put these two blocks of code
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
UIBarButtonItem *rightBarButton = [[UIBarButtonItem alloc] initWithImage:[[UIImage imageNamed:#"edit_icon.png" ] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] style:UIBarButtonItemStylePlain target:self action:#selector(edit:)];
[rightBarButton setTintColor:[UIColor whiteColor]];
self.navigationItem.rightBarButtonItem = rightBarButton;
}
Afterwards you need also to put your edit selector
-(void)edit:(UIButton *)sender {
// Toggle edit by inverting current edit state
// Also in this block change your right bar button text or image
[self.tableView setEditing:!self.tableView.editing animated:YES];
}
UPDATE 1
After your comment we got to whole another question. You problem is not in the part where you try to call toggle edit. Your problem is the wrong hierarchy of controllers (Navigation Controller > View Controller > Page View Controller > Table View Controller). This might cause a problem. Try to change your controllers like this;
UINavigationController > UIPageViewController > UIViewController(s)
Also it's a good practice to have a UITableView in UIViewController rather than using really dead UITableViewController. Don't forget to connect your tableView IBOutlet (by the way you didn't need it in UITableViewController), also connect datasource and delegate to Files owner. In your MyTableViewVC.h file add this line
#interface MyTableViewVC : UIViewController <UITableViewDataSource, UITableViewDelegate>
After that all your calls will work fine.
UPDATE 2
After analyzing your entire structure I found a mistake that you do every time on the button click.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
tvc = [[TodolistTableViewController alloc] init];
When you call storyboard every time it's ok but when you do [[TodolistTableViewController alloc] init] you are RE-MAKING the same table view controller every time but not even adding it to your main view. As I told you, your tricky hierarchy might cause difficulties but it has a solution.
In your PageViewController.m make tv1 and tv2 properties in .h file, like so.
#property (strong, nonatomic) UITableViewController *tv1;
#property (strong, nonatomic) UITableViewController *tv2;
Then in the view controller file do this
-(void)toggleEdit:(id)sender
{
PageViewController *current = (PageViewController *)[[self childViewControllers] firstObject];
if ([current isKindOfClass:[PageViewController class]])
{
[((TodolistTableViewController *)[current tv1]) toggleEdit];
}
}
Answer includes all security checks and direct access to your table view controllers, because you might need to change other properties/call functions later.
Now in -(void)toggleEdit:(id)sender you don't re-create your views every time but you catch the ones you already have in your current View Controller.
Good Luck!
Ok, your issue here is that you are trying to access an embedded controller in a wrong way.
You are actually managing 2 differents PageViewController:
The one you generated through your storyboard
The other one you are initiating in your code further
That's why you can't reach the expected result.
First of all, add a new method to your PageViewController:
PageViewController.h:
- (void)editTableAtIndex:(int)index;
PageViewController.m:
- (void)editTableAtIndex:(int)index {
[[self viewControllerAtIndex:index] setEditing:YES];
}
Now, in your main ViewController, access the PageViewController by using childViewControllers:
-(void)toggleEdit:(id)sender
{
PageViewController *pvc = self.childViewControllers[0];
[pvc editTableAtIndex:0];
}
It should be editing your TodoListTableView:
(Please notice that I used [pvc editTableAtIndex:0];, instead you should be calling something like [pvc editTableAtIndex:_PageViewController_current_index_];)

Toolbar as sub navigation bar in NavigationController

I'm building an iOS app using a NavigationController. However, in this app I need a sub navigation bar and it needs to be in every view. I initially implemented this using a toolbar in every view. But what happens, when a new view slides in, is that the toolbar slides in as well. I need the toolbar to be persistent, like the navigation bar. What's the best way to approach this?
My best guess is to set [self.navigationController setToolbarHidden:YES animated:YES]; to YES and then somehow positioning that underneath the navbar...
This is how I used to do it in every viewcontroller:
#interface TableViewController ()
#property (weak, nonatomic) IBOutlet UIToolbar *mainToolBar;
#end
#implementation TableViewController
- (void)viewWillAppear:(BOOL)animated
{
[self.navigationController setToolbarHidden:YES animated:YES];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"TV Shows";
[self addRightMenuButton];
[self loadNinjas];
self.mainToolBar.barTintColor = [UIColor whiteColor];
self.mainToolBar.layer.shadowColor = [[UIColor blackColor] CGColor];
self.mainToolBar.layer.shadowOffset = CGSizeMake(1.0f, 1.0f);
self.mainToolBar.layer.shadowRadius = 3.0f;
self.mainToolBar.layer.shadowOpacity = 1.0f;
self.tableView.dataSource=self;
self.tableView.delegate=self;
}
Three distinct approaches I can think of trying:
Make a taller Navigation Bar subclass with your secondary toolbar thing at the bottom. Set it as the Navigation Controller's Navigation Bar. I've tried this a couple of times to achieve different things and it didn't work out, but maybe it will for you.
Stick with what you're doing, a second toolbar on every VC, and use a custom VC transition or presentation controller to make it appear like the toolbar isn't moving while the rest of the content is.
Don't do this. I can't really see a way that a double navigation thing is going to be good for an iPhone app.

Toolbar is not hidden after segue

I have trouble w/ hiding toolbar when leave screen by segue.
Details: App has a few dozen screens, all of them are belonged the same navigation controller. A few screens have toolbar. For these a few screens in -(void)viewDidLoad I use
[self.navigationController setToolbarHidden:NO animated:NO];
and in -(void)viewWillDisappear:(BOOL)animated:
[self.navigationController setToolbarHidden:YES animated:YES];
so toolbar is visible only on necessary screens and the screen which needs toolbar controls the visibility. All work well when I navigate by "back" button.
The trouble starting when I try to navigate by segue like this (goto home & goto another branch).
[owner.navigationController popToRootViewControllerAnimated:NO];
[self performSegueWithIdentifier:SEGUE_NAME sender:self];
toolbar is stay visible in spite of calling -(void)viewWillDisappear which should hide toolbar.
are there any ideas how to perform these "ToolBarHidden" by right way.
thanks
PS: of course I could hide toolbar on every screen, but I want to avoid this unnecessary operations and want to know how to do it right.
**STEP1:** in your controller.h
#interface ViewController : UIViewController {
UIToolbar *bar;
}
#property (nonatomic, strong) IBOutlet UIToolbar *bar;
#end
**STEP2:** in your controller.m
#synthesize bar;
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.bar.hidden = NO;
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
self.bar.hidden = YES;
}
**STEP3:** connect in Intrface
hope this help you!

Handling a view controller that slides in with either way swipe

I am building an application that is for iOS6+. The application will have a main View Controller at one point in the application.
I would like this main view controller to handle a swipe left and swipe right on screen to then show another view controller.
Is there an easy way to accomplish this in core iOS6+, or should I look for another library etc.
I already use a slide in menu style else where in the application. I also understand and can find a million alternatives to these.
What I am looking for is to have one View Controller (which acts in the 'middle'). Then when they swipe left/right another view controller is shown. They can then swipe back the opposite direction or click a back button to return to the main controller.
EDIT-
Specifically I am looking for the functionality to do the following:
Pre-load the controller that will slide in.
When the swipe occurs (is happening)... the controller to drag/slide in with the touch.
The same drag/swipe to occur either way the controller is swiped (lefT/right).
EDIT 2 -
I am looking for the functionality of dragging the view controller in with the finger. Dependant on which way the drag is occurring, it would be pulling the same view controller in.
I.e the layout would be:
[VC for Drag] [Main controller] [VC for Drag].
If the user swipes from left to right, or right to left the other controller is dragged over the top and they can return to the Main controller using the opposite entry swipe.
My favorite side-drawer controller: https://github.com/mutualmobile/MMDrawerController
MMDrawerController is highly configurable and does all the things you mention:
support for left and right controllers
preloads side controllers
"dragging" open with a gesture
If you're using a storyboard you can use this extension to have storyboard support: https://github.com/TomSwift/MMDrawerController-Storyboard
EDIT:
Another option might be to use a UIPageViewController with a transition style of UIPageViewControllerTransitionStyleScroll: https://developer.apple.com/library/ios/documentation/uikit/reference/UIPageViewControllerClassReferenceClassRef/UIPageViewControllerClassReference.html
This will have the behavior of "pulling" in the side view controllers vs. "uncovering" them.
EDIT 2: example per request
The only real complicating requirement you have is that the same view controller is used for both left and right. That means we have to track where the view controller is being presented so that we can correctly manage our data source. Without this requirement we could just back our data source with an array and derive next/prev from that.
First, the storyboard. The storyboard has three view controllers: 1) the UIPageViewController, which I've subclassed as TSPageViewController. Don't forget to set the page controller transition-style property to 'scroll'. 2) the "center" view controller, and 3) the "side" view controller. For center and side I've set the storyboard ID of each to "center" and "side", respectively. For this sample, both the center and side controllers are plain vanilla UIViewControllers, and I've set their view backgroundColor's to tell them apart.
Second, the page view controller:
.h
#interface TSPageViewController : UIPageViewController
#end
.m
#interface TSPageViewController () <UIPageViewControllerDataSource>
#end
#implementation TSPageViewController
{
UIViewController* _side;
UIViewController* _center;
}
- (void) viewDidLoad
{
[super viewDidLoad];
self.dataSource = self;
_side = [self.storyboard instantiateViewControllerWithIdentifier: #"side"];
_center = [self.storyboard instantiateViewControllerWithIdentifier: #"center"];
[self setViewControllers: #[_center]
direction: UIPageViewControllerNavigationDirectionForward
animated: NO
completion: nil];
}
- (UIViewController*) pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
if ( viewController == _center )
{
_side.title = #"right";
return _side;
}
if ( viewController == _side && [_side.title isEqualToString: #"left"] )
{
return _center;
}
return nil;
}
- (UIViewController*) pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
if ( viewController == _center )
{
_side.title = #"left";
return _side;
}
if ( viewController == _side && [_side.title isEqualToString: #"right"] )
{
return _center;
}
return nil;
}
#end
Again, the only thing here that's special is the tracking of the whether the side controller is currently "left" or "right". This implementation has an issue in that it relies on the behavior of the UIPageViewController to not "page ahead" and cache view controllers (if it did, our logic would get confused). So you might want to consider a more robust mechanism to track which side the view controller is currently on. For that you'd likely have to introduce your own swipe gesture recognizer and use the data from that to drive tracking left/right.
If you can toss your requirement of using the same view controller for left and right, then you can have separate left/right/center controllers, stored in an array, and return next/prev controllers based on what you see in the array. Much easier and more robust!
for iOS6+:
I'd be inclined to use https://github.com/pkluz/PKRevealController and just set both left and right viewControllers to be pointers to a single viewController.
for iOS7+:
I think you should be looking into custom UIViewController transitions.
https://github.com/ColinEberhardt/VCTransitionsLibrary
http://www.teehanlax.com/blog/custom-uiviewcontroller-transitions/
There is a good WWDC 2013 video on this subject entitled "Custom transitions using view controllers", it's session 218.
You can accomplish that with some of the cocoa controls such as:
https://github.com/Inferis/ViewDeck
https://github.com/gotosleep/JASidePanels
EDIT: Proposal number two, use a controller with a scrollView:
// Allocate all the controlelrs you need
MyFirstViewController *first = [[MyFirstViewController alloc] init];
MySecondViewController *second= [[MySecondViewController alloc] init];
MyThirdViewController *third = [[MyThirdViewController alloc] init];
// Adjust the frames of the controllers
first.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
second.view.frame = CGRectMake(0, self.view.frame.size.width, self.view.frame.size.width, self.view.frame.size.height);
third .view.frame = CGRectMake(0, 2 * self.view.frame.size.width, self.view.frame.size.width, self.view.frame.size.height);
// Add controllers as subViews to the scrollView
[self.scrollView addSubview:self.first.view];
[self.scrollView addSubview:self.second.view];
[self.scrollView addSubview:self.third.view];
// Set the scrollView contentSize and paging
self.scrollView.contentSize = CGRectMake(self.view.frame.size.width * 3, self.view.frame.size.height);
self.scrollView.pagingEnabled = YES;
// Scroll to the middle view initally
[self.scrollView scrollRectToVisible:CGRectMake(0, self.view.frame.size.width, self.view.frame.size.width, self.view.frame.size.height) animated:NO];
The code above is written by heart, I have probably named a few things wrongly, and there is more than one way to handle the subviews. The mentioned pageViewController in the comments will work as well.
What you are looking to do sounds a lot like the iPhone version of Apple's UIPageControl Demo;
Sounds like a job for UISwipeGestureRecognizer.

Changing between Views in iOS

I am making my first iOS application, it is for the iPad. It is a memorization game. It has cover page with a couple of options and depending on the option you choose it sends you different page/view. Throughout the application, the user will be traveling through different pages/views. The entire interface for the application will be custom made, so i want have the navigation bars or anything. I am using xCode 3.2.5. I have created the views in the interface builder. And I have attached the cover page to the app, so after the splash page it appears.
How do I go about switching between views?
Thanks for any help you can give me.
Edit 1:
Here is some code that I think is pertinent
This is the AppDelegate.m file, I left out the methods I did not edit
#synthesize coverController=_coverController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
cover *aCoverController = [[cover alloc] initWithNibName:#"cover" bundle:nil];
self.coverController = aCoverController;
// Or, instead of the line above:
// [self setcover:aCoverController];
[aCoverController release];
self.window.rootViewController = self.coverController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)dealloc {
[managedObjectContext_ release];
[managedObjectModel_ release];
[persistentStoreCoordinator_ release];
[_coverController release];
[window release];
[super dealloc];
}
Ok. 1stly can you be a little more clearer about what you want.
From what I got was, you are not looking to navigate in/out of controllers, you just have few views prepared for your RootViewController, and then you want to switch between them.
Navigation controller is used when you have a sequential flow of views, as in moving from view1 'leads to' view2, and so on. eg- a contactsBook-->contactDetails-->editContact--> so on ..
But it feels, in your case, the views/pages are separate and have no connection whatsoever, so there wont be any sequential flow, but a random flow of say view1-->view5-->view2--> ..
If that is the case, if you have already build the views, you just need to connect each of them with their parentController(coverController in your case).
Simplest way would be - lets say you have 3 views, view1 view2 view3, each having 1 or more buttons to switch b/w views.
1 way would be to have a reference of the coverController, in each of the views. There are more elegant methods possible, but this 1 will be the easiest to understand and implement.
So, in view1.h(add these) :
import "cover.h"
#class cover;
#interface view1 : UIView {
cover *coverController;
}
#property(nonatomic, assign)cover *coverController;
#end
And in cover.h, add
import "view1.h"
#class view1;
#interface cover : UIViewController{
IBOutlet view1 *firstView;
}
#property(nonatomic, retain) IBOutlet view1 *firstView;
#end
Finally in cover.m, add
#implementation cover
#synthesize view1;
and in 'viewDidLoad' method in cover.m, add 2 lines
self.view1.frame = CGRectMake(0,0,768,1024); //set whatever frame you want
self.view1.coverController = self; //concept of reference-paring
And done.
in the view1ButtonPressed method of view1 -
-(IBAction)view1ButtonPressed{
// remove the current view from the superview
[self removeFromSuperView];
//go to superView, to load anotherview
[coverController view1ButtonWasPressed];
}
in cover.m :
-(void)view1ButtonWasPressed{
//after doing the same process for view2
[self.view addSubview:view2];
}
If you have made the correct connections, in you nib files, you ll achieve what you set out to do.
Concept is simple, what we are doing is - on click on the button, we remove the current view from superview, go to the super view itself(which is the controller's view only), and add as a subview some other view of our choice.
There is only 1 controller, and many views, and we are switching in b/w those views.
You should use a navigation controller, it's the simplest way of structuring an app with multiple views. There's nothing that says you have to show the navigation bar and you can create custom buttons which push and pop views on and off of the stack.
I've been playing with different ways of doing this and it's just not worth the effort. I strongly recommend the navigation controller.
This tutorial helped me get my head round it, but try googling to find what works best for you.

Resources