Choppy Paging UIScrollView Experience - ios

I'm interested in implementing a paging UIScrollView experience, very similar to the current Twitter app, where there is a main paging UIScrollView (horizontal scrolling) at the top of the view hierarchy, and several other (vertical scrolling) UIScrollViews or UITableViews as the paging UIScrollView's subview.
I was taking reference from this WWDC video where they described how we could add a/several "zooming" scrollViews as a subview of a bigger "paging" scrollView.
In my current setup, I have:
A ViewController in storyboard with hierarchy as follows: View > ScrollView (contentScrollView) > Several subviews (UIImageViews, UIButtons and UILabels).
When that view is being loaded, I call a method setupPagingScrollView method in its viewDidAppear.
- (void)setupPagingScrollView
{
// Setup the PAGING UIScrollView
self.pagingScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 340, self.view.frame.size.height)];
self.pagingScrollView.contentSize = CGSizeMake(680, self.view.frame.size.height);
self.pagingScrollView.pagingEnabled = YES;
self.pagingScrollView.backgroundColor = [UIColor blackColor];
// Remove the CONTENT UIScrollView (from storyboard) from the view.
// Add the CONTENT UIScrollView (from storyboard), as a subview of the newly created PAGING UIScrollView
[self.contentScrollView removeFromSuperview];
[self.pagingScrollView addSubview:self.contentScrollView];
[self.view addSubview:self.pagingScrollView];
// Create the 2nd page, which is a UITableView
self.tableView = ({
UITableView *tableView = [[UITableView alloc] initWithFrame:CGRectMake(340, 0, 320, self.view.frame.size.height) style:UITableViewStylePlain];
tableView.delegate = self;
tableView.dataSource = self;
tableView.backgroundColor = [UIColor whiteColor];
tableView.tableFooterView = [UIView new];
tableView.contentInset = UIEdgeInsetsMake(50, 0, 0, 0);
tableView;
});
[self.pagingScrollView addSubview:self.tableView];
// UINavigationBar for the UITableView in the 2nd page.
self.likesCommentsNavBar = ({
UINavigationBar *navBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(340, 0, 320, 44)];
UINavigationItem *navItem = [[UINavigationItem alloc] init];
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:#[#"Likes", #"Comments"]];
[segmentedControl addTarget:self action:#selector(toggleLikesCommentsWithSegmentedControl:) forControlEvents:UIControlEventValueChanged];
segmentedControl.selectedSegmentIndex = 0;
navItem.titleView = segmentedControl;
navBar.items = #[navItem];
navBar;
});
[self.pagingScrollView addSubview:self.likesCommentsNavBar];\
}
My intended end result would be something like the twitter application, just that instead of panning between 3 UITableViews, my first view would be a custom view with some images, labels, and buttons, and the 2nd and 3rd page would be UITableViews.
I have created a mockup of my intended result
Currently, I am able to get the result I want but I realize that there is some choppiness in the performance. Am I doing something wrong here by allocating memory to so many views or something?
Many thanks!

Incase the image loading on the main thread is the problem here, here is an easy way to load images on a background thread
UIImageView *imageView = [[UIImageView alloc] init]; // can be your IBOutlet or something instead
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
UIImage *image = [UIImage imageNamed:#"imageName"];
dispatch_sync(dispatch_get_main_queue(), ^{
imageView.image = image; //can add some fade in animation or something here too
});
});

Related

iOS UIPageViewController with background

