I'm using iCarousel library in my small app. I'm getting the image urls via web service and placing those images to the iCarousel library.
First I created a UIView and added iCarousel as respective class to it. Latter set the datasourse and delete gate to same class.
Now everything looks cool and I could see the images but I couldn't swipe the images.
Following is my code.
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel
{
//return the total number of items in the carousel
return [galleryItems 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)
{
//NSString *ImageURL = #"YourURLHere";
//NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURL]];
//imageView.image = [UIImage imageWithData:imageData];
view = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200.0f, 200.0f)];
//[((UIImageView *)view) setImageWithURL:[NSURL URLWithString:#"http://www.pizzatower.com/img/icons/Pizza-icon.png"]];
NSURL *imageURL = [[galleryItems objectAtIndex:index] galleryURL];
[((UIImageView *)view) setImageWithURL:imageURL];
view.contentMode = UIViewContentModeScaleAspectFit;
label = [[UILabel alloc] init];
label.backgroundColor = [UIColor clearColor];
label.font = [label.font fontWithSize:20];
label.tag = 1;
// label.contentMode = UIViewContentModeBottom;
// label.frame = CGRectMake(
// self.view.frame.size.width - label.frame.size.width,
// self.view.frame.size.height - label.frame.size.height,
// label.frame.size.width,
// label.frame.size.height );
//label.bounds = view.bounds;
[view addSubview:label];
}
else
{
//get a reference to the label in the recycled view
label = (UILabel *)[view viewWithTag:1];
}
//set item label
//remember to always set any properties of your carousel item
//views outside of the `if (view == nil) {...}` check otherwise
//you'll get weird issues with carousel item content appearing
//in the wrong place in the carousel
//label.text = [[galleryItems objectAtIndex:index] galleryDescription];
return view;
}
I've used same code base and it worked in some other project. No idea what am I missing here. Can someone please enlighten me.
You UIView containing the carousel may have userInteractionEnabled set to NO.
Another possibility is that the UIView containing the carousel may be smaller than the carousel and so be blocking interaction. Try setting its background color to see its true size.
I'd suggest delete your nib or the ViewController in your storyboard and re-create it. I had the same issue once and after re-creating it it worked. Make sure you center your UIView when placing it (both horizontally and vertically)
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;
In my ipad app, i has 200 images and i add these images into an array.
Then add this array into image view by looping.
Then, i add this image view as sub view of scroll view.
When i open app, my app is crash.
I try with reducing image size. But, it didn't work.
One of my friend told firstly i should add only image1 and image2.
When user scroll image1, then it show image2.
After that image1 is remove from image view.
And add image3 to image view.
He told it can maintain memory usage.
But, i don't know how can i do that? :D
Please, give me some example.
Thanks in advance.
My code is here,
- (void)viewDidLoad
{
[super loadView];
self.view.backgroundColor = [UIColor grayColor];
UIScrollView *ScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 44, self.view.frame.size.width, self.view.frame.size.height)];
ScrollView.pagingEnabled = YES;
// Create a UIImage to hold Info.png
UIImage *image1 = [UIImage imageNamed:#"Image-001.jpg"];
UIImage *image2 = [UIImage imageNamed:#"Image-002.jpg"];
UIImage *image200 = [UIImage imageNamed:#"Image-200.jpg"];
NSArray *images = [[NSArray alloc] initWithObjects:image1,image2,...,image200,nil];
NSInteger numberOfViews = 200;
for (int i = 0; i < numberOfViews; i++)
{
CGFloat xOrigin = i * self.view.frame.size.width;
UIImageView *ImageView = [[UIImageView alloc] initWithFrame:CGRectMake(xOrigin, 0, self.view.frame.size.width, self.view.frame.size.height-44)];
[ImageView setImage:[images objectAtIndex:i]];
[ScrollView addSubview:ImageView];
}
ScrollView.contentSize = CGSizeMake(self.view.frame.size.width * numberOfViews, self.view.frame.size.height);
[self.view addSubview:ScrollView];
It looks like you're accessing the images array at indexes 0..200, but it contains only three elements. Either set numberOfViews = 3;, or index into the array like this:
ImageView.image = images[i%3];
The modulo index will cause you to add each of the three images in a repeating sequence and still let you test with a larger number of scrollView subviews. I doubt that your crash is about memory with only 200 images, unless they are super-huge ones.
You should use a table view to display your images. You don't want to create an array of all those images, because that puts all those images into memory -- not a good thing. You don't even need to create an array to hold the names, since they have names you can easily construct from an integer (which you can get from indexPath.row in the tableView:cellForRowAtIndexPath: method). Something like this:
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 200;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSString *imageName = [NSString stringWithFormat:#"Image-%.3d.jpg",indexPath.row +1];
UIImage *image = [UIImage imageNamed:imageName];
cell.imageView.image = image;
return cell;
}
This example just uses the cell's default imageView to show the images, which is pretty small. You would probably want to create a custom cell with a larger image view in it (or a couple side by side if you want more than one image per row).
I am implementing iCarousel (using coverflow type) to show a bunch of images of some videos that are available in my app. (2 seperate carousels, same problem)
I use the arrays of videos for the numberOfItemsInCarousel (currently 60) and viewForItemAtIndex to use the objects from my array to build out the view.
However, only 5 of the videos are being used. So 60 items are showing up in the carousel, but its just the same 5 items being repeated. When I logged the index inside of the 'viewForItemAtIndex', it only gets called 5 times (0,1,...5 are the log results).
After some testing, it seems that the only indexes being called are for whatever is visible in the carousel by default.
What gives?
*The arrays have been tested to ensure they are populated with all unique videos. The array is fine, its something to do with the iCarousel method.
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel{
if(carousel==freeCarousel){
NSLog(#"Free: %i",freeVideos.count);
return freeVideos.count;
}
if(carousel==feeCarousel){
NSLog(#"Fee: %i",feeVideos.count);
return feeVideos.count;
}
return 0;
}
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view{
NSLog(#"TESTING");
if (view == nil){
//Copy array for easier use of global Video / File object
NSArray *copy = [[NSArray alloc] init];
if(carousel==freeCarousel){
copy = [NSArray arrayWithArray:freeVideos];
}
else if(carousel==feeCarousel){
copy = [NSArray arrayWithArray:feeVideos];
}
Videos *currentVideo = [copy objectAtIndex:index];
Files *file = [currentVideo valueForKey:#"files"];
NSLog(#"TITLE TEST: %#",currentVideo.title);
//Video Button
UIButton *buttonVideo = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 465, 310)];
[buttonVideo setTag:[currentVideo.videoID intValue]];
[buttonVideo addTarget:self action:#selector(showVideoDetails:) forControlEvents:UIControlEventTouchUpInside];
//Thumbnail
UIImageView *videoThumbnail = [[UIImageView alloc] initWithFrame:buttonVideo.bounds];
//Border
[videoThumbnail setBackgroundColor:[UIColor whiteColor]];
//Caption
UIImage *captionImage = [UIImage imageNamed:#"video-box-caption"];
UILabel *caption = [[UILabel alloc] initWithFrame:CGRectMake(0, videoThumbnail.frame.size.height-captionImage.size.height, videoThumbnail.frame.size.width, captionImage.size.height)];
[caption setBackgroundColor:[UIColor colorWithPatternImage:captionImage]];
[caption setTextAlignment:NSTextAlignmentCenter];
[caption setFont:[UIFont fontWithName:#"Open Sans Condensed" size:16]];
[caption setTextColor:[UIColor whiteColor]];
[caption setText:currentVideo.title];
[videoThumbnail addSubview:caption];
if(file.thumbnailPath!=(id)[NSNull null] || ![file.thumbnailPath isEqualToString:#"missing_image.png"]){
UIImage *thumbnailImage = [[DataManager sharedManager] generateThumbnailImage:currentVideo];
[videoThumbnail setImage:thumbnailImage];
[buttonVideo addSubview:videoThumbnail];
}else{
UIImage *thumbnailImage = [UIImage imageNamed:#"video-details-thumbnail"];
[videoThumbnail setImage:thumbnailImage];
[buttonVideo addSubview:videoThumbnail];
}
view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, buttonVideo.frame.size.width, buttonVideo.frame.size.height)];
[view addSubview:buttonVideo];
}
return view;
}
You've implemented the viewForItemAtIndex method wrong.
iCarousel recycles views to avoid allocating new objects while moving (like a UITableView). The if (view == nil) check is saying "if view is nil create a new view, otherwise use a view I've already set without modifying it).
Move any index-specific logic outside of the if (if view == nil) check. If you look at the iCarousel examples included with the library, it shows how to do this correctly.
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;