How can I make UIScrollView/UIPageControl infinite? - ios

I have created a simple image scrolling with UIPageControl and UIScrollView, I have three pages ! so what I need is when user scrolls page 0 to left , actually scroll should move to the page 3 and vice versa . I have checked Apple sample code but it was so complicated !, here is my codes :
- (void)setupScrollView {
_pageControl.currentPage = 0;
_pageControl.numberOfPages = 3;
[_scrollView setContentSize:CGSizeMake(_scrollView.frame.size.width * _pageControl.numberOfPages, _scrollView.frame.size.height)];
_scrollView.delegate = self;
[self createPageWithImage:_image1 forPage:0];
[self createPageWithImage:_image2 forPage:1];
[self createPageWithImage:_image3 forPage:2];
}
- (void)createPageWithImage:(UIImageView *)frameImage forPage:(int)page
{
UIView *newView = [[UIView alloc] initWithFrame: CGRectMake(_scrollView.frame.size.width * page, 0, _scrollView.frame.size.width, _scrollView.frame.size.height)];
[newView addSubview: frameImage];
[_scrollView addSubview: newView];
}
- (void)scrollViewDidScroll: (UIScrollView *) sView
{
CGFloat offset = _scrollView.contentOffset.x;
CGFloat pageSize = _scrollView.frame.size.width;
int page = floor((offset + (pageSize/2)) / pageSize);
_pageControl.currentPage = page;
}
- (IBAction)changeThePage
{
CGRect pageRect = CGRectMake(_pageControl.currentPage * _scrollView.frame.size.width, 0, _scrollView.frame.size.width, _scrollView.frame.size.height);
[_scrollView scrollRectToVisible: pageRect animated: YES];
}

Adding the methods which I have changed. I have commented wherever necessary.
- (void)setupScrollView {
_pageControl.currentPage = 0;
_pageControl.numberOfPages = 3 ;
//Add 2 more pages.
[_scrollView setContentSize:CGSizeMake(_scrollView.frame.size.width * (_pageControl.numberOfPages + 2), _scrollView.frame.size.height)];
_scrollView.delegate = self;
// Seriously recommend this for this type of apps.
_scrollView.pagingEnabled = YES;
// Do not instantiate imageviews. Send only image names as string.
// Add last image at beginning of scroll view.
[self createPageWithImageName:#"imageName3" forPage:0];
// Increase page number of existing images.
[self createPageWithImageName:#"imageName1" forPage:1];
[self createPageWithImageName:#"imageName2" forPage:2];
[self createPageWithImageName:#"imageName3" forPage:3];
//Add first image at end of scroll view
[self createPageWithImageName:#"imageName1" forPage:4];
// Show first image but present in second page.
[_scrollView setContentOffset:CGPointMake(_scrollView.frame.size.width, 0) animated:NO];
}
// Instead of sending image views, send image name. Create image view inside this method.
// This is because, since we are adding two more images, separate image view needs
// to be created. Otherwise, same image view will be used and one added at the end
// will be used as the frame of the image.
- (void)createPageWithImageName:(NSString *)imageName forPage:(int)page
{
UIView *newView = [[UIView alloc] initWithFrame: CGRectMake(_scrollView.frame.size.width * page, 0, _scrollView.frame.size.width, _scrollView.frame.size.height)];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:newView.bounds];
imageView.image = [UIImage imageNamed:imageName];
[newView addSubview: imageView];
[_scrollView addSubview: newView];
}
- (void)scrollViewDidScroll: (UIScrollView *) sView
{
CGFloat offset = _scrollView.contentOffset.x;
CGFloat pageSize = _scrollView.frame.size.width;
int page = floor((offset + (pageSize/2)) / pageSize);
if (page == 0) {
page = _pageControl.numberOfPages - 1;
}
else if (page == _pageControl.numberOfPages + 1) {
page = 0;
}
else {
page = page - 1;
}
_pageControl.currentPage = page;
// If present in scroll view's first page, move it to second last page
if (offset < pageSize) {
[_scrollView setContentOffset:CGPointMake(pageSize * 3 + offset, 0) animated:NO];
}
// If present in scroll view's last page, move it to second page.
else if (offset >= pageSize * (_pageControl.numberOfPages + 1)) {
CGFloat difference = offset - pageSize * _pageControl.numberOfPages;
[_scrollView setContentOffset:CGPointMake(difference, 0) animated:NO];
}
}
The method of changeThePage is not needed for this code.
Hope this answer helps you.

Related

Scrolling to specific page using pageControl and ScrollView ios

I know this question has been asked earlier but i am not getting any specific answer to my problem. I am using page control and scrollView to add view controllers and then showing all the pages using swipe. I need to redirect to a particular page on button click. I tried scrollView SetcontentOffet and every other possiblities.
-(void)ScrollToPage:(int)page
{
UIViewController *controller = [self.childViewControllers objectAtIndex:page];
if (controller.view.superview == nil)
{
CGRect frame = self.scrollView.frame;
if (frame.size.width == 0)
{
frame.size.width = self.view.frame.size.width;
frame.size.height = self.view.frame.size.height;
}
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
controller.view.frame = frame;
[scrollView setContentOffset:CGPointMake(frame.origin.x, frame.origin.y) animated:YES];
self.pageControl.currentPage = page;
[self centerScrollViewContents];
[self.scrollView setContentOffset:CGPointMake(frame.origin.x, frame.origin.y)];
[self.scrollView scrollRectToVisible:frame animated:YES];
[self.scrollView addSubview:controller.view];
}
}
I assume that your pages are using your device width closely. Just follow the below steps.
- (void)viewWillAppear:(BOOL)animated {
self.myCurrentPage = 0;
[self setScrollViewPages];
self.scrollView.delegate = self;
}
- (void)setScrollViewPages {
for (int i = 0; i < numberOfPages; i++) {
UIView *myPageView = [[UIView alloc]initWithFrame:(CGRect) {self.view.frame.size.width * i
+ 10.0f,10.0f,self.view.frame.size.width - 20.0f , self.scrollView.frame.size.height-20.0f}];
myPageView.backgroundColor = [UIColor greenColor];
[self.scrollView addSubview:myPageView];
}
}
On Button Clicked
- (IBAction)buttonClicked:(id)sender {
//Pass the requried page, by default I'm passing 4
self.myCurrentPage = 4;
[self updateMyScrollView];
}
And the respective scroll view setting is
- (void)updateMyScrollView {
[self.scrollView setContentOffset:CGPointMake(self.view.frame.size.width *self.myCurrentPage, 0) animated:YES];
self.pageControl.currentPage = self.myCurrentPage;
}
Additionally, your scrollview delegate would be like this...
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{
int pageWidth = self.view.frame.size.width ;
int pageX = self.myCurrentPage*pageWidth - scrollView.contentInset.left;
if (targetContentOffset->x<pageX) {
if (self.myCurrentPage>0) {
self.myCurrentPage--;
}
}
else if(targetContentOffset->x>pageX){
if (self.myCurrentPage < numerOfPages) {
self.myCurrentPage++;
}
}
targetContentOffset->x = self.myCurrentPage*pageWidth-scrollView.contentInset.left;
DLog(#"%ld %d", (long)self.myCurrentPage, (int)targetContentOffset->x);
self.pageControl.currentPage = self.myCurrentPage;
}
Hope this helps....

UIScrollView + PageControl

I have a view controller with outlets of scrollview (initial size: 390, 170) and page control. I need it to display an image per page from my array. But i have unexpected result (see image below).
Images are not full-width and after 2nd page scrollView ends.
Here is code
- (void)viewDidLoad {
[super viewDidLoad];
//Put the names of our image files in our array.
imageArray = [[NSArray alloc] initWithObjects:#"header1.jpg", #"header2.jpg", #"header3.jpg", nil];
[self.articlesPageControll setNumberOfPages:imageArray.count];
for (int i = 0; i < [imageArray count]; i++) {
//We'll create an imageView object in every 'page' of our scrollView.
CGRect frame;
frame.origin.x = 390 * i;
frame.origin.y = 0;
frame.size = self.articlesScrollView.frame.size;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
[imageView setContentMode:UIViewContentModeScaleToFill];
imageView.image = [UIImage imageNamed:[imageArray objectAtIndex:i]];
[self.articlesScrollView addSubview:imageView];
}
//Set the content size of our scrollview according to the total width of our imageView objects.
self.articlesScrollView.contentSize = CGSizeMake(self.articlesScrollView.frame.size.width * [imageArray count], 170);
}
- (void)scrollViewDidScroll:(UIScrollView *)sender
{
// Update the page when more than 50% of the previous/next page is visible
CGFloat pageWidth = self.articlesScrollView.frame.size.width;
int page = floor((self.articlesScrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
self.articlesPageControll.currentPage = page;
}
UPD: 3rd page with image actually exists, but it's impossible to scroll to this page
Thanks in advance!
Solution self.articlesScrollView.contentSize = CGSizeMake(390 * [imageArray count], 170);

Implement UIPageControl vertical scrolling

I am trying to create a UIPageControl with vertical scrolling . By default you can slide only in horizontal direction ,but how can I slide it up to down ?
here is my code :
#pragma mark page control setup
- (void)setupPageScroll {
_pageControl.transform = CGAffineTransformMakeRotation(M_PI /2 );
_pageControl.currentPage = 0;
_pageControl.numberOfPages = 3;
[_scrollView setContentSize:CGSizeMake(_scrollView.frame.size.width * _pageControl.numberOfPages, _scrollView.frame.size.height)];
_scrollView.delegate = self;
[self createPageWithView:_tower1 forPage:0];
[self createPageWithView:_tower2 forPage:1];
[self createPageWithView:_tower3 forPage:2];
}
- (void)createPageWithView:(UIView *)iview forPage:(int)page
{
UIView *newView = [[UIView alloc] initWithFrame:
CGRectMake(_scrollView.frame.size.width * page, 0, _scrollView.frame.size.width, _scrollView.frame.size.height)];
[newView addSubview:iview];
[_scrollView addSubview:newView];
}
- (IBAction)pageChanged:(id)sender {
CGRect pageRect = CGRectMake(_pageControl.currentPage * _scrollView.frame.size.width, 0, _scrollView.frame.size.width, _scrollView.frame.size.height);
[_scrollView scrollRectToVisible: pageRect animated: YES];
}
- (void)scrollViewDidScroll: (UIScrollView *) sView
{
CGFloat offset = _scrollView.contentOffset.x;
CGFloat pageSize = _scrollView.frame.size.width;
int page = floor((offset + (pageSize/2)) / pageSize);
_pageControl.currentPage = page;
}
If You are using interface builder, just set this value as a User Defined Runtime Atrribute.
It works.
http://i.imgur.com/USBf2a9.png

Sample code for ios6 based scrollview with pagination and zooming features for an array of images

Can anybody help me with the sample code for embedding a zoomable scroll view within a paging scroll view so that each page can be zoomed and panned individually?
Also the navigation structure is like tab bar controller --> navigation controller with buttons (on push of the buttons) --> view controller where in the horizontal scrollview of images has to be implemented with pagination and zooming.
Here is the link to the tutorial that I followed: How To Use UIScrollView to Scroll and Zoom Content
The code I've implemented is following:
#import "ViewCorpBrochureController.h"
#interface ViewCorpBrochureController ()
#property (nonatomic, strong) NSArray *pageImages;
#property (nonatomic, strong) NSMutableArray *pageViews;
#property (nonatomic, strong) UIImageView *imageView;
- (void)loadVisiblePages;
- (void)loadPage:(NSInteger)page;
- (void)purgePage:(NSInteger)page;
- (void)centerScrollViewContents;
- (void)scrollViewDoubleTapped:(UITapGestureRecognizer*)recognizer;
- (void)scrollViewTwoFingerTapped:(UITapGestureRecognizer*)recognizer;
#end
#implementation ViewCorpBrochureController
#synthesize scrollView = _scrollView;
#synthesize pageControl = _pageControl;
#synthesize pageImages = _pageImages;
#synthesize pageViews = _pageViews;
#synthesize imageView = _imageview;
- (void)centerScrollViewContents {
CGSize boundsSize = self.scrollView.bounds.size;
CGRect contentsFrame = self.imageView.frame;
if (contentsFrame.size.width < boundsSize.width) {
contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2.0f;
} else {
contentsFrame.origin.x = 0.0f;
}
if (contentsFrame.size.height < boundsSize.height) {
contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0f;
} else {
contentsFrame.origin.y = 0.0f;
}
self.imageView.frame = contentsFrame;
}
- (void)scrollViewDoubleTapped:(UITapGestureRecognizer*)recognizer {
// Get the location within the image view where we tapped
CGPoint pointInView = [recognizer locationInView:self.imageView];
// Get a zoom scale that's zoomed in slightly, capped at the maximum zoom scale specified by the scroll view
CGFloat newZoomScale = self.scrollView.zoomScale * 1.5f;
newZoomScale = MIN(newZoomScale, self.scrollView.maximumZoomScale);
// Figure out the rect we want to zoom to, then zoom to it
CGSize scrollViewSize = self.scrollView.bounds.size;
CGFloat w = scrollViewSize.width / newZoomScale;
CGFloat h = scrollViewSize.height / newZoomScale;
CGFloat x = pointInView.x - (w / 2.0f);
CGFloat y = pointInView.y - (h / 2.0f);
CGRect rectToZoomTo = CGRectMake(x, y, w, h);
[self.scrollView zoomToRect:rectToZoomTo animated:YES];
}
- (void)scrollViewTwoFingerTapped:(UITapGestureRecognizer*)recognizer {
// Zoom out slightly, capping at the minimum zoom scale specified by the scroll view
CGFloat newZoomScale = self.scrollView.zoomScale / 1.5f;
newZoomScale = MAX(newZoomScale, self.scrollView.minimumZoomScale);
[self.scrollView setZoomScale:newZoomScale animated:YES];
}
#pragma mark -
- (void)loadVisiblePages {
// First, determine which page is currently visible
CGFloat pageWidth = self.scrollView.frame.size.width;
NSInteger page = (NSInteger)floor((self.scrollView.contentOffset.x * 2.0f + pageWidth) / (pageWidth * 2.0f));
// Update the page control
self.pageControl.currentPage = page;
// Work out which pages we want to load
NSInteger firstPage = page - 1;
NSInteger lastPage = page + 1;
// Purge anything before the first page
for (NSInteger i=0; i<firstPage; i++) {
[self purgePage:i];
}
for (NSInteger i=firstPage; i<=lastPage; i++) {
[self loadPage:i];
}
for (NSInteger i=lastPage+1; i<self.pageImages.count; i++) {
[self purgePage:i];
}
}
- (void)loadPage:(NSInteger)page {
if (page < 0 || page >= self.pageImages.count) {
// If it's outside the range of what we have to display, then do nothing
return;
}
// Load an individual page, first seeing if we've already loaded it
UIView *pageView = [self.pageViews objectAtIndex:page];
if ((NSNull*)pageView == [NSNull null]) {
CGRect frame = self.scrollView.bounds;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0.0f;
UIImageView *newPageView = [[UIImageView alloc] initWithImage:[self.pageImages objectAtIndex:page]];
newPageView.contentMode = UIViewContentModeScaleAspectFit;
newPageView.frame = frame;
[self.scrollView addSubview:newPageView];
[self.pageViews replaceObjectAtIndex:page withObject:newPageView];
}
}
- (void)purgePage:(NSInteger)page {
if (page < 0 || page >= self.pageImages.count) {
// If it's outside the range of what we have to display, then do nothing
return;
}
// Remove a page from the scroll view and reset the container array
UIView *pageView = [self.pageViews objectAtIndex:page];
if ((NSNull*)pageView != [NSNull null]) {
[pageView removeFromSuperview];
[self.pageViews replaceObjectAtIndex:page withObject:[NSNull null]];
}
}
#pragma mark -
- (void)viewDidLoad {
[super viewDidLoad];
self.title = #"CorporateBrochure";
self.pageImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"CB1.jpg"],
[UIImage imageNamed:#"CB2.jpg"],
[UIImage imageNamed:#"CB3.jpg"],
[UIImage imageNamed:#"CB4.jpg"],
[UIImage imageNamed:#"CB5.jpg"],
[UIImage imageNamed:#"CB6.jpg"],
nil];
NSInteger pageCount = self.pageImages.count;
// Set up the page control
self.pageControl.currentPage = 0;
self.pageControl.numberOfPages = pageCount;
// Set up the array to hold the views for each page
self.pageViews = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < pageCount; ++i) {
[self.pageViews addObject:[NSNull null]];
}
/* If I use this the subview appears below the image
UIImage *image = self.imageView.image;
//UIImage *image = [UIImage imageNamed:#"CB2.jpg"];
self.imageView = [[UIImageView alloc] initWithImage:image];
self.imageView.frame = (CGRect){.origin=CGPointMake(0.0f, 0.0f), .size=image.size};
[self.scrollView addSubview:self.imageView];
self.scrollView.contentSize = image.size;
*/
UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(scrollViewDoubleTapped:)];
doubleTapRecognizer.numberOfTapsRequired = 2;
doubleTapRecognizer.numberOfTouchesRequired = 1;
[self.scrollView addGestureRecognizer:doubleTapRecognizer];
UITapGestureRecognizer *twoFingerTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(scrollViewTwoFingerTapped:)];
twoFingerTapRecognizer.numberOfTapsRequired = 1;
twoFingerTapRecognizer.numberOfTouchesRequired = 2;
[self.scrollView addGestureRecognizer:twoFingerTapRecognizer];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
CGSize pagesScrollViewSize = self.scrollView.frame.size;
self.scrollView.contentSize = CGSizeMake(pagesScrollViewSize.width * self.pageImages.count, pagesScrollViewSize.height);
[self loadVisiblePages];
}
- (void)viewDidUnload {
[super viewDidUnload];
self.scrollView = nil;
self.pageControl = nil;
self.pageImages = nil;
self.pageViews = nil;
}
- (UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView {
// Return the view that we want to zoom
return self.imageView;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationMaskAll);
}
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// Load the pages which are now on screen
[self loadVisiblePages];
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
// The scroll view has zoomed, so you need to re-center the contents
[self centerScrollViewContents];
}
#end
Is there a specific issue you are having with Ray Wenderlich's tutorial?
Apple's documentation has a very good example of how to implement a paging scroll view, see the Photo Scroller sample code here. I would suggest starting there.
From the above link:
"PhotoScroller" demonstrates the use of embedded UIScrollViews and
CATiledLayer to create a rich user experience for displaying and
paginating photos that can be individually panned and zoomed.
Note: If your images are not overly large, you can get away with not using CATiledLayer.
EDIT 1: See my answer to this question about how to modify Apple's Photo Scroller code to make the UIPageViewController a subview of your own view controller (and not the rootViewController).
EDIT 2: See this sample project on github.

UISegmentedControl setting UITableView, page control, scrollview, image view

i have a segmented control with 4 segment
segment 1 - i need a page control to swipe through photos <- -> left & right. 1- 4 photos max
Segment 2 & 3 - i need a table view
Segment 4 - i need it to be able to play video
i'm currently doing this
- (IBAction)infoAction:(id)sender {
NSString * selectedTitle = [info titleForSegmentAtIndex:[info selectedSegmentIndex]];
NSLog(#"Selected Title = %#",selectedTitle);//test
switch ([info selectedSegmentIndex])
{ case 0:
{
test.text = [frogInfo.imageFiles objectAtIndex:0];
test.textColor = [UIColor whiteColor];
[tempImageView setImage:[UIImage imageNamed:#"Detail1Temp.png"]];
break;
}
case 1:
{
test.text = frogInfo.description;
test.textColor = [UIColor whiteColor];
[tempImageView setImage:[UIImage imageNamed:#"Detail2Temp.png"]];
break;
}
case 2:
{
test.text = frogInfo.distribution;
test.textColor = [UIColor whiteColor];
[tempImageView setImage:[UIImage imageNamed:#"Detail3Temp.png"]];
break;
}
case 3:
{
test.text = [frogInfo.videoFiles objectAtIndex:0];
test.textColor = [UIColor whiteColor];
[tempImageView setImage:[UIImage imageNamed:#"Detail4Temp.png"]];
break;
}
}
}
picture with page control
section tableview
Based on what i will like to do, is it possible ? in this switch case function ?
can anybody show or have any link to tutorial on how to work out the page control swiping ?
thanks for reading
Des
I have done something very similar although I used a UISlider instead of segmented control - What you need is a pageable UISCrollview with 4 equal sized pages (UIViews) loaded horizontally one after another if take-up the entire width of an iPhone each page is 320 wide and the content size width of your scrollview will be 1280. Tie up the UIsegmented controls to scroll the pages programatically:
assuming a page width of 320:
-(IBAction)movepage:(id)sender {
int xloc = (segmentedController.selectedSegmentIndex * 320);
CGRect fieldrect = CGRectMake(xloc,0,320, pagesize.height);
[scrollView scrollRectToVisible:fieldrect animated:YES];
}
To load the scrollview and manage the pagecontroller:
pagectrl.numberOfPages = 4;
pagectrl.currentPage = 0;
scrollView.pagingEnabled = YES;
scrollView.contentSize=CGSizeMake(320* pagectrl.numberOfPages, 500);
scrollView.showsVerticalScrollIndicator = NO;
scrollView.showsHorizontalScrollIndicator = YES;
scrollView.bouncesZoom = NO;
scrollView.decelerationRate = UIScrollViewDecelerationRateFast;
scrollView.scrollsToTop = NO;
scrollView.delegate = self;
search_url.delegate = self;
user.delegate = self;
password.delegate = self;
rpc_code.delegate = self;
// add pages
int page = 0;
CGRect frame = scrollView.frame;
pagesize = frame.size.width;
frame.origin.y = 0;
frame.origin.x = frame.size.width * page;
firstView.frame = frame;
[scrollView addSubview:firstView];
page ++;
frame.origin.x = frame.size.width * page;
locsubView.frame = frame;
[scrollView addSubview:locsubView];
page ++;
frame.origin.x = frame.size.width * page;
QRgensubView.frame = frame;
[scrollView addSubview:QRgensubView];
page ++;
frame.origin.x = frame.size.width * page;
scansubView.frame = frame;
[scrollView addSubview:scansubView];
page ++;
frame.origin.x = frame.size.width * page;
symbologysubView.frame = frame;
[scrollView addSubview:symbologysubView];
[self registerForKeyboardNotifications];
CGRect fieldrect = CGRectMake(0,0,320, pagesize);
[scrollView scrollRectToVisible:fieldrect animated:YES]; //goto 1st page
}
Note you may need to control or manage the user ability to scroll the scroll view - you do that by setting up the scrollview delegate - the code below is not fitted to your exact requirement but I'm sure you can figure out the rest!
- (void)scrollViewDidScroll:(UIScrollView *)sender
{
// We don't want a "feedback loop" between the UIPageControl and the scroll delegate in
// which a scroll event generated from the user hitting the page control triggers updates from
// the delegate method. We use a boolean to disable the delegate logic when the page control is used.
// if (pageControlUsed)
// {
// do nothing - the scroll was initiated from the page control, not the user dragging
// return;
// }
// Switch the indicator when more than 50% of the previous/next page is visible
int page = floor((scrollView.contentOffset.x - pagesize / 2) / pagesize) + 1;
pagectrl.currentPage = page;
// A possible optimization would be to unload the views+controllers which are no longer visible
}

Resources