I have a container UIViewController (IntroViewController), in which I load a UIPageViewController (PageViewController). In the UIPageViewController, I have IntroPageContentViewControllers and a LastIntroPageContentViewController.
I want to have a background image in the UIPageViewController. If I put it in IntroViewController, it isn't viewable. I can't put it in the UIPageViewController, and when I put it in one of the ContentViewControllers it scrolls in and out with each page. I want it to be in one place and only scroll the content.
Where do I put the UIImageView and where should I bringSubviewToFront or something alike?
Simply put the UIImageView into container UIViewController and set view.backgroundColor property to [UIColor clearColor] for both content view controllers.
Here you have an example how it works:
https://github.com/Wojdan/stackAnswers/tree/master/33912671
UIView *view = [[UIView alloc] init];
view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
UIImageView *imageView1 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"login_backgroung"]];
imageView1.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
[view addSubview:imageView1];
// Create page view controller
self.pageViewController = [self.storyboard
instantiateViewControllerWithIdentifier:#"PageViewController"];
self.pageViewController.dataSource = self;
self.pageViewController.view.backgroundColor = [UIColor clearColor];
[self.pageViewController.view insertSubview:view atIndex:0];
UIPageControl *pageControl = [UIPageControl appearance];
pageControl.pageIndicatorTintColor = [UIColor whisperWhite];
pageControl.currentPageIndicatorTintColor = [UIColor whisperDarkGray];
pageControl.backgroundColor = [UIColor clearColor];
Ideally, You should be adding UIPageViewControlleras child of it parentViewController. In your case IntroViewController is parent and PageViewController will become child of it.
Now, you set IntroViewController background colour from image like below :
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"background"]];
And then, you can clear background colours for content view controllers which are you planning to add into UIPageViewController.
However, you may have to comment below delegate to remove page control from bottom of `UIPageViewController'
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
{
}
Hope this helps.

how to make parallax demo with three tab like image give below

How to make parallax demo with three tab like image given below in iOS make scrolling vertically.and click on tab multiple table scrolling Horizental.
Try using a UIScrollView with paging enabled. Then connect an IBAction to the buttons with a tag value to it. The tag value indicates which page the UIScrollView has to show. Make sure the UIScrollView direction is set to horizontal. In this example I'm only adding UIViews but this could be anything. UITableView, UIScrollView or UICollectionView you name it.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//Set number of pages
int numberOfPages = 3;
//Set properties scrollView
self.scrollView.pagingEnabled = true;
self.scrollView.contentSize = CGSizeMake((numberOfPages * self.scrollView.frame.size.width), self.scrollView.frame.size.height);
//Add pages
UIView *pageOne = [[UIView alloc] initWithFrame:CGRectMake((0 * self.scrollView.frame.size.width), 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height)];
[pageOne setBackgroundColor:[UIColor yellowColor]];
[self.scrollView addSubview:pageOne];
UIView *pageTwo = [[UIView alloc] initWithFrame:CGRectMake((1 * self.scrollView.frame.size.width), 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height)];
[pageTwo setBackgroundColor:[UIColor blueColor]];
[self.scrollView addSubview:pageTwo];
UIView *pageThree = [[UIView alloc] initWithFrame:CGRectMake((2 * self.scrollView.frame.size.width), 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height)];
[pageThree setBackgroundColor:[UIColor redColor]];
[self.scrollView addSubview:pageThree];
}
- (IBAction)btnSelectPage:(id)sender; {
UIButton *btn = (UIButton *)sender;
[self.scrollView setContentOffset:CGPointMake((self.scrollView.frame.size.width * btn.tag), 0) animated:true];
}
And for the storyboard do something like this:
Don't forget to set the tag value of the button indicating what page you would like to show.

Page control on subview

I am creating a view with a subview for a tutorial screen.
I want the gray subview to be swipeable using the page control
I have implemented the example of http://www.appcoda.com/uipageviewcontroller-tutorial-intro/ but this works with whole ViewControllers and I want it to work with only the subview...
Does anyone have any idea how to implement the PageControl with the swipe gesture so that only the gray subview changes? Any good tutorial?
The grey area must be a UIScrollView with a content view containing each page of the tutorial. Set pagingEnabled to YES on your scroll view so that it will snap to each page when you scroll.
Then you need to attach an action to the page control using addTarget:action:forControlEvents: and pass UIControlEventValueChanged as the event. Then the action must be a method that tells the scroll view to move forward or back a page depending on whether the value of the page control increased or decreased. You can do this by changing the scroll view's content offset, or by telling it to scroll so that a particular rect is visible.
Finally, implement the delegate of the UIScrollView, and use the methods that tell when the scroll view stopped scrolling (you'll need a combination of the did end decelerating, did end dragging and possibly did end scrolling animation), and update the page control's value when the scroll view changes pages.
And that's all there is to it. If you need more details, read the documentation for UIScrollView, UIScrollViewDelegate and UIPageControl.
use UIView instead of ViewController
Here is a solution that works for me:
1) Create a scrollView and pageControl in your NIB or Storyboard
2) scrollView in ViewDidLoad
self.scrollView.backgroundColor = [UIColor clearColor];
self.scrollView.indicatorStyle = UIScrollViewIndicatorStyleBlack; //Scroll bar style
self.scrollView.showsHorizontalScrollIndicator = NO;
//dont forget to set delegate in .h file
[self.scrollView setDelegate:self];
self.scrollView.showsVerticalScrollIndicator = YES; //Close vertical scroll bar
self.scrollView.bounces = YES; //Cancel rebound effect
self.scrollView.pagingEnabled = YES; //Flat screen
self.scrollView.contentSize = CGSizeMake(640, 30);
3) create your views you want in the scrollView and add them in an Array
//For instance, you want 3 views
UIView *ViewOne = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height)];
[ViewOne setBackgroundColor:[UIColor redColor]];
UIView *ViewTwo = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.scrollView.frame.size.width+1, self.scrollView.frame.size.height)];
[ViewTwo setBackgroundColor:[UIColor greenColor]];
UIView *ViewThree = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.scrollView.frame.size.width+2, self.scrollView.frame.size.height)];
[ViewThree setBackgroundColor:[UIColor blueColor]];
//add all views to array
NSMutableArray *viewsArray = [[NSMutableArray alloc] initWithObjects:ViewOne, ViewTwo, ViewThree, nil];
4) pageControl in ViewDidLoad
self.pageControl.numberOfPages = viewsArray.count;
self.pageControl.currentPage = 0;
self.pageControl.backgroundColor = [UIColor clearColor];
[self.pageControl setTintColor:[UIColor whiteColor]];
5) Add it all up
for(int i = 0; i < viewsArray.count; i++)
{
CGRect frame;
frame.origin.x = (self.scrollView.frame.size.width *i) + 10;
frame.origin.y = 0;
frame.size = CGSizeMake(self.scrollView.frame.size.width - 20, self.scrollView.frame.size.height);
NSLog(#"array: %#", [viewsArray objectAtIndex:i]);
UIView *view = [[UIView alloc] initWithFrame:frame];
view = [viewsArray objectAtIndex:i];
[self.scrollView addSubview:view];
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width*viewsArray.count, self.scrollView.frame.size.height);
}
6) Track the scrollView and update the pageControl (DONT FORGET THE SCROLLVIEW DELEGATE)
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
CGFloat pageWidth = scrollView.frame.size.width;
//int page = floor((scrollView.contentOffset.x - pageWidth*0.3) / pageWidth) + 1);
self.pageControl.currentPage = (int)scrollView.contentOffset.x / (int)pageWidth;
NSLog(#"CURRENT PAGE %d", self.pageControl.currentPage);
}
This should do the trick.
PS. Sorry for all the magic numbers.

Adding UISearchBar to UITableView

Background: I have a UIViewController which has a UITableView added programmatically. At the top of the UITableView I have a tablHeaderView in which I have placed a UIView. This UIView has a UISearchBar and a segmentedControl. The idea being: that a user can sort the UITableView by some basic categories such as 'Date/Time' or 'Location' etc. They can also search by an item in the programme.
Problem: When I tap the search bar it resizes (which I don't want) and then when I cancel the search it resizes again and stays there until the UIViewController is exited and loaded again.
Code:
-(void)loadTableView
{
usableSpace = [[UIScreen mainScreen] applicationFrame];
usableWidth = usableSpace.size.width;
usableHeight = usableSpace.size.height;
_tableView = [[UITableView alloc] init];
[_tableView setFrame:CGRectMake(0,0,usableWidth, usableHeight)];
[_tableView setDataSource:self];
[_tableView setDelegate:self];
[self.view addSubview:_tableView];
_searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, usableWidth, 44)];
_searchBar.showsCancelButton = YES;
NSLog(#"searchBar height = %fl", _searchBar.frame.size.height);
segmentedControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"Date/Time", #"Location", #"Speaker", nil]];
segmentedControl.frame = CGRectMake(0, (_searchBar.frame.size.height), usableWidth, (usableHeight * 0.075));
[segmentedControl addTarget:self action:#selector(sortList) forControlEvents:UIControlEventValueChanged];
searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:_searchBar contentsController:self];
searchDisplayController.delegate = self;
searchDisplayController.searchResultsDataSource = self;
searchDisplayController.searchResultsDelegate = self;
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, usableWidth, (usableHeight * 0.15))];
[headerView addSubview:_searchBar];
[headerView addSubview:segmentedControl];
_tableView.tableHeaderView = headerView;
[self.view addSubview:_tableView];
self.tableView = _tableView;
}
What I have tried: I have tried setting the size of the SearchBar, not setting its size. Not having it in a UIView in the tableHeaderView, instead just having it there on its own.
Why does it resize at all and how can I get it to stop?
EDIT: I have just tried the following: In storyboard (where the UIViewController was originally created) I have selected the UIVC in question and in attributes inspector I deselected 'Under Top Bars' and 'Under Bottom Bars' and this appears to have fixed the first part of the animation problem. Now, when I tap in the search bar, the search becomes active but the searchBar does NOT resize. However, when I cancel the searchBar the searchBar still animates and resizes as per the last image in my screenshot. What could be causing THAT resizing?
i've been banging my head on this for too freakin long... props to this dude here for the clues.
if you want your UISearchBar to be in the header along with other views and to scroll with the header instead of sticking at the top, then you've got to remove it and re-add it after the search completes. to be clear, build your header like you already do and then throw this in there as well to handle the screwy animations.
-(void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller {
[self.mySearchBar removeFromSuperview];
self.mySearchBar.frame = CGRectMake(0, 0, 320, 44);
[self.table.tableHeaderView addSubview:self.mySearchBar];
}
As Timothy Moose notes here, "It seems that UISearchDisplayController makes an undocumented assumption that the search bar is the only content of the header view"
...yay apple.
Ok, after hours of reading up and trying different things I think I have found out how to have a UISearchBar where I want it and it seems to work ok. I believe the problem was to do with either having multiple views in the tableHeaderView OR the UISearchBar did not like being with another view inside a 'containing' view.
Here is the code I ended up with that allowed me to have a segmentedControl at the top of my UITableView AND a UISearchBar which actually sat at the top of my UIView (to which the UITableView was added).
-(void)loadTableView
{
usableSpace = [[UIScreen mainScreen] applicationFrame];
usableWidth = usableSpace.size.width;
usableHeight = usableSpace.size.height;
_tableView = [[UITableView alloc] init];
[_tableView setFrame:CGRectMake(0,0,usableWidth, usableHeight)];
[_tableView setDataSource:self];
[_tableView setDelegate:self];
[self.view addSubview:_tableView];
_searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, usableWidth, 44)];
[_searchBar setShowsCancelButton:YES];
NSLog(#"searchBar height = %fl", _searchBar.frame.size.height);
segmentedControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"Title", #"Date/Time", #"Speaker", nil]];
segmentedControl.frame = CGRectMake(0, (_searchBar.frame.size.height), usableWidth, (usableHeight * 0.075));
segmentedControl.selectedSegmentIndex = 0;
[segmentedControl addTarget:self action:#selector(sortList) forControlEvents:UIControlEventValueChanged];
searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:_searchBar contentsController:self];
searchDisplayController.delegate = self;
searchDisplayController.searchResultsDataSource = self;
searchDisplayController.searchResultsDelegate = self;
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, usableWidth, (usableHeight * 0.15))];
[headerView addSubview:segmentedControl];
_tableView.tableHeaderView = headerView;
[self.view addSubview:_tableView];
[self.view addSubview:_searchBar];
self.tableView = _tableView;
}
This meant that I had:
UIViewController with a UINavigationController, UISearchBar, UITableView. The UITableView had a segmentedConrol. The UISearchBar sits just under the UINavigationController and is always present. The UISearchBar sits at the top of the UITableViewController and scrolls with the UITableViewCells.
If anyone knows why the UISearchBar acted as it did in the question then I would be grateful if they could leave a comment. I know that this problem (or very similar) has been experienced by MANY people and I haven't found a definitive answer anywhere.

How to enable zoom for two different UIScrollview in single UIView?

I am displaying two images on single view where both images must have zoom functionality.My page height is around 1000 pixels and images must be display on top and bottom of page. For that I have added two different scroll view and added image views on scroll views.
Now Zoom is working properly for second image .But first image is getting displayed in top left corner of scroll view once zoomed out. It seems there are two images.
Here is the delegate method i am using:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
return [[scrollView subviews] objectAtIndex:0];
}
Is there anything i am missing ? or is this not really possible to enable zoom when there are two scroll views for single page.
Here is the code its working for enable zoom when there are two scroll views for single page.
//Create First ImageView
image1 =[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 320, 220)];
image1.image = [UIImage imageNamed:#"image1.png"];
image1.contentMode = UIViewContentModeScaleToFill;
//Create and Set Values for Scrollview 1
scroll1 =[[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 220)];
scroll1.contentSize = image1.frame.size;
[scroll1 setMinimumZoomScale:1.0];
[scroll1 setMaximumZoomScale:4.0];
scroll1.delegate = self;
scroll1.clipsToBounds = YES;
scroll1.tag =0;
[scroll1 addSubview:image1];
image1.userInteractionEnabled =YES;
scroll1.zoomScale = 1;
[self.view addSubview:scroll1];
Second Scrollview and ImageView
// Create Second ImageView
image2 =[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 320, 260)];
image2.image = [UIImage imageNamed:#"image2.png"];
image2.contentMode = UIViewContentModeScaleToFill;
// Create Second ScrollView
scroll2 =[[UIScrollView alloc] initWithFrame:CGRectMake(0, 220, 320, 260)];
scroll2.contentSize = image2.frame.size;
[scroll2 setMinimumZoomScale:1.0];
[scroll2 setMaximumZoomScale:4.0];
scroll2.delegate = self;
scroll2.clipsToBounds = YES;
scroll2.tag =1;
[scroll2 addSubview:image2];
image2.userInteractionEnabled =YES;
scroll2.zoomScale = 1;
[self.view addSubview:scroll2];
This will help you, since it is already working for me.
Delegate method as follow:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
if (scrollView.tag ==0) {
return image1;
}
else return image2;
}

Resources