Dynamically display images on tableview cells - iphone

In my aplication I need to display an image or images on tableview cells depending on their availability in database. What I have done is I have planted four webviews [to show images from urls] and I'm hiding or showing these depending on their availability.
There might also be a case when there's no image, when I'm hiding webviews entirely.
But after random scrolling my application is crashing. Also, while scrolling it's showing me the newer images over older. So, I'm able to see at first one image, then after scrolling through the same cell, two images are led over one another[some part of earlier photo is visible] and so on. Can this be because of cell-reusability? What is the ideal way to about this issue?
EDIT:
I'm using following code:
noOfPhotos = [photos_array count];
if(noOfPhotos > 0){
commentWhenWebviewNotThere.alpha = 0.0; //Things that are not visible when images are there
noOfCommentsWhenWebviewNotThere.alpha = 0.0;
commentsLblWhenWebviewAbset.alpha = 0.0;
image1.hidden = NO;
image2.hidden = NO;
image3.hidden = NO;
image4.hidden = NO;
commentsLblWhenWebview.alpha = 1.0;
noOfComments.alpha = 1.0;
comment.alpha = 1.0;
for(NSInteger x = 0; x < noOfPhotos; x++){
photoName = [photos_array objectAtIndex:x];
NSString *urlAddress = [NSString stringWithFormat:#"%#",photoName];
NSURL *url = [NSURL URLWithString:urlAddress];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
if(x == 0){
image1 = [[UIWebView alloc] initWithFrame:CGRectMake(10, comment.frame.origin.y - 5, 60, 60)];
[image1 loadRequest:requestObj]; //Load the request in the UIWebView.
[self addSubview:image1];
}
else if(x == 1){
image2 = [[UIWebView alloc] initWithFrame:CGRectMake(88, comment.frame.origin.y - 5, 60, 60)];
[image2 loadRequest:requestObj]; //Load the request in the UIWebView.
[self addSubview:image2];
}
else if(x == 2){
image3 = [[UIWebView alloc] initWithFrame:CGRectMake(169, comment.frame.origin.y - 5, 60, 60)];
[image3 loadRequest:requestObj]; //Load the request in the UIWebView.
[self addSubview:image3];
}
else if(x == 3){
image4 = [[UIWebView alloc] initWithFrame:CGRectMake(251, comment.frame.origin.y - 5, 60, 60)];
[image4 loadRequest:requestObj]; //Load the request in the UIWebView.
[self addSubview:image4];
}
}
}
else{
commentWhenWebviewNotThere.alpha = 1.0; //Should be visible when images are not there
noOfCommentsWhenWebviewNotThere.alpha = 1.0;
commentsLblWhenWebviewAbset.alpha = 1.0;
commentsLblWhenWebview.alpha = 0.0;
noOfComments.alpha = 0.0;
comment.alpha = 0.0;
image1.hidden = YES;
image2.hidden = YES;
image3.hidden = YES;
image4.hidden = YES;
}
Thanx in advance.

coupling!!! cells are being reused! what if cell is being reused even before those web views get the results? please pull out the image loading operation from your cell and do it in your controller. Cell must have four image views. And controller should pass the images for them.

Related

Adding an UIView programmatically not working (UIView should show an UIWebView and open URL)

Currently working on two introduction pages (First shows an image, second should show a website) for my iPhone app (like Pocket, for the user a little hands-on after first start).
Came across Matthew York's GitHub project which works perfectly with images and text.
Additionally I like to show a website as a part of the introduction but I can't get it working. My programmatically created UIWebView just doesn't show up.
Matthew York's GitHub Project:
https://github.com/MatthewYork/iPhone-IntroductionTutorial
Complete code for showing the two introduction pages is shown below.
Please mind that panelImage works as expected but not panelView.
I see the second page show up but without the UIWebView.
I think I add the subview to a view not visible on the screen therefore I don't see it. Am I right? Can you please have a look at: [view addSubview:aWebView]; in method: showWebView
ViewController.m
- (void)showIntro
{
MYIntroductionPanel *panelImage = [[MYIntroductionPanel alloc] initWithimage:[UIImage imageNamed:#"img.jpg"] description:#"TEST: IMAGE"];
MYIntroductionPanel *panelView = [[MYIntroductionPanel alloc] initWitView:[self showWebView] description:#"TEST: VIEW"];
MYIntroductionView *introductionView = [[MYIntroductionView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) headerText:#"TESTING" panels:#[panelImage, panelView] languageDirection:MYLanguageDirectionLeftToRight];
introductionView.BackgroundImageView.image = [UIImage imageNamed:#"BG_iPad_1024.png"];
introductionView.delegate = self;
[introductionView showInView:self.view];
}
- (UIView *)showWebView
{
UIWebView *aWebView= [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 290)];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.google.com"]];
[aWebView loadRequest:requestObj];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 300)];
[view addSubview:aWebView];
return view;
}
MYIntroductionPanel.m
-(id)initWitView:(UIView *)view description:(NSString *)description{
if (self = [super init]) {
self.view = [[UIView alloc] init];
self.Description = [[NSString alloc] initWithString:description];
}
return self;
}
-(id)initWithimage:(UIImage *)image title:(NSString *)title description:(NSString *)description{
if (self = [super init]) {
self.Image = [[UIImage alloc] init];
self.Image = image;
self.Title = title;
self.Description = [[NSString alloc] initWithString:description];
}
return self;
}
The view to which you are adding your UIWebView is never added to the view hierarchy itself. You appear to be passing the UIWebView's superview to MyIntroductionPanel's initWithView:description: method, but that method just ignores its input view and creates a new one with self.view = [[UIView alloc] init]. Try setting self.view = view in your initWithView:description: method instead.
I didn't love all of the author's decisions, but followed his pattern to achieve what you're looking for.
Added the following:
// MyIntroductionPanel.h
#property (nonatomic, retain) NSURL *url;
-(id)initWithURL:(NSURL *)url;
// MyIntroductionPanel.m
-(id)initWithURL:(NSURL *)url {
if (self = [super init]) {
_url = url;
}
return self;
}
That was easy. This was less easy - hacking the layout method to deal with panels with urls. I didn't try too hard to understand this method, just added what I could to get it working. My additions are marked with // DANH
// MYIntroductionView.m
-(UIView *)PanelViewForPanel:(MYIntroductionPanel *)panel atXIndex:(CGFloat*)xIndex{
// snipped original code
NSInteger descriptionHeight = panelDescriptionTextView.contentSize.height;
int contentWrappedScrollViewHeight = 0;
if ((imageHeight + descriptionHeight + panelTitleLabelFrame.size.height) > maxScrollViewHeight) {
contentWrappedScrollViewHeight = maxScrollViewHeight;
imageHeight = contentWrappedScrollViewHeight-descriptionHeight - panelTitleLabelFrame.size.height - 10;
}
else if ((imageHeight+descriptionHeight + panelTitleLabelFrame.size.height) <= maxScrollViewHeight){
contentWrappedScrollViewHeight = imageHeight + panelTitleLabelFrame.size.height + descriptionHeight;
}
// DANH
if (panel.url) {
contentWrappedScrollViewHeight = 300;
// you can certainly do a better job than I did here, but just to get going
}
panelView.frame = CGRectMake(*xIndex, 0, self.ContentScrollView.frame.size.width, contentWrappedScrollViewHeight);
//Build image container
UIImageView *panelImageView = [[UIImageView alloc] initWithFrame:CGRectMake(5, 0, self.ContentScrollView.frame.size.width - 10, imageHeight)];
panelImageView.contentMode = UIViewContentModeScaleAspectFit;
panelImageView.backgroundColor = [UIColor clearColor];
panelImageView.image = panel.Image;
panelImageView.layer.cornerRadius = 3;
panelImageView.clipsToBounds = YES;
[panelView addSubview:panelImageView];
// DANH
// add webview on top if we have a url
if (panel.url) {
UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, self.ContentScrollView.frame.size.width, 300)];
[webView loadRequest:[NSURLRequest requestWithURL:panel.url]];
[panelView addSubview:webView];
}
// snipped original code
}
Now, to call it with example code....
// MYViewController.m
MYIntroductionPanel *panel3 = [[MYIntroductionPanel alloc] initWithURL:[NSURL URLWithString:#"http://www.google.com"]];
// ...
MYIntroductionView *introductionView = [[MYIntroductionView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) headerText:#"MYIntroductionView" panels:#[panel, panel2, panel3] languageDirection:MYLanguageDirectionLeftToRight];

How to make a seamless scrollview with web views as their pages (subviews)

I want to make a seamless scrollView
The scrollview should have web views as its subview
And should scroll Seamlessly
The question is...
I had taken the reference from
http://iosdevelopertips.com/user-interface/creating-circular-and-infinite-uiscrollviews.html#comment-66679
And now I had implemented the seamless scrollview with only 3 pages, but I want the webviews to be in place of label...
Nick
In the viewDidLoad we have to write the following code.
- (void)viewDidLoad
{
[super viewDidLoad];
documentTitles = [[NSMutableArray alloc] init];
arrayWebViews = [[NSMutableArray alloc] init];
// create our array of documents
for (int i = 0; i < 5; i++)
{
[documentTitles addObject:[NSString stringWithFormat:#"index%i",i]];
}
// create webviews for the html files
webOne = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 400)];
webTwo = [[UIWebView alloc] initWithFrame:CGRectMake(320, 0, 320, 400)];
webThree = [[UIWebView alloc] initWithFrame:CGRectMake(640, 0, 320, 400)];
// load all three pages into our scroll view
[self loadPageWithId:2 onPage:0];
[self loadPageWithId:0 onPage:1];
[self loadPageWithId:1 onPage:2];
// add them as the subview of scrollview
[scrollView addSubview:webOne];
[scrollView addSubview:webTwo];
[scrollView addSubview:webThree];
// adjust content size for three pages of data and reposition to center page
scrollView.contentSize = CGSizeMake(960, 400);
[scrollView scrollRectToVisible:CGRectMake(320,0,320,400) animated:NO];
}
Now in the loadPageWithID:andPage: method write the following code
- (void)loadPageWithId:(int)index onPage:(int)page
{
switch (page)
{
case 0:
{
self.webOne.backgroundColor = [UIColor clearColor];
self.webOne.delegate = self;
[self.webOne loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:[documentTitles objectAtIndex:index] ofType:#"html"]isDirectory:NO]]];
[arrayWebViews addObject:self.webOne];
}
break;
}
Now in the scrollViewDidEndDecelerating write the following code:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)sender
{
UIWebView* lobjTempWebView = [arrayWebViews objectAtIndex:0];
for (int indexWebViews = 0; indexWebViews < 2; indexWebViews ++)
{
[arrayWebViews replaceObjectAtIndex:indexWebViews withObject:[arrayWebViews objectAtIndex:indexWebViews + 1]];
}
[arrayWebViews replaceObjectAtIndex:[arrayWebViews count] - 1 withObject:lobjTempWebView];
[[arrayWebViews objectAtIndex:0] setFrame:CGRectMake(0, 0, 320, 400)];
[[arrayWebViews objectAtIndex:1] setFrame:CGRectMake(320, 0, 320, 400)];
[[arrayWebViews objectAtIndex:2] setFrame:CGRectMake(640, 0, 320, 400)];
if(scrollView.contentOffset.x > scrollView.frame.size.width)
{
currIndex = (currIndex >= [documentTitles count]-1) ? 0 : currIndex + 1;
nextIndex = (currIndex >= [documentTitles count]-1) ? 0 : currIndex + 1;
[[arrayWebViews objectAtIndex:2] loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:[documentTitles objectAtIndex:nextIndex] ofType:#"html"]isDirectory:NO]]];
}
// Reset offset back to middle page
[scrollView scrollRectToVisible:CGRectMake(320,0,320,400) animated:NO];
}
You'll never get that to be seamless. Webviews take a while to load their contents. If you recycle them like this, they'll be blank for a while as their contents are reloaded.

iPhone Page Control only shows on the first page of a UIScrollView

My page control only shows on the first page of the UIScrollView. Once I scroll to the next page it disappears.
Could you tell me what I'm doing wrong? Because I'm curious as to whether I need to add a subview of the page control each time I add a subview to my UIScrollView.
My relevant pieces of code:
-(IBAction)clickPageControl:(id)sender
{
int page=pageControl.currentPage;
CGRect frame=scroller.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
[scroller scrollRectToVisible:frame animated:YES];
}
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
int page = scrollView.contentOffset.x/scrollView.frame.size.width;
pageControl.currentPage=page;
}
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
arrayCount = [array count];
scroller.delegate=self;
scroller.pagingEnabled=YES;
scroller.directionalLockEnabled=YES;
scroller.showsHorizontalScrollIndicator=NO;
scroller.showsVerticalScrollIndicator=NO;
//should have an array of photo objects and the number of objects, correct?
scrollWidth = 0;
scroller.contentSize=CGSizeMake(arrayCount*scroller.frame.size.width, scroller.frame.size.height);
for (int i = 0; i < arrayCount;i++) {
PhotoViewController *pvc = [[PhotoViewController alloc] initWithNibName:#"PhotoViewController" bundle:nil];
UIImageView *scrollImageView = [[UIImageView alloc] initWithFrame:CGRectOffset(scroller.bounds, scrollWidth, 0)];
CGRect rect = scrollImageView.frame;
pvc.view.frame = rect;
[pvc view];
pvc.label.textColor = [UIColor whiteColor];
id individualPhoto = [array objectAtIndex:i];
NSLog(#"%#",individualPhoto);
NSArray *keys=[individualPhoto allKeys];
NSLog(#"%#",keys);
NSString *imageURL=[individualPhoto objectForKey:#"source"];
//here you can use this imageURL to get image-data and display it in imageView
NSURL *url = [NSURL URLWithString:imageURL];
NSData *data = [NSData dataWithContentsOfURL:url];
pvc.imageView.image = [[UIImage alloc] initWithData:data];
pvc.label.text = [NSString stringWithFormat:#"Photo Number: %i", arrayCount];
//check to make sure the proper URL was passed
//I have an imageView next to the UIScrollView to test whether that works - it does.
[scroller addSubview:pvc.view];
[scrollImageView release];
[pvc release];
scrollWidth += scroller.frame.size.width;
}
if (arrayCount > 3) {
pageControl.numberOfPages=3;
} else {
pageControl.numberOfPages=arrayCount;
}
pageControl.currentPage=0;
[self.view addSubview:scroller];
}
You should not add your page control as a subview of the scroll view, this causes it to scroll with the content. Make it a sibling of the scroll view instead.

UIImage imageWithData

I have a UITable and when I click on a row I load a set of images.
I create the images with
UIImage *image = [UIImage imageWithData:data];
The problem is that ever time I click on the same row, the images are re-allocated into memory, like if no cache it is used and no memory is freed, so the allocated memory keep increasing. (I see this using the Inspector on both the device and the emulator)
I am releasing everything and also, with clang, everything looks fine.
The point is that after a while my app crashes.
Any suggestion or idea?
EDIT:
Here is the portion of code I think is generating the issue:
UIView *main = [[[UIView alloc] initWithFrame:rectScrollView] autorelease];
for (int i=0; i<[contentArray count]; i++) {
float targetWidth = rectScrollView.size.width;
float targetHeight = rectScrollView.size.height;
Link *tmp_link = [contentArray objectAtIndex:i];
AsyncImageView* asyncImage = nil;
if(tmp_link!=nil){
CGRect imageFrame = CGRectMake(targetWidth*i, 0, targetWidth, targetHeight);
//asyncImage = [[[AsyncImageView alloc] initWithFrame:imageFrame ] autorelease];
asyncImage = [[AsyncImageView alloc] initWithFrame:imageFrame ];
asyncImage.contentMode = UIViewContentModeScaleAspectFit;
NSURL* url = [NSURL URLWithString:[[IMG_SERVER_URL stringByAppendingString: tmp_link.url] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
[asyncImage loadImageFromURL:url];
[self.scrollView addSubview:(UIImageView *)asyncImage];
[asyncImage release];
}
if ([tmp_link.caption length] > 0 && asyncImage!=nil) {
float marginTop = 25;
UILabel *caption = [[UILabel alloc] init];
caption.text = tmp_link.caption;
caption.textAlignment = UITextAlignmentCenter;
caption.textColor = [UIColor whiteColor];
caption.font = [UIFont systemFontOfSize:12];
caption.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.4];
CGRect captionFrame = CGRectMake((i * targetWidth), marginTop+10, targetWidth, 20.0f);
caption.frame = captionFrame;
[self.scrollView addSubview:caption];
[caption release];
}
//[asyncImage release];
}
[main addSubview:scrollView];
[scrollView release];
if (pageControlEnabledTop) {
rectPageControl = CGRectMake(0, 5, scrollWidth, 15);
}
else if (pageControlEnabledBottom) {
//rectPageControl = CGRectMake(0, (scrollHeight - 25), scrollWidth, 15);
rectPageControl = CGRectMake(0, (scrollHeight), scrollWidth, 15);
}
if (pageControlEnabledTop || pageControlEnabledBottom) {
//pageControl = [[[UIPageControl alloc] initWithFrame:rectPageControl] autorelease];
pageControl = [[UIPageControl alloc] initWithFrame:rectPageControl];
pageControl.numberOfPages = [contentArray count];
pageControl.currentPage = page;
[main addSubview:pageControl];
[pageControl release];
}
if (pageControlEnabledTop || pageControlEnabledBottom || rememberPosition) self.scrollView.delegate = self;
//if (margin) [margin release];
return (UIScrollView *)main;
And it is used like this:
reviewImagesImage = [[IGUIScrollViewImage alloc] init];
if([currentReview.linkScreenshots count]>0){
//reviewImages
reviewImages = [[UIView alloc] init];
//placing the images
CGRect frameImages = reviewImages.frame;
frameImages.origin.x = 10;
frameImages.origin.y = (infoView.frame.origin.y + infoView.frame.size.height + 10.0f);
frameImages.size.width = 300;
frameImages.size.height = 350.0f;
reviewImages.frame = frameImages;
reviewImages.backgroundColor = [UIColor clearColor];
[reviewImagesImage setContentArray:currentReview.linkScreenshots];
[reviewImagesImage setWidth:reviewImages.frame.size.width andHeight: reviewImages.frame.size.height];
[reviewImagesImage enablePageControlOnBottom];
[reviewImagesImage setBackGroudColor: [UIColor clearColor]];
UIScrollView *tmp_sv = [reviewImagesImage getWithPosition:0];
[reviewImages addSubview:tmp_sv];
[self.view addSubview:reviewImages];
[reviewImages release];
}
I have noticed that if I try to release reviewImagesImage my app crashes :/
Of course no cache is used because new UIImage will be created from the data every time. If memory usage significantly increased like you have said, it is most likely that it is our fault that unintentionally keep the reference retained somewhere.
Once you've set your image with imageWithData, save the image to the filepath in the app bundle.

How to catch event inside uiscrollview on image

Hi I have populated uiscrollview with images (code is bellow) but I don't know how to add some event to images inside. I want to double tap on image inside scrollview and get some event. Any direction how to achieve this?
arrayOfImages = [[NSMutableArray alloc] init];
NSString *img;
for (img in imgArray)
{
[arrayOfImages addObject:[UIImage imageNamed:img]];
}
NSLog(#"Array initialization complete...");
scrollView = [[UIScrollView alloc] init];
scrollView.scrollEnabled = YES;
scrollView.pagingEnabled = YES;
scrollView.directionalLockEnabled = YES;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.delegate = self;
scrollView.backgroundColor = [UIColor blueColor];
scrollView.autoresizesSubviews = YES;
scrollView.frame = CGRectMake(0, 0, 320, 29);
[self.view addSubview:scrollView];
NSLog(#"Scroll View initialization setup complete...");
UIImage *imageToAdd;
int x = 0;
int y = 0;
for (imageToAdd in arrayOfImages)
{
UIImageView *temp = [[UIImageView alloc] initWithImage:imageToAdd];
temp.frame = CGRectMake(x, y, 29, 29);
x += 29;
[scrollView addSubview:temp];
}
NSLog(#"Adding images to outlet complete...");
Add a UITapGestureRecognizer to the UIImageView(s).
Look at this guide for more info.