I have successfully created a "tutorial" pages that will show up at the first time user open the app. And i am facing the problem on how to move to another "branch" of view controllers in my storyboard.
So basically I have two main flows in my storyboard:
1. Page View Controllers
2. Main app view controllers
As you can see from screenshot below
So, the question is, how to move to my main app flow after the user clicked on the skip button from my UIPageViewController?
In my tutorial page view controller, i have this code to set the page view controllers
- (void)viewDidLoad {
[super viewDidLoad];
self.arrPageTitles = #[#"A",#"B",#"C"];
self.arrPageImages =#[#"1.jpg",#"2.jpg",#"3.jpg"];
// Create page view controller
self.PageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"pageViewController"];
self.PageViewController.dataSource = self;
TutorialPageContentViewController *startingViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = #[startingViewController];
[self.PageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
// Change the size of page view controller
self.PageViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 30);
[self addChildViewController:self.PageViewController];
[self.view addSubview:self.PageViewController.view];
[self.PageViewController didMoveToParentViewController:self];
}
Or is there any better approach to achieve this? Is my design wrong?
I have searching for any clue but can't find any. Thanks!
First of all I'd recommend you to use different storyboards for Tutorial flow and for main app screens. It's very hard to store everything in single storyboard: you will get some mess when project will have at least 20-30 view controllers.
And you can replace root view controller at any time using this code:
let storyboard = UIStoryboard(name: "<storyboard_name>", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "<vc_name>")
UIApplication.shared.keyWindow?.rootViewController = viewController
Related
I need advice to create user interface like this UI.
Is it better to use UITableView or UICollectionView because its display is row based? But, when I swipe left and right, it has different section like the collection view horizontal scroll. It makes me confused because I have never created such a UI. I prefer to use UITableViewController, but when I see the segment, I can't use segmented controller because I can't swipe to change the filter.
1) Create storyboard view controller (UIViewController). Controller's view has two subviews: title view and container view (two IBOutlet views).
2) Title view - it's a top view (in your case - collection view with items).
Container view - it's a view for pageViewController.
You will do something like this:
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll
navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
options:nil];
self.pageViewController.dataSource = self;
self.pageViewController.delegate = self;
[self.pageViewController setViewControllers:#[[self viewControllerForIndex:index]]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
[self addChildViewController:self.pageViewController];
[self.containerView addSubview:self.pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
- (UIViewController *)viewControllerForIndex:(NSUInteger)index {
UITableViewController *vc = [[UITableViewController alloc] init];
return vc;
}
in my app i am trying to make a slider using the LWSlideShow LWSlideShow
the source of images are fetched from my server after trying the solution here i stuck with error that said unbalanced call and it means that i am presenting a modal view on a view that did not completed his animation after solving this problem by putting animation to no the splashView that i present will be dismissed before the images are downloaded here is my code for further explanation:
- (IBAction)goDownload {
UIViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"Splash"];
[self.navigationController presentViewController:vc animated:YES completion:nil];
dispatch_async(dispatch_get_main_queue(), ^{
NSMutableArray *array = [#[] mutableCopy];
LWSlideItem *item = [LWSlideItem itemWithCaption:#""
imageUrl:#"http://code-bee.net/geeks/images/cover-1.jpg"];
[array addObject:item];
item = [LWSlideItem itemWithCaption:#""
imageUrl:#"http://code-bee.net/geeks/images/cover-2.jpg"];
[array addObject:item];
item = [LWSlideItem itemWithCaption:#""
imageUrl:#"http://code-bee.net/geeks/images/cover-3.jpg"];
[array addObject:item];
LWSlideShow *slideShow = [[LWSlideShow alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), 120)];
slideShow.autoresizingMask = UIViewAutoresizingFlexibleWidth;
//slideShow.delegate = self;
[self.view addSubview:slideShow];
slideShow.slideItems = array;
if ([slideShow.slideItems count] == [array count]) {
[self dismissViewControllerAnimated:YES completion:nil];
}
});
}
//
//-(void)viewWillAppear:(BOOL)animated
//{
//
// UIViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"Splash"];
// [self.navigationController presentViewController:vc animated:YES completion:nil];
//}
- (void)viewDidLoad {
[super viewDidLoad];
[self goDownload];
}
also you can see from the code that also i try to use viewWillAppear same thing happened what i want is when the images are downloaded the splashView need to be dismissed i dont know what i am doing wrong
Running that code from a VC anytime before viewDidAppear (like viewDidLoad, viewWillAppear) will cause the problem you describe. But you probably don't want the slide show view to appear - even for an instant - until you're done fetching the assets. This is a common problem.
The solution is to realize that the "splash screen" and the network tasks aren't just preamble, they are as much a part of your application as the slide show.
EDIT
Make that Splash vc the app's initial view controller in storyboard. Right now, the slide show vc probably looks like this:
Uncheck the "Is Initial View Controller" checkbox, find your splash view controller (in the same storyboard, I hope) and check it's box to be the initial view controller. Now your app will start up on the splash vc, like you want it.
When the splash vc done, it can present the slide show vc, or it can even replace itself (with the slide show ) as the app window's root.
To replace the UI, I use variations of this snippet...
// in the splash vc, after all of the asset loading is complete
// give what used to be your initial view controller a storyboard id
// like #"MySlideShowUI"
UIViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"MySlideShowUI"];
UIWindow *window = [UIApplication sharedApplication].delegate.window;
window.rootViewController = vc;
[UIView transitionWithView:window
duration:0.3
options:UIViewAnimationOptionTransitionCrossDissolve
animations:nil
completion:nil];
I am trying to use UIPageViewController to create walkthrough screens with three separate UIViewControllers. As a summary, I have four View Controllers and a Page View Controller in my storyboard. One view controller act as base view (XYZViewController.h/m) and other three act as sub views that loads inside base view controller. Below shows how the XYZViewController.h displays roughly.
#import <UIKit/UIKit.h>
#import “XYZPageContentViewController.h"
#import "XYZPageTwoContentViewController.h"
#import "XYZPageThreeContentViewController.h"
#interface XYZViewController : UIViewController <UIPageViewControllerDataSource>
#property (strong, nonatomic) UIPageViewController *pageViewController;
#end
Following code snippet shows the viewDidLoad method of XYZViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageViewController"];
self.pageViewController.dataSource = self;
XYZPageContentViewController *startingViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = #[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
self.pageViewController.view.frame = CGRectMake(0, 60, self.view.frame.size.width, self.view.frame.size.height - 60);
[self addChildViewController:_pageViewController];
[self.view addSubview:_pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
bottomView.layer.zPosition = 1;
startBtnOutlet.layer.zPosition = 1;
}
Actually, loading sub views and walkthrough is working perfectly. What is not working is, the button touch up inside event I have declared in base view.
As you can see with the image, there is "Start again" button at the bottom of the screen. At first that view even didn't display when I set page controller view till bottom of the screen and not using z-index option.
Which means having this line
self.pageViewController.view.frame = CGRectMake(0, 60, self.view.frame.size.width, self.view.frame.size.height - 60);
with commenting following lines.
// bottomView.layer.zPosition = 1;
// startBtnOutlet.layer.zPosition = 1;
What I need is limit the page view controller where the gray view begins and available the sub view till end of the screen. I can limit the page view controller frame as mentioned above, then it is apply to my all walkthrough screens as well. What can I do for that?
I have followed this tutorial. Is there any better way to do this?
Found the solution.
Keep comment below lines of codes.
// bottomView.layer.zPosition = 1;
// startBtnOutlet.layer.zPosition = 1;
Add this line below that code, inside viewDidLoad method
[self.view sendSubviewToBack:_pageViewController.view];
I have an ipad app.
I am trying to open view 2 (kind of push view) full with entire screen. how normally do with push view or UIModalPresentationFullScreen. but my base view which is view 1 is also modal view.
so i was trying to open view 2 when view 1 get dismiss…
- (void) handleNewButton :(int)id
{
[self dismissViewControllerAnimated:YES
completion:^{
NewViewController *View2 = [NewViewController alloc] init];
View2.modalPresentationStyle = UIModalPresentationFullScreen;
View2.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController: View2 animated:YES completion:nil];
}];
}
but my view 2 is not opening. i know i can not do push view. But is there any way to achieve it?.
When you do this dismissViewControllerAnimated the UIViewController (self in this case) is gone, in the sense that he is not on the screen anymore, if it has been released or not, that's another story. The reason for you to not be able to show the View2 (very poor name, it should at least ViewController2) is because you are trying to show it from a UIViewController that is not on the screen anymore.
So, what can you do?
The current self in the context of the handleNewButton method, in theory was presented by another UIViewController, that's from where you want to present your View2.
Probably the quickest way of implementing of what I said, would probably be with a notification described here. Although I would do it with a block, so when the self would be created, I would pass a dismissiCompletionBlock that would be called when that UIViewController was dismissed.
try to allocate NewViewController with nib name if you are not using storyboard,
[self dismissViewControllerAnimated:YES
completion:^{
NewViewController *n=[[NewViewController alloc]initWithNibName:#"NewViewController" bundle:nil];
View2.modalPresentationStyle = UIModalPresentationFullScreen;
View2.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController: View2 animated:YES completion:nil];
}];
or if you are using storyboard get NewViewController using identifier.
For an app I am creating I started out with a standard Tabbed Application Template. From there I implemented a tutorial for a UIPageViewController and all work correctly together. However now I want to start using Segue's as this makes the app better understandable in my opinion. Problem here is I really don't know how to make this work.
The following code is now used to create the viewControllers from the UIStoryBoard
- (IBAction)goToTables:(id)sender {
[super viewDidLoad];
// Create page view controller
self.weightPageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"WeightPageViewController"];
self.weightPageViewController.dataSource = self;
WeightPageContentViewController *startingViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = #[startingViewController];
[self.weightPageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
[self addChildViewController:_weightPageViewController];
[self.view addSubview:_weightPageViewController.view];
[self.weightPageViewController didMoveToParentViewController:self];
}
What I am looking for is the code which can be used to do the same but then in a Segue, as I cannot get to a point where it works.
In the storyboard you create a segue between 2 viewControllers, give the segue a name and then call the following:
[self performSegueWithIdentifier:#" <Segue-Name> " sender:self];
there is also a callback:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
which will give you access to the destination viewController to pass data, call functions etc