iCarousel scaling images when number of images is greater than iCarouselOptionVisibleItems - ios

I'm using iCarousel to display images clicked by the user and are reloaded dynamically into the carousel. The whole setup works perfectly with default values for iCarouselOptionVisibleItems but images start to scale up when the total number of images exceeds 8.
TO try and fix the issue i increased the number of iCarouselOptionVisibleItems to 25 and that temporarily fixed the issue but i know thats not the best solution because the images will still scale after the number exceeds 25. Is there something I'm missing from the documentation that I'm missing?
Here's the code for my icarousel screen
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.carousel.delegate = self;
self.carousel.dataSource = self;
_carousel.type = iCarouselTypeCoverFlow2;
}
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel
{
//return the total number of items in the carousel
return [images count];
}
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view
{
//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, 200.0f)];
view.contentMode = UIViewContentModeScaleAspectFit;
((UIImageView *)view).image = [UIImage imageWithContentsOfFile:[images objectAtIndex:index]];
}
else
{
//get a reference to the label in the recycled view
view.contentMode = UIViewContentModeScaleAspectFit;
view = [[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:[images objectAtIndex:index]]];
}
return view;
}
- (CGFloat)carousel:(iCarousel *)carousel valueForOption:(iCarouselOption)option withDefault:(CGFloat)value
{
if (option == iCarouselOptionSpacing)
{
return value * 1.1f;
}
else if (option == iCarouselOptionVisibleItems)
{
return 25;
}
return value;
}

Related

iCarousel display images from array of images' URLs

I have implemented iCarousel for my Banner View on iPad with this relevant codes:
- (NSInteger)numberOfItemsInCarousel:(__unused iCarousel *)carousel
{
return (NSInteger)[self.bannerDatas count];
}
- (UIView *)carousel:(__unused iCarousel *)carousel viewForItemAtIndex:(NSInteger)index reusingView:(UIView *)view
{
if (view == nil)
{
view = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 215.0f, 155.0f)];
((UIImageView *)view).image = [UIImage imageNamed:[self.netImages objectAtIndex:index]];
view.contentMode = UIViewContentModeCenter;
}
return view;
}
But the problem lies here at this line:
((UIImageView *)view).image = [UIImage imageNamed:[self.netImages objectAtIndex:index]];
netImages need to be image's name in order to get this works but my netImages contain array of images' URLs. So my question is how to use image URL instead of name for Carousel?
Here below is how netImages get data:
- (NSArray *)setUpNetImages {
self.netImages = [NSMutableArray new];
for (BannerData *data in self.bannerDatas) {
if (data.imageUrl != nil) {
[self.netImages addObject:data.imageUrl]; //original
}
}
return self.netImages;
}
Please Use SDwebImage that provide you functionality to download your image in Asynchronous orderer from url and update your image once downloading done.and your UI never get halt.
((UIImageView *)view)sd_setImageWithURL:[NSURL URLWithString:[self.netImages objectAtIndex:index]]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]]
You just need to add it and import
#import <SDWebImage/UIImageView+WebCache.h>

Regarding iCarousel and labels iOS

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?

iCarousel Sticks during screen transition

I am using an iCarousel. The carousel contains about 10 images. While screen transitions the images get stuck to the next screen. I am using popToRootview while going back to the original screen. Does it have to do with the UIImage alloc ?
My Code:
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel
{
return ([animals count]);
}
- (NSUInteger)numberOfVisibleItemsInCarousel:(iCarousel *)carousel
{
//limit the number of items views loaded concurrently (for performance reasons)
return 7;
}
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index
{
NSString *filePath1 = [animals objectAtIndex:index];
UIImage *image = [[UIImage alloc] initWithContentsOfFile:filePath1];
//create a numbered view
UIView *view = [[UIImageView alloc] initWithImage:image];
view.frame = CGRectMake(0.0f, 0.0f, 230, 150);
return view;
}
- (NSUInteger)numberOfPlaceholdersInCarousel:(iCarousel *)carousel
{
//note: placeholder views are only displayed on some carousels if wrapping is disabled
return 0;
}
- (CGFloat)carouselItemWidth:(iCarousel *)carousel
{
//usually this should be slightly wider than the item views
return 240;
}
- (BOOL)carouselShouldWrap:(iCarousel *)carousel
{
//wrap all carousels
return wrap;
}
- (void)carouselDidEndScrollingAnimation:(iCarousel *)aCarousel
{
label.text = [descriptions objectAtIndex:aCarousel.currentItemIndex];
[_label1 setText:[NSString stringWithFormat:#"%ld/%lu", (long)aCarousel.currentItemIndex+1,(unsigned long)[animals count]]];
}
- (IBAction)btnBackAct:(UIButton *)sender
{
[carousel removeFromSuperview];
//[carousel scrollToItemBoundary];
[carousel scrollToItemAtIndex:0 animated:NO];
[self.navigationController popViewControllerAnimated:YES];
}
try:
- (IBAction)btnBackAct:(UIButton *)sender
{
[carousel scrollToItemAtIndex:0 duration:0.01];
[self performSelector:#selector(popMyView) withObject:nil afterDelay:0.02];
}
-(void)popMyView
{
[self.navigationController popViewControllerAnimated:YES];
}

iCarousel performance issue on iPad

I'm using Nick Lockwood's iCarousel for an iPad app. Right now it's just a carousel of 15 full screen images.
I setup a single view project, add the iCarousel view in storyboard, add it's view controller as a data source and put this code for the datasource methods:
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel {
return 15;
}
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view {
UIImage* img = [UIImage imageNamed:[NSString stringWithFormat:#"image%d.jpg", index]];
UIImageView* imgView = [[UIImageView alloc] initWithImage:img];
return imgView;
}
This works, but the first time I scroll through all the items you can notice a little performance hit when a new item is being added to the carousel. This does not happen the second time I go through all the items.
You can see what I mean in this profiler screenshot. The peaks in the first half are for the first time I scroll through all the images, then I do it again and there are no peaks and no performance hit.
How can I fix this?
EDIT
I isolated one of the peaks on instruments and this is the call tree
EDIT
The code with jcesar suggestion
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray* urls_aux = [[NSMutableArray alloc] init];
for (int i = 0; i<15; i++) {
NSString *urlPath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"captura%d", i] ofType:#"jpg"];
NSURL *url = [NSURL fileURLWithPath:urlPath];
[urls_aux addObject:url];
}
self.urls = urls_aux.copy;
self.carousel.dataSource = self;
self.carousel.type = iCarouselTypeLinear;
}
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view {
if (view == nil) {
view = [[[AsyncImageView alloc] initWithFrame:CGRectMake(0, 0, 1024, 768)] autorelease];
view.contentMode = UIViewContentModeScaleAspectFit;
}
[[AsyncImageLoader sharedLoader] cancelLoadingImagesForTarget:view];
((AsyncImageView *)view).imageURL = [self.urls objectAtIndex:index];
return view;
}
I don't think this is a very orthodox solution, but it works.
What I do is use iCarousel's method insertItemAtIndex:animated: to add the images one at a time on setup. Performance gets hit then, but after that everything runs smoothly.
- (void)viewDidLoad
{
[super viewDidLoad];
self.images = [[NSMutableArray alloc] init];
self.carousel.dataSource = self;
self.carousel.type = iCarouselTypeLinear;
for (int i = 0; i<15; i++) {
UIImage* img = [UIImage imageNamed:[NSString stringWithFormat:#"captura%d.jpg", i]];
[self.images addObject:img];
[self.carousel insertItemAtIndex:i animated:NO];
}
}
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel {
return self.images.count;
}
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view {
UIImage* img = [self.images objectAtIndex:index];
UIImageView* imgView = [[UIImageView alloc] initWithImage:img];
return imgView;
}
It's hard to be certain, but I'd guess that the first time through it's loading the images from the file; whereas the second time it's using the cached copies - that's something that +[UIImage imageNamed:] does automatically for you; without it, you'd see the performance hit every time. You could load the images earlier, either in your app delegate or in the initialiser for your controller.
Another thing you could do would be to make use of iCarousel's view reuse logic. I don't think it's responsible for your problem, but you may as well do it now:
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view {
UIImage* img = [UIImage imageNamed:[NSString stringWithFormat:#"image%d.jpg", index]];
UIImageView* imgView = nil;
if ([view isKindOfClass:[UIImageView class]])
{
imgView = (UIImageView *)view;
imgView.image = img;
[imgView sizeToFit];
}
else
{
[[UIImageView alloc] initWithImage:img];
}
return imgView;
}
UPDATE: It would be great to get a bit more information on where your app is spending its time. If you use the Instruments Time Profiler you can get a breakdown of what percentage of the time is spent in each method.
Look at his example: Dynamic Downloads. He uses AsyncImageView instead UIImageView, that loads the images in an async way. So it won't try to load all the 15 images at the same time, and I think it shouldn't have performance issues

In iCarousel images are overlapping.

My code is below
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view
{
UIImageView *imgView = nil;
if (view == nil)
{
NSLog(#"no is %i",index);
view = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 255, 255)] autorelease];
imgView = [[[UIImageView alloc] initWithImage:[ImagesCFArray objectAtIndex:index]] autorelease];
[view addSubview:imgView];
}
else
{
}
return view;
}
ImagesCfArray contains the images to be displayed. 0th index image overlapping with other images when carousel moves or scrolls. Please give me solution for this.
Can you show your itemWidth implementation? Does it return more than 255?
You might want to tell the subview to clip to its bounds:
imgView.clipToBounds = YES;
And also, perhaps use a fill for the image:
imgView.contentMode = UIViewContentModeScaleAspectFit;

Resources