I am working on app in which i have to make welcome screen. In that UIPageControl i need to display different 9 subviews. Also need infinite circular scrolling in that. It means after page-9 if i slide than page-1 should appear.
I have tried so much to implement it but never got expected results.
Can anyone help me out to get the best solution for it.
Thanks.
I recommended to use iCarousel for doing this task. I do following changes in to there demo Buttons Demo
.h class
#property (nonatomic, assign) BOOL wrap;
.m class
- (void)viewDidLoad
{
[super viewDidLoad];
_wrap = YES;
//configure carousel
carousel.type = iCarouselTypeLinear;
}
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel
{
return 9;
}
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view
{
UILabel *label = nil;
//create new view if no view is available for recycling
if (view == nil)
{
view = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200.0f, 400)];
view.backgroundColor=[UIColor redColor];
((UIImageView *)view).image = [UIImage imageNamed:#"page.png"];
view.contentMode = UIViewContentModeCenter;
label = [[UILabel alloc] initWithFrame:view.bounds];
label.backgroundColor = [UIColor clearColor];
label.textAlignment = UITextAlignmentCenter;
label.font = [label.font fontWithSize:50];
label.tag = 1;
[view addSubview:label];
}
else
{
//get a reference to the label in the recycled view
label = (UILabel *)[view viewWithTag:1];
}
label.text = [NSString stringWithFormat:#"%i", index];
return view;
}
- (UIView *)carousel:(iCarousel *)carousel placeholderViewAtIndex:(NSUInteger)index reusingView:(UIView *)view
{
UILabel *label = nil;
//create new view if no view is available for recycling
if (view == nil)
{
//don't do anything specific to the index within
//this `if (view == nil) {...}` statement because the view will be
//recycled and used with other index values later
view = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200.0f, 400.0f)];
view.backgroundColor=[UIColor redColor];
((UIImageView *)view).image = [UIImage imageNamed:#"page.png"];
view.contentMode = UIViewContentModeCenter;
label = [[UILabel alloc] initWithFrame:view.bounds];
label.backgroundColor = [UIColor clearColor];
label.textAlignment = UITextAlignmentCenter;
label.font = [label.font fontWithSize:50.0f];
label.tag = 1;
[view addSubview:label];
}
else
{
//get a reference to the label in the recycled view
label = (UILabel *)[view viewWithTag:1];
}
label.text = (index == 0)? #"[": #"]";
return view;
}
- (CGFloat)carousel:(iCarousel *)_carousel valueForOption:(iCarouselOption)option withDefault:(CGFloat)value
{
//customize carousel display
switch (option)
{
case iCarouselOptionWrap:
{
//normally you would hard-code this to YES or NO
return _wrap;
}
case iCarouselOptionSpacing:
{
//add a bit of spacing between the item views
return value * 1.05f;
}
case iCarouselOptionFadeMax:
{
if (carousel.type == iCarouselTypeCustom)
{
//set opacity based on distance from camera
return 0.0f;
}
return value;
}
default:
{
return value;
}
}
}
- (CATransform3D)carousel:(iCarousel *)_carousel itemTransformForOffset:(CGFloat)offset baseTransform:(CATransform3D)transform
{
//implement 'flip3D' style carousel
transform = CATransform3DRotate(transform, M_PI / 8.0f, 0.0f, 1.0f, 0.0f);
return CATransform3DTranslate(transform, 0.0f, 0.0f, offset * carousel.itemWidth);
}
or getting tapped Button index:-
- (void)carousel:(iCarousel *)carousel didSelectItemAtIndex:(NSInteger)index
{
NSLog(#"Tapped view number: %d", index);
}
it's Output is :-
Here is Attached Demo
Related
I have 2 labels.
First label, named "label" is placed inside every view within the carousel. The string/text of the label is the view's index.
label.text = [[items1 objectAtIndex:index] stringValue];
I also have a second label (outside the carousel) named "outsideLabel".
I want the outsideLabel's string/text to be the view's index aswell (always the view being in front of the carousel).
outsideLabel.text = [[items1 objectAtIndex:index] stringValue];
Somehow I am doing it wrong and wonder how I shall code this in order to show the proper number in outsideLabel's string/text (always the view being in front). The code somewhat shows the correct numbers but get messed up when scrolling backwards in the carousel. The carouseltype is timeMachine.
My current code:
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSInteger)index reusingView:(UIView *)view
{
//create new view if no view is available for recycling
if (view == nil)
{
view = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200.0f, 200.0f)];
view.contentMode = UIViewContentModeCenter;
label = [[UILabel alloc] initWithFrame:view.bounds];
label.backgroundColor = [UIColor clearColor];
label.textColor = [UIColor whiteColor];
if (carousel == carousel1)
{
CGRect test = CGRectMake(10, 10, 20, 20);
self.label.frame = test;
}
else {
CGRect test = CGRectMake(50, 40, 40, 40);
self.label.frame = test;
}
[view addSubview:label];
}
else
{
label = [[view subviews] lastObject];
}
if (carousel == carousel1)
{
//items in this array are numbers
outsideLabel.text = [[items1 objectAtIndex:index] stringValue];
label.text = [[items1 objectAtIndex:index] stringValue];
((UIImageView *)view).image = [UIImage imageNamed:[view1background objectAtIndex:index]];
}
else
{
//not relevant....
}
return view;
}
From the code you've provided, it looks like you're not initializing the outsideLabel in the right place. To be safe, you should initialize all your subviews inside the block where you are checking if the view is nil. Another safe convention is to assign tags to all your subviews, so that you can later retrieve them from views that are reused, as in the code below. For easy reference, and to avoid errors, I define constants for these tags at the top of my implementation file, like this:
#define INSIDE_LABEL_TAG 1
#define OUTSIDE_LABEL_TAG 2
This is much safer, since it doesn't depend on the structure of the views, as is the case with your code, where you get the last view:
label = [[view subviews] lastObject];
Try initializing outsideLabel inside that block, and use tags. The pattern used in initialization is identical to that used for the subviews of UITableView cells in a UITableViewDataSource delegate:
(UITableViewCell * _Nonnull)tableView:(UITableView * _Nonnull)tableView
cellForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath
Here is some pseudo code that shows where I would use tags and initialize the outsideLabel:
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSInteger)index reusingView:(UIView *)view
{
//create new view if no view is available for recycling
if (view == nil)
{
//Configure the view
...
/* Initialize views for all carousels */
//Initialize the insideLabel and set its tag
...
insideLabel.tag = INSIDE_LABEL_TAG;
//Initialize the outsideLabel and set its tag
...
outsideLabel.tag = OUTSIDE_LABEL_TAG;
if (carousel == carousel1)
{
//Do any carousel-specific configurations
}
//Add all subviews initialized in this block
[view addSubview:label];
[view addSubview:outsideLabel];
}
else
{
//Get the subviews from an existing view
insideLabel = (UILabel *)[view viewWithTag:INSIDE_LABEL_TAG];
outsideLabel = (UILabel *)[view viewWithTag:OUTSIDE_LABEL_TAG];
}
if (carousel == carousel1)
{
//Set the values for each subview
} else {
//Other carousels...
}
return view;
}
It looks to me like you want the "time machine" style carousel. I don't see your code setting the carousel type anywhere. Don't you need to set the carousel type?
I am trying to achieve a right to left iCarousel object with a fade on both sides.
So i imported the GtiHub Project into My application, Assigned a UIView to iCarousel...Linked that to an IBOutLet on my MainViewController and passed the Delegate as well as the DataSource just like the UITableViewController.
Though it will not show up and i am unsure of what could be causing this issue.
My iCarousel DataSource is is an NSMutableArray *items; designed like so:
for (int i = 0; i < 100; i++)
{
[_items addObject:#(i)];
}
I am initializing the iCarousel in the ViewDidLoad like below
- (void)viewDidLoad
{
[super viewDidLoad];
//Initialize Carousel
_carousel = [[iCarousel alloc] init];
_carousel.delegate = self;
_carousel.dataSource = self;
//Carousel Testing Data
for (int i = 0; i < 100; i++)
{
[_items addObject:#(i)];
}
//configure carousel
_carousel.type = iCarouselTypeRotary;
}
My Delegate Methods for Carousel are below:
#pragma mark -
#pragma mark iCarousel methods
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel
{
//return the total number of items in the carousel
return [_items count];
}
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view
{
UILabel *label = nil;
//create new view if no view is available for recycling
if (view == nil)
{
view = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200.0f, 200.0f)];
((UIImageView *)view).image = [UIImage imageNamed:#"page.png"];
view.contentMode = UIViewContentModeCenter;
label = [[UILabel alloc] initWithFrame:view.bounds];
label.backgroundColor = [UIColor clearColor];
label.font = [label.font fontWithSize:50];
label.tag = 1;
[view addSubview:label];
}
else
{
//get a reference to the label in the recycled view
label = (UILabel *)[view viewWithTag:1];
}
label.text = [_items[index] stringValue];
return view;
}
- (CGFloat)carousel:(iCarousel *)carousel valueForOption:(iCarouselOption)option withDefault:(CGFloat)value
{
switch (option)
{
case iCarouselOptionFadeMin:
return -0.2;
case iCarouselOptionFadeMax:
return 0.2;
case iCarouselOptionFadeRange:
return 2.0;
default:
return value;
}
}
Everything from the storyboard seems to be connected and the data should be presenting itself, what is wrong and how can i fix this issue?
Since you have the DataSource array (_items) setup after the view gets loaded:
Make sure that the carousel view in your storyboard does have the IBOutlet to the controller, but NOT the 'Delegate' and 'DataSource' linked to the File's Owner (Controller or view).
Set the _carousel.delegate and _carousel.dataSource to 'self' only After you initialize and update the dataSource array (_items in this case).
Place breakpoints to check whether the iCarousel Datasource and Delegate methods are being called or not.
If the methods are not called, check whether the controller follows the iCarousel protocols like this:
#interface yourViewController : UIViewController <iCarouselDataSource, iCarouselDelegate>
Obviously you'll have to
#import "iCarousel.h"
UPDATE: In your viewDidLoad, you have
_carousel = [[iCarousel alloc] init];
looks like you forgot to set a frame for _carousel and add it as a subView.
To get the imageView reference, try this:
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200.0f, 200.0f)];
imageView.image = [UIImage imageNamed:#"page.png"];
view = imageView;
I am using iCarousel in my application to show images which is coming from web service with linear type carousel. When user scroll end of the carousel if no images available from web service i am adding one carousel with button.
What i am doing is when no data available from web service i am setting boolean value yes(isNoImagesAvailable == YES).then i am adding one extra carousel item on bottom.
Below is example code to understand how i am doing
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)
{
self.carousel.contentOffset = CGSizeMake(0, (213 - self.carousel.frame.size.height) * 0.5);
}
else
{
self.carousel.contentOffset = CGSizeMake(0, (200 - self.carousel.frame.size.height) * 0.5);
}
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel
{
//Here i am increasing carousel count by 1 if no images available
if (isNoImagesAvailable)
{
return images.count+1;
}
else
{
return images.count;
}
}
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view
{
//create new view if no view is available for recycling
if(index < images.count )
{
if (view == nil)
{
//this `if (view == nil)
{`
view = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200.0f, 200.0f)];
((UIImageView *)view).image =// Here loading images from web service
view.contentMode = UIViewContentModeCenter;
}
else
return view;
}
// if no images are available adding one button with text "No data available"
else
{
UIView * endimageView = nil;
if (view == nil)
{
endimageView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 150.0f,50.0f)];
endimageView.backgroundColor =[UIColor clearColor];
endimageView.contentMode = UIViewContentModeCenter;
UIButton *noDataButton =[UIButton buttonWithType:UIButtonTypeCustom];
noDataButton.frame =CGRectMake(0, 0, 150, 40);
noDataButton.userInteractionEnabled=YES;
[noDataButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[noDataButton setTitle:#"No data available" forState:UIControlStateNormal];
[noDataButton addTarget:self action:#selector(popToHomePage) forControlEvents:UIControlEventTouchUpInside];
noDataButton.backgroundColor =[UIColor whiteColor];
[endingDealView addSubview: noDataButton s];
}
return endingDealView;
}
Here the problem is when user on bottom of the screen when scroll up "No data available" button is going below the navigation bar. How can make "endimageView" carousel item offset to exact below the navigation bar.
Let me know any information need from my side
Thanks
Hi my requirement is showing image in scrollview along with that it should display next and previous button.User can scroll the image as well as use buttons to move images.
I have doubt about how to get the index/tag/imagename or anything else when user scroll based on that values buttons should be updated.
Here is my Code
[self arrayInitiaisation];
scrollview.pagingEnabled = YES;
scrollview.alwaysBounceVertical = NO;
scrollview.alwaysBounceHorizontal = YES;
NSInteger numberOfViews = 4;
for (int i = 0; i < numberOfViews; i++) {
CGFloat xOrigin = i*320;
imageView.image = [UIImage imageNamed:[NSString stringWithFormat:#"image%d",i+1]];
imageView.contentMode = UIViewContentModeScaleAspectFit;
[self.scrollview addSubview:imageView];
imageView.tag = i;
...
Array Initialisation method
-(void) arrayInitialisation {
count=0;
[super viewDidLoad];
images=[NSMutableArray arrayWithObjects : [UIImage imageNamed:#"image1.png"],
[UIImage imageNamed :#"image2.png"],
[UIImage imageNamed :#"image3.png"],
[UIImage imageNamed :#"image4.png"],nil];
[imageView setImage:[images objectAtIndex:0]];
NSLog(#"Array Length :%d",images.count);
[previous setEnabled:NO];
}
Action Methods
- (IBAction)nextButton:(id)sender {}
- (IBAction)prevButton:(id)sender {}
scroll is working correctly but when user clicks on prev and next image is not updating on 'imageview'
Here is my updated code
int count=0;
- (void)viewDidLoad
{
[super viewDidLoad];
[self arrayInitialisation];
[scrollview setScrollEnabled:YES];
self.scrollview =[[UIScrollView alloc] initWithFrame:CGRectMake(30 , 30, 320, 412)];
self.scrollview.delegate=self;
scrollview.pagingEnabled = YES;
scrollview.alwaysBounceVertical=NO;
scrollview.alwaysBounceHorizontal=YES;
scrollview.showsHorizontalScrollIndicator=NO;
NSInteger numberOfViews = 4;
for (int i = 0; i < numberOfViews; i++) {
CGFloat xOrigin = i*320;
imageView = [[UIImageView alloc]initWithFrame:CGRectMake(xOrigin, 0, 320, 412)];
imageView.image = [images objectAtIndex:i];
imageView.contentMode = UIViewContentModeScaleAspectFit;
[self.scrollview addSubview:imageView];
imageView.tag=i;
}
scrollview.contentSize = CGSizeMake(320*numberOfViews, 412);
scrollview.contentOffset = CGPointMake(0,0);
[self.view addSubview:self.scrollview];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(void) arrayInitialisation{
count=0;
[super viewDidLoad];
images=[NSArray arrayWithObjects : [UIImage imageNamed:#"image1.png"],
[UIImage imageNamed :#"image2.png"],
[UIImage imageNamed :#"image3.png"],
[UIImage imageNamed :#"image4.png"],nil];
[imageView setImage:[images objectAtIndex:0]];
NSLog(#"Array Length :%d",images.count);
[previous setEnabled:NO];
}
- (IBAction)nextButton:(id)sender {
if(count==0){
count++;
NSLog(#"Next Button : if Loop %d",count);
[imageView setImage:[images objectAtIndex:count]];
[previous setEnabled:YES];
}
else{
[previous setEnabled:YES];
count++;
NSLog(#"Next Button : else Loop %d",count);
if(count <images.count){
[imageView setImage:[images objectAtIndex:count]];
}
else{
[next setEnabled:NO];
}
}
}
- (IBAction)prevButton:(id)sender {
if(count==0){
//count--;
NSLog(#"prev Button : if Loop %d",count);
[imageView setImage:[images objectAtIndex:count]];
[previous setEnabled:NO];
[next setEnabled:YES];
}
else{
count--;
NSLog(#"prev Button : else Loop %d",count);
[imageView setImage:[images objectAtIndex:count]];
[previous setEnabled:YES];
//[next setEnabled:YES];
}
}
#pragma mark - ScrollView Delegate
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate: (BOOL)decelerate{
//NSLog(#"scrollViewDidEndDragging");
/* count=count+1;
NSLog(#"scrollViewDidEndDragging : %d",count);*/
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
//NSLog(#"scrollViewDidScroll");
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset NS_AVAILABLE_IOS(5_0){
//NSLog(#"scrollViewWillEndDragging");
count=count+1;
NSLog(#"scrollViewWillEndDragging : %d",count);
}
I have left and right button for scroll images, and imageview width is same.
I am writing code for scroll image at pressing button.
int pos=0;// ViewDiaLoad
- (IBAction)OnClickLeftButton:(UIButton*)sender
{
if(pos>0)
{
pos -=1;
[scrlDemandMenu scrollRectToVisible:CGRectMake(pos*scrlDemandMenu.frame.size.width, 0, scrlDemandMenu.frame.size.width, scrlDemandMenu.frame.size.height) animated:YES];
}
}
- (IBAction)OnClickRightButton:(UIButton*)sender
{
if(pos<numberOfImages)
{
pos +=1;
[scrlDemandMenu scrollRectToVisible:CGRectMake(pos*scrlDemandMenu.frame.size.width, 0, scrlDemandMenu.frame.size.width, scrlDemandMenu.frame.size.height) animated:YES];
}
}
Set scrollView Deleagte
Scroll View delegate Method
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
pos=scrollView.contentOffset.x/scrollView.frame.size.width;
}
You can use UIPageControl and set and get image according to page index. For more information check out this link
Try below piece of code. I hope it will help. Put this in your .h file
IBOutlet UIScrollView *scrollView;
IBOutlet UIPageControl *pageControl;
NSMutableArray *arrImages;
NSInteger page;
Now in your - (void)viewDidLoad put following lines.
int x = 30;
for (int i=0; i< arrImages.count; i++)
{
UIImageView *imgShow = [[UIImageView alloc]initWithFrame:CGRectMake(x+20, 50, self.view.frame.size.width-100, self.view.frame.size.height-180)];
imgShow.backgroundColor = [UIColor whiteColor];
imgShow.image = [UIImage imageNamed:[arrImages objectAtIndex:i]];
imgShow.contentMode = UIViewContentModeScaleAspectFit;
[scrollView addSubview:imgShow];
x = x+scrollView.frame.size.width;
}
scrollView.contentSize = CGSizeMake(5*self.view.frame.size.width, 0);
pageControl.backgroundColor = [UIColor clearColor];
pageControl.pageIndicatorTintColor = [UIColor grayColor];
pageControl.currentPageIndicatorTintColor = [UIColor blueColor];
[pageControl setTintAdjustmentMode:UIViewTintAdjustmentModeDimmed];
pageControl.numberOfPages = arrTitle.count;
pageControl.currentPage = 0;
implement scroll view delegate.
#pragma mark - ScrollView Delegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView1
{
CGFloat pageWidth = scrollView.frame.size.width;
float fractionalPage = scrollView.contentOffset.x / pageWidth;
page = lround(fractionalPage);
pageControl.currentPage = page;
}
- (IBAction)prevButton:(UIButton *)sender
{
page = page-1;
UIButton *btn = (UIButton *)[sender viewWithTag:sender.tag];
// write your code
for (id obj in btn.subviews)
{
if ([obj isKindOfClass:[UIImageView class]])
{
// write your code
}
else
{
// write your code
}
}
}
- (IBAction)nextButton:(UIButton *)sender
{
page = page+1;
UIButton *btn = (UIButton *)[sender viewWithTag:sender.tag];
// write your code
for (id obj in btn.subviews)
{
if ([obj isKindOfClass:[UIImageView class]])
{
// write your code
}
else
{
// write your code
}
}
}
When i press the back button. the iCarousel is still shows up for 1 second.why is this happening and how to stop this.I have used storyboard to create a iCarosel view..
- (void)viewDidUnload
{
[super viewDidUnload];
self.carousel = nil;
}
- (void)dealloc
{
carousel.delegate = nil;
carousel.dataSource = nil;
}
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel
{
return [idOfAllWords count];
}
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view
{
UILabel *label = nil;
//create new view if no view is available for recycling
if (view == nil)
{
view = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 250.0f, 250.0f)];
((UIImageView *)view).image = [UIImage imageNamed:#"page.png"];
view.contentMode = UIViewContentModeCenter;
label = [[UILabel alloc] initWithFrame:view.bounds];
label.backgroundColor = [UIColor clearColor];
label.textAlignment = NSTextAlignmentCenter;
label.font = [label.font fontWithSize:50];
label.tag = 1;
[view addSubview:label];
}
else
{
label = (UILabel *)[view viewWithTag:1];
}
Words *word=nil;
word=idOfAllWords[index];
label.text =word.Name;
return view;
}
Hiding and unhiding is not the solution. What you need is just one line:
yourCarousel.clipsToBounds = YES;
I actually tried to reproduce your problem and did see that the carousel view stays for a second when 'pop' or back button press happens. This particularly happens when you the carousel is swiped and then the back button pressed. As a workaround, I was able to fix it by setting the iCarousel hidden in the viewWillDisappear method.
- (void)viewWillDisappear:(BOOL)animated
{
[YOUR_CAROUSEL_NAME setHidden:YES]; //This sets the carousel to be hidden when you press Back button
}
If this looks to be hidden suddenly, you can perhaps try setting the alpha to 0.0 inside an animation block. Something like this:
- (void)viewWillDisappear:(BOOL)animated
{
//[YOUR_CAROUSEL_NAME setHidden:YES];
[UIView animateWithDuration:0.2f animations:^{
[YOUR_CAROUSEL_NAME setAlpha:0.0f]; //This makes the carousel hide smoothly
}];
}
Hope this helps!