How to implement lazy loading to uiscroll view
I am taking 15 images from the web service and add it to UIscrollview
I want to lad the scroll view with temporary image and when the image is ready it can add the image to uiscrollview
-(void)loadthscroll:(NSMutableArray *)idarray:(NSMutableArray *)imgarray
{
/*************scroll for scroll in in theater******************/
scrollview_intheater= [[UIScrollView alloc] initWithFrame:CGRectMake(0, btn_thhead.frame.size.height,view_banner.frame.size.width, view_intheater.frame.size.height-btn_thhead.frame.size.height)];
[view_intheater addSubview:scrollview_intheater];
[scrollview_thcsoon removeFromSuperview];
adj=5;
currentx=5;
for(int i=0;i<[imgarray count];i++)
{
btn_theater_ct = [UIButton buttonWithType:UIButtonTypeCustom];
btn_theater_ct.frame=CGRectMake(currentx, 5, 95, 120);
[btn_theater_ct addTarget:self action:#selector(theaterAction:) forControlEvents:UIControlEventTouchDown];
[scrollview_intheater addSubview:btn_theater_ct];
addr = [imgarray objectAtIndex:i];
addr = [addr stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
//NSLog(#"addr-------%#",addr);
data_theater = [NSData dataWithContentsOfURL:[NSURL URLWithString:addr ] ];
[btn_theater_ct setBackgroundImage:[UIImage imageWithData:data_theater] forState:UIControlStateNormal];
currentx +=btn_theater_ct.frame.size.width+adj;
btn_theater_ct.tag=i;
[scrollview_intheater setContentSize:CGSizeMake(currentx,0)];
NSLog(#"add th scroll--%d----%d",[imgarray count],i);
}
}
I face the same issue before few days but i fixed it now by
importing
#import "UIImageView+AFNetworking.h"
and implementing its method
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholderImage;
to use this u have to use AFNetworking class
Set up the whole UIScrollView with a loading image
Create a method which exchanges a given image and update the content size if needed
Add a routine do download the image
Now you can setup the UIScrollView and call the routine to download. Then when the download is done call the method to exchange the image and you are done.
Try to study GCD(GrandCentralDispatch) and work with your scenario's.
May be this will suits you.
-(void)loadthscroll:(NSMutableArray *)idarray:(NSMutableArray *)imgarray
{
scrollview_intheater= [[UIScrollView alloc] initWithFrame:CGRectMake(0, btn_thhead.frame.size.height,view_banner.frame.size.width, view_intheater.frame.size.height-btn_thhead.frame.size.height)];
[view_intheater addSubview:scrollview_intheater];
[scrollview_thcsoon removeFromSuperview];
adj=5;
currentx=5;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
//Here, do your iteration part like parsing URL from array and hitting the service which is background thread.
for(int i=0;i<[imgarray count];i++)
{
btn_theater_ct = [UIButton buttonWithType:UIButtonTypeCustom];
btn_theater_ct.frame=CGRectMake(currentx, 5, 95, 120);
[btn_theater_ct addTarget:self action:#selector(theaterAction:) forControlEvents:UIControlEventTouchDown];
[scrollview_intheater addSubview:btn_theater_ct];
currentx +=btn_theater_ct.frame.size.width+adj;
[scrollview_intheater setContentSize:CGSizeMake(currentx,0)];
NSLog(#"add th scroll--%d----%d",[imgarray count],i);
addr = [imgarray objectAtIndex:i];
addr = [addr stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
//NSLog(#"addr-------%#",addr);
data_theater = [NSData dataWithContentsOfURL:[NSURL URLWithString:addr ] ];
UIImage *receivedImage = [UIImage imageWithData:data_theater];
}
dispatch_async(dispatch_get_main_queue(), ^{
//Here, do your UI work like set the background image which is include in main thread
if([receivedImage isKindOfClass:[UIImage class]])
{
[btn_theater_ct setBackgroundImage: receivedImage];
btn_theater_ct.tag=i;
}
});
});
}
Related
I need to add more than one button (its depend upon array count) to UIScrollview.Now i am using the following code.This code is working properly but more time ( delay for adding button) taking for this function.Please help me..
for (int i=0; i< [imageArray count]; i++) {
NSURL *url = [NSURL URLWithString:[[imgArray objectAtIndex:i]objectForKey:#"url"]];
UIImage *img = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
UIButton *button1 = [UIButton buttonWithType:UIButtonTypeCustom];
button1.frame = CGRectMake(xp, 0, 75, 75);
[button1 setImage:img forState:UIControlStateNormal];
[button1 addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
button1.layer.borderColor = [UIColor whiteColor].CGColor;
button1.layer.borderWidth = 2.0;
[mScrollView addSubview:button1];
xp += button1.frame.size.width+15;
}
Because you are loading your image from server so it blocks your main thread till image load itself completely. Try loading image in different thread
Below is an example that shows how to load image on diffrent thread
Add your button object and url in an array (this can be written inside your for loop)
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:0];
[array addObject:cell.businessLogoImageView];
[array addObject:#"your Url"];
[NSThread detachNewThreadSelector:#selector(loadImage:) toTarget:self withObject:array];
[array release];
array = nil;
now implement loadImage
-(void)loadImage:(NSArray *)objectArray
{
UIImageView *tempImageView = (UIImageView *)[objectArray objectAtIndex:0];
tempImageView.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[objectArray objectAtIndex:1]]]];
}
For the ready made project you can use the following link.
As you are loading images from server it should also make CACHE of the images , so as not to download images again and again,
So, there should be something like lazyloading( this will not solve by just running in background)
LAZYLOADING scrollView
Get SDWebImage from GitHub. There's a category in it called UIButton+WebCache which can load your button's images asynchronously as well as store them on disk and memory to speed up their subsequent reloads.
#import "UIButton+WebCache"
....
UIButton *button...
[button setImageWithURL:[NSURL urlWithString:#"www.etc.com/img.jpg"] forControlState:UIControlStateNormal];
I am using AsyncImageView classes to apply lazy loading on UITableView. And want to apply activity indicator on image view until the image is loaded on cell. Below is my code i am trying.
// AsyncIamgeView.m
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection {
//[connection release];
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
indicator.center = CGPointMake(15, 15);
connection=nil;
if ([[self subviews] count]>0) {
[[[self subviews] objectAtIndex:0] removeFromSuperview];
}
UIImage *imgData = [UIImage imageWithData:data];
UIImageView* imageView = [[UIImageView alloc]init];
[imageView addSubview:indicator];
[indicator startAnimating];
if(imgData == nil)
{
imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"NoImagenew.png"]];
//[indicator stopAnimating];
}
else{
imageView = [[UIImageView alloc] initWithImage:imgData];
// [indicator stopAnimating];
}
//imageView.contentMode = UIViewContentModeScaleAspectFit;
//imageView.autoresizingMask = ( UIViewAutoresizingFlexibleWidth || UIViewAutoresizingFlexibleHeight );
//[imageView sizeToFit];
[self addSubview:imageView];
imageView.frame = self.bounds;
//imageView.frame = CGRectMake(0, 0, 85, 94);
[imageView setNeedsLayout];
[self setNeedsLayout];
//[data release];
data=nil;
}
// cellForRowAtIndexPath method.
asyncImageView = [[AsyncImageView alloc]initWithFrame:CGRectMake(1, 3, 85, 54)];
[asyncImageView loadImageFromURL:[NSURL URLWithString:imageUrlString]];
[cell.contentView addSubview:asyncImageView];
This code shows activity indicator but when image is loaded after that not before loading images. Please guide for above.
You have to create AsyncImageView object instead of UIImageView, then it will automatically add indicator to your view
AsyncImageView *imageView = [[AsyncImageView alloc] initWithFrame:CGRectMake(1, 3, 85, 54)];
[cell addSubview:imageView];
//cancel loading previous image for cell
[[AsyncImageLoader sharedLoader] cancelLoadingImagesForTarget:imageView];
//load the image
imageView.imageURL = [imageURLs objectAtIndex:indexPath.row];
Here is an example of this
Currently you are adding activity indicator when your image is downloaded.
Here is the simple idea, hope you can implement this in your code
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// This method is called when your connection receives a response
// add your activity indication here and start animating
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// This method is called when your image is downloaded.
// remove your activity indicator or stop animating here
}
Hope u downloaded AsyncImageView from https://github.com/nicklockwood/AsyncImageView. By default, it has the feature to show activity indicator. You just dont need to add or remove any code by yourself to get this feature works. Just call loadImageWithURL.
I think u are using asynimageview classs, In that by default you will get the loader in the cell itself .
AysncImageView already has a loader.
You won't see it if your background is black since it loads the default activity indicator.
So, just set the activityIndicatorStyle property for your AsyncImageView object based on your background.
In my case, my background was black, so I used the following code :
asyncImgView.activityIndicatorStyle = UIActivityIndicatorViewStyleWhite;
im using the followng method , to display image when a timestamp detecetd , am using
dispatch_async(dispatch_get_main_queue(), to do UIImageView , its never works its should open a new screen full size image that it ,
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *myImage = [UIImage imageNamed:#"img.jpg"];
UIImageView *myImageView = [[UIImageView alloc] initWithImage:myImage];
[myImageView setFrame:CGRectMake(0, 0, 100, 200)];
[myImageView release];
;
});
my full code
- (void) onPayload:(PayloadEvent *) event
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *header = #"[OnPayload] ";
if (event.payloadType == TYPE_IDENTIFIED)
{
if ((event.contentID != -1) && (event.timeStamp == -1))
{
[mUI performSelectorOnMainThread: #selector(Trace:) withObject:[NSString stringWithFormat:#"%# StaticID detected: %x\t\tConfidence: %f\n", header,(int)event.contentID, event.confidence] waitUntilDone:NO];
}
if ((event.timeStamp != -1) && (event.contentID == -1))
{
[mUI performSelectorOnMainThread: #selector(Trace:) withObject:[NSString stringWithFormat:#"%# Timestamp detected: %f\t\tConfidence: %f\n", header, event.timeStamp, event.confidence] waitUntilDone:NO];
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *myImage = [UIImage imageNamed:#"img.jpg"];
UIImageView *myImageView = [[UIImageView alloc] initWithImage:myImage];
[myImageView setFrame:CGRectMake(0, 0, 100, 200)];
[myImageView release];
; });
You never add myImageView to any view as a subview.
Try to use this one in your code.
[self.view addSubview:myImageView];
You are creating an ImageView, assigning an Image to it and releasing the ImageView. In other words, you're not displaying the ImageView anywhere.
If you can't do something like [self.view addSubview:imageView], it means that you're not running this code on a UIViewController subclass.
You basically need to add this ImageView you're creating as a subview for the current view before releasing it.
In which class are you running this code? Do you know which View Controller is currently being displayed?
In one of my app's user interfaces i want my app display a scrolling view(the count of the scrolled pages is dynamically set in runtime). But i want the to add UIWebView and UIView elements to the same array, so that when i scroll i will be able to display both UIWebView(let's say a web page) and some other View?
EDIT
I received this answer which looks as if exactly ok but doesn't work(or i couldn't to)
here is the code:
NSArray *myArray;
// Fill the array with a bunch of UIWebView and UIView objects here
for (id theObject in myArray)
{
if ([theObject isKindOfClass:[UIWebView class]]) {
// do stuff
}
else if ([theObject isKindOfClass:[UIView class]]) {
// do other stuff
}
}
Can anyone please give a hend of help? I need to create a scrollable array of views(like the main page of the iPhone) but the first page(mean, view) must be a member of UIWebView(the others are UIView)
And below is all my code(i han't try to do anything here:)
CGRect frame;
[webView initWithFrame:frame];
NSArray *colors = [NSArray arrayWithObjects:webView, [UIColor blackColor],[UIColor blackColor], nil];
for (int i = 0; i < colors.count; i++) {
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
UIView *subview = [[UIView alloc] initWithFrame:frame];
subview.backgroundColor = [colors objectAtIndex:i];
[subview setTag:i];
if([subview tag]==2){
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(70.0f, 600.0f, 250.0f, 60);
[button setTitle:#"Read Messages" forState:UIControlStateNormal];
for(NSDictionary* buttonData in butDat) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
NSString* buttonTitle = [buttonData objectForKey:#"name"];
NSString* buttonID=[buttonData objectForKey:#"order_number"];
[button setTitle:buttonTitle forState:UIControlStateNormal];
[button setTag:[buttonID intValue]];
button.titleLabel.font=[UIFont systemFontOfSize:28];
CGFloat yPosition = 60.0f;
const CGFloat buttonHeight = 85.0f;
if (button.tag==1) {
button.frame = CGRectMake(70.0f, yPosition, 250.0f, buttonHeight);
//[ma.view addSubview:button];
}
if (button.tag==2) {
button.frame = CGRectMake(440.0f, yPosition, 250.0f, buttonHeight);
//[ma.view addSubview:button];
}
if (button.tag==3) {
button.frame = CGRectMake(70.0f, 200.0f, 250.0f, buttonHeight);
//[ma.view addSubview:button];
}
if (button.tag==4) {
button.frame = CGRectMake(440.0f, 200.0f, 250.0f, buttonHeight);
//[menu_2.view addSubview:button];//****
}
if (button.tag==5) {
button.frame = CGRectMake(70.0f, 335.0f, 250.0f, buttonHeight);
//[menu_2.view addSubview:button];//****
}
if (button.tag==6) {
button.frame = CGRectMake(440.0f, 335.0f, 250.0f, buttonHeight);
//[menu_2.view addSubview:button];//****
}
[button addTarget:self action:#selector(secondAct:) forControlEvents:UIControlEventTouchUpInside];
[scrollView addSubview:button];
}
//
[button addTarget:self action:#selector(readM:) forControlEvents:UIControlEventTouchUpInside];
// [scrollView addSubview:button];
[self.view addSubview:button];
// [self.scrollView addSubview:button];
}
[self.scrollView addSubview:subview];
There's nothing stopping you from adding objects of type UIWebView and UIView to the same NSArray.
If your code needs to know if you're dealing with a UIWebView or a UIView, you can use the method isKindOfClass: to check:
NSArray *myArray;
// Fill the array with a bunch of UIWebView and UIView objects here
for (id theObject in myArray)
{
if ([theObject isKindOfClass:[UIWebView class]]) {
// do stuff
}
else if ([theObject isKindOfClass:[UIView class]]) {
// do other stuff
}
}
Furthermore, UIWebView is a subclasses of UIView and inherits many of the same methods, making view layout the same in both cases.
From a user interface standpoint, it's probably bad practice to have scroll views inside scroll views, so you're going to want to disable scrolling of your UIWebView objects. If you are targeting iOS 5 and above you can use the following:
webView.scrollView.scrollEnabled = NO;
webView.scrollView.bounces = NO;
and if you're on a version of iOS lower than 5.0, you can inject the following javascript:
<script type="text/javascript">
touchMove = function(event) {
event.preventDefault();
}
</script>
To implement the javascript injection, you can use UIWebView's stringByEvaluatingJavaScriptFromString: method inside webViewDidFinishLoad:
See here for more information on UIWebView javascript injection: http://iphoneincubator.com/blog/windows-views/how-to-inject-javascript-functions-into-a-uiwebview
Edit: Looking at your code, it seems as thought you're sticking a UIWebView and two UIColor objects into your array. Therefore you need to check if you're dealing with a UIWebView or a UIColor, or you'll crash on subview.backgroundColor = [colors objectAtIndex:i]; Also you set your UIWebView object's frame to CGRect frame; which is uninitialized.
You should populate your NSArray with your UIWebView and then two UIView objects with their background colors set:
UIWebView *webView = [[UIWebView alloc] init];
UIView *viewOne = [[UIView alloc] init];
[viewOne setBackgroundColor:[UIColor blackColor]];
UIView *viewTwo = [[UIView alloc] init];
[viewTwo setBackgroundColor:[UIColor blackColor]];
NSArray *viewArray = [NSArray arrayWithObjects:webView, viewOne, viewTwo, nil];
for (id theObject in viewArray)
{
if ([theObject isKindOfClass:[UIWebView class]]) {
// do stuff
}
else if ([theObject isKindOfClass:[UIView class]]) {
// do other stuff
}
}
Yes. UIWebViews descend from UIViews. You may use them wherever you would insert a UIView as a subview, including within a UIScrollView parent view, or as an object to be inserted into an array.
Your scroll view is not scrolling because you didn't set the contentsize property. First you have to find the content size appropriately, and then you have to set content size as
[scrollView setContentSize:CGSize];
at the end of code. ie; after
[self.scrollView addSubview:subview];
For a blind try, use
[scrollView setContentSize:CGSizeMake(1000,1000)];
this will definitely scroll the view!!!
I m parsing a json url and showing it in a grid view.The output in the simulator looks like a grid of images similar to imagepicker.on pressing the image it got to navigate to a new view...the code works fine and i am able to receive the data in the console when the image is clicked.the problem is i m not able to navigate to the next view..cud u guys help me out
- (void)viewDidLoad {
[super viewDidLoad];
jsonurl=[NSURL URLWithString:#"http://www.1040communications.net/sheeba/stepheni/iphone/stephen.json"];
jsonData=[[NSString alloc]initWithContentsOfURL:jsonurl];
jsonArray = [jsonData JSONValue];
items = [jsonArray objectForKey:#"items"];
// NSLog(#"hello:%#",items);
story = [[NSMutableArray array]retain];
media1 = [[NSMutableArray array]retain];
for (NSDictionary *item in items )
{
[story addObject:[item objectForKey:#"title"]];
[media1 addObject:[item objectForKey:#"media"]];
}
UIScrollView *view = [[UIScrollView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
int row = 0;
int column = 0;
for(int i = 0; i < media1.count; i++) {
NSString *mel=[media1 objectAtIndex:i];
NSString *escapedURL = [mel stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
UIImage *thumb = [[UIImage alloc]initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:escapedURL]]];
button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(column*100+24, row*80+10, 64, 64);
[button setImage:thumb forState:UIControlStateNormal];
[button addTarget:self
action:#selector(buttonClicked:)
forControlEvents:UIControlEventTouchUpInside];
button.tag = i;
[view addSubview:button];
if (column == 2) {
column = 0;
row++;
} else {
column++;
}
}
[view setContentSize:CGSizeMake(320, (row+1) * 80 + 10)];
self.view = view;
[view release];
}
- (IBAction)buttonClicked:(id)sender
{
UIImage *boy = [story objectAtIndex:button.tag];
Detailview *detailview=[[Detailview alloc]init];
[detailview initWithItem:boy];
self.detailviewController=detailview;
[self.navigationController pushViewController:self.detailviewController animated:YES];
}
Try this in your buttonClicked:
UIImage *boy = [story objectAtIndex:sender.tag];
You want the tag of sender, not button. button was set to the last one in your list when your buttons were created. sender is the ui object that caused this event.
hi looks like ur using old JSON parser. there is a much better parser for json.
thats JSONKIT.
It has just 2 files(.h and .m) and in just 2 lines of code u can get any data corresponding to the key. u dont hav to iterate through your items array. ur performance rate will definetly incr using JSONKit. if u tryin to use this let me i can post sample codes to parse json contents using jsonkit.
Secondly for the problem u have, u are putting the images in UIScrollview. ur uiscrollview doesnt have navigationcontrol to be pushed to the next view. either remove the scroll view and push from the rootviewcontroller or add navigationcontroller to uiscrollview. guess thats the prob. try it.
all the best.