I have a tableview, and when i click on a row, it navigates to another view; The code for the navigation part is shown below;
ShowImageController *showImageController = [[HowItWorksViewController alloc] initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:showImageController animated:YES];
The other view contains an image, i have added the image to its viewDidLoad. and here's the code for that
UIImageView *imageView=[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"hello.png"]];
[imageView setFrame:CGRectMake(o, o, 200, 300)];
[[self view] addSubview:imageView ];
The problem is When i click on the row it takes a long time (extremely slow), to navigate to the other screen.
note: Rows which didn't have an image in the other view navigated well with no issue. Why is this happening ? and how can i fix it ?
Try loading the images in a asynk task or nsoperationqueue :)
Definitely sounds like the images are big and therefore taking a while to load. I suggest you either use smaller images or if you have no control over them you might want to try loading the images in the background. Here is some code to get you started with loading them in the background:
- (void)decodeImageInBackgroundThread:(UIImage*)decodedImage forImageView:(UIImageView*)imageView {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
CGImageRef originalImage = [decodedImage CGImage];
CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(originalImage));
CGDataProviderRef imageDataProvider = CGDataProviderCreateWithCFData(imageData);
if (imageData != NULL) {
CFRelease(imageData);
}
CGImageRef image = CGImageCreate(CGImageGetWidth(originalImage),
CGImageGetHeight(originalImage),
CGImageGetBitsPerComponent(originalImage),
CGImageGetBitsPerPixel(originalImage),
CGImageGetBytesPerRow(originalImage),
CGImageGetColorSpace(originalImage),
CGImageGetBitmapInfo(originalImage),
imageDataProvider,
CGImageGetDecode(originalImage),
CGImageGetShouldInterpolate(originalImage),
CGImageGetRenderingIntent(originalImage));
if (imageDataProvider != NULL) {
CGDataProviderRelease(imageDataProvider);
}
dispatch_async(dispatch_get_main_queue(), ^{
[imageView setImage:[UIImage imageWithCGImage:image]];
CGImageRelease(image);
});
});
}
Which you can then use like this:
- (void)viewDidLoad {
...
UIImage *image = [UIImage imageNamed:#"hello.png"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:nil];
[imageView setFrame:CGRectMake(0.0f, 0.0f, 200.0f, 300.0f)];
[[self view] addSubview:imageView];
[self decodeImageInBackgroundThread:image forImageView:imageView];
}
Related
I have a background coming from Default-568h#2x.png. I want to display a shrunk PNG over part of the background, but calling:
[[CJSHCardView alloc] initWithScale:.1];
turns the display white. This does not happen if I comment this line, but in the function call, even if I make it return immediately it turns the display white after half a second:
- (id)initWithScale:(float)scale
{
UIImage *img = [UIImage imageNamed:#"note.png"];
self = [super initWithImage:img];
if (self != nil)
{
self.frame = CGRectMake(0, 0, img.size.width * scale, img.size.height * scale);
UIImageView *myImage = [[UIImageView alloc] initWithFrame:self.frame];
myImage.opaque = NO;
[self addSubview:myImage];
}
return self;
}
Moving/copying the return statement to be the first in initWithScale makes no discernible change from how it is with the return statement properly at the end: a brief view of the background, followed by a white screen. note.png is in "Supporting Files".
Do you see any gotchas where I can change things so that a shrunken version of the note (maintaining aspect ratio) displays? The note.jpg image does not have a pixel of white.
Thanks,
--EDIT--
Regarding the first comment:
#implementation CJSHCardView : UIImageView
- (id)initWithFrame:(CGRect)frame
{
NSAssert(NO, #"Call initWithHeight instead.");
return self;
}
Does that answer your question?
--SECOND EDIT--
Thank you for your response and your code, Nick. I have slightly altered it to fit ARC and to initially set a fixed-width scale, but I was a little unsure of what method to put it in. I tried the ViewController's viewDidLoad() method, but that resulted in the background being shown without hide or hair of the note. My present viewDidLoad() method reads:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIImage *backgroundImage = [UIImage imageNamed:#"Default-568h"];
CGRect containerRect = CGRectZero;
containerRect.size = [backgroundImage size];
UIView *containerView = [[UIView alloc] initWithFrame:containerRect];
float scale=.1;
UIImageView *backgroundView = [[UIImageView alloc] initWithImage:backgroundImage];
[containerView addSubview:backgroundView];
[backgroundView sizeToFit];
// [backgroundView release];
UIImage *noteImage = [UIImage imageNamed:#"note"];
CGSize noteSize = [noteImage size];
UIImageView *noteView = [[UIImageView alloc] initWithImage:noteImage];
[noteView setContentMode:UIViewContentModeScaleAspectFit];
[noteView setFrame:CGRectMake(0, 0, noteSize.width * scale, noteSize.height * scale)];
[containerView addSubview:noteView];
// [noteView release];
}
Thanks,
Subclassing UIImageView is not necessary. Just create a container UIView and add 2 UIImageView subviews.
Edit - this should work for your implementation:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIImage *backgroundImage = [UIImage imageNamed:#"Default-568h"];
CGRect containerRect = CGRectZero;
containerRect.size = [backgroundImage size];
UIView *containerView = [[UIView alloc] initWithFrame:containerRect];
[[self view] addSubview:containerView];
float scale=.1;
UIImageView *backgroundView = [[UIImageView alloc] initWithImage:backgroundImage];
[containerView addSubview:backgroundView];
[backgroundView sizeToFit];
UIImage *noteImage = [UIImage imageNamed:#"note"];
CGSize noteSize = [noteImage size];
UIImageView *noteView = [[UIImageView alloc] initWithImage:noteImage];
[noteView setContentMode:UIViewContentModeScaleAspectFit];
[noteView setFrame:CGRectMake(0, 0, noteSize.width * scale, noteSize.height * scale)];
[containerView addSubview:noteView];
}
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 my Iphone App, I used the following code for the animation of those 3 images in viewDidLoad() method and I use left transform to load this ViewController. But these imageView is not displayed on the view.
NSArray *newArray = [[NSArray alloc]initWithObjects:[UIImage imageNamed:#"search1.png"],
[UIImage imageNamed:#"search2.png"],
[UIImage imageNamed:#"seach3.png"],
nil];
UIImageView *imageView = [UIImageView alloc];
[imageView initWithFrame:CGRectMake(240, 60, 60, 30)];
imageView.animationImages = newArray;
imageView.animationDuration = 0.25;
imageView.animationRepeatCount = 3;
[self.view addSubview:imageView];
Animation won't start until you tell it to start. You will need to add a command to startAnimating. I also cleaned up your alloc/init and I added a command to make the image view still keep showing when it is not animating. Setting an animation will not make the image appear. The image property is for the still image and the animationImages property is for the animating images of a UIImageView.
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(240, 60, 60, 30)];
imageView.image = [UIImage imageNamed:#"search3.png"]; //This will be the image that is visible when it is NOT animating.
imageView.animationImages = newArray;
imageView.animationDuration = 0.25;
imageView.animationRepeatCount = 3;
[imageView startAnimating]; //This will make the animation start
[self.view addSubview:imageView];
Finally, your third image is missing an r. I think you want #"search.png" and not #"seach.png"
I've got a UIImageView in a page that gets its image from the Interface builder and I'm trying to put small icons on the top of it (it's a small map and I want to put icons on it). I know it's probably very simple but I tried to look it up in the documentation but it pretty much got me more confused.
Using Interface Builder, can't you just drag a UIImageView into an existing UIImageView? In effect, you end up with one UIImageView embedded within another.
You should also be able to easily set the hidden property of the "small map" UIImageView in code, depending on if that UIImageView is needed or not.
Hope this helps. Good Luck.
Let It Be Known
you could compose your own UIView by adding both the large and small UIViewImage views.
I have illustrated my approach below with the Pseudocode .
-(id) initwithFrame:(CGRect) frame
{
if(self = [super initWithFrame:frame])
{
iContainer = [[UIView alloc] initWithFrame:frame];
[iContainer addSubViews:iLargerUIImageView];
[iContainer addSubViews:iSmallUIImageView];
[self.view addSubViews:iContainer];
}
return self;
}
-(void) layoutSubviews
{
CGRect myRect = self.frame;
iContainer.frame = myRect;
//Give the location to iLargerUIImageView as per your requirement.
iLargerUIImageView.frame = CGRectMake(...,...,...,...);
//Give the location to iSmallUIImageViewas per your requirement.
iSmallUIImageView.frame = CGRectMake(...,...,...,...);
}
-(void) dealloc
{
[iContainer release];
[iLargerUIImageView release];
[iSmallUIImageView release];
}
try this code:
UIImageView *backgroundImageView = (UIImageView *)[self viewWithTag:kBckGndImag];
if(!backgroundImageView){
UIImage *imageName = [UIImage imageNamed:kpointsChartBig];
backgroundImageView = [[UIImageView alloc] initWithFrame:CGRectMake(15, 15, imageName.size.width, imageName.size.height)];
backgroundImageView.image=imageName;
[backgroundImageView setTag:kBckGndImag];
[pointImageView addSubview:backgroundImageView];
[backgroundImageView release];
}
UIImageView *foregroundImageView = (UIImageView *)[self viewWithTag:kForGndImage];
if(!foregroundImageView){
foregroundImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:kpointsColoredChartBig]];
foregroundImageView.contentMode = UIViewContentModeLeft;
foregroundImageView.clipsToBounds = YES;
[pointImageView addSubview:foregroundImageView];
[foregroundImageView release];
}