Just started with xCode 5 storyboard and am having an issue with images. I have a View Controller that Houses a Scroll View > Image View.
When the image loads, it's displaying at full size and expanding the Scroll View. I've tried changing the View Mode and resizing it programmatically as shown below but it's not working. Can anyone shed some light on this issue?
if(!_curInfo.img)
{
showActivity(self);
dispatch_queue_t aQueue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(aQueue1, ^{
_curInfo.img = getImageFromURL([NSString stringWithFormat:#"%#%#", g_serverUrl, _curInfo.imgPath]);
dispatch_async(dispatch_get_main_queue(), ^{
hideActivity();
[_imgCompany setImage:_curInfo.img];
});
});
}
_imgCompany.frame = CGRectMake(0,0,320,180);
_imgCompany.contentMode=UIViewContentModeScaleAspectFill;
_imgCompany.clipsToBounds=YES;
[_imgCompany setImage:_curInfo.img];
Here is what it looks like
You can try:
_imgCompany.autoresizingMask = UIViewAutoresizingNone;
or
self.edgesForExtendedLayout=UIRectEdgeNone;
self.extendedLayoutIncludesOpaqueBars=NO;
self.automaticallyAdjustsScrollViewInsets=NO;
You probably have the master switch for Auto Layout switched on. Turn it off.
Related
My app is presently made of a TableViewController, and a ViewController. When a cell in the TableView is selected, the ViewController is pushed, which is the main app. This View Controller previously loads all its UIViews in the main thread, which caused the screen to freeze as the code ran, often leading users to believe it has crashed. To prevent this issue, and improve the user experience, I have changed my code to the following overall format:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self initialiseApp];
}
- (void) initialiseApp {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Initialising views
imageView = [[UIImageView alloc] initWithImage:[self getImageFromUrl:currentWallpaperURL]];
[imageView setFrame:CGRectMake(0.0, 100, screenWidth, (screenWidth/7)*4)];
[imageView setContentMode:UIViewContentModeScaleAspectFit];
// etc etc for other views
dispatch_async(dispatch_get_main_queue(), ^{
//Add subviews to UI
[[self view] addSubview:imageView];
});
});
}
When app running in the simulator, this causes the ViewController to load as a blank screen, and later load the UI after some time. During loading, I would have some form of spinner, or text on the screen. I would therefore like clarification on this topic:
Is loading an app's UI when the ViewController is opened (or alternatively, when the app is launched) conventional? And if not, what is a better alternative to prevent having the app freeze for 10 seconds on launch?
Thanks.
I tend to experience issues when creating UI elements on background threads, so I would avoid this if possible (Apple says the same). In your situation, rather than loading the UI elements in the background, load the image in the background and then create the UI elements when the image has been loaded. As an example,
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImage *image = [self getImageFromUrl:currentWallpaperURL];
dispatch_async(dispatch_get_main_queue(), ^{
//Add subviews to UI
imageView = [[UIImageView alloc] initWithImage:image];
[imageView setFrame:CGRectMake(0.0, 100, screenWidth, (screenWidth/7)*4)];
[imageView setContentMode:UIViewContentModeScaleAspectFit];
[[self view] addSubview:imageView];
});
});
I want to set an image according to screen size. I've been going through many codes on it but I've not found a working solution yet. I'm using Xcode 5.1.1 and Iphone Retina 4inch. Whenever I add my background image, it becomes huge and goes out of screen size. Kindly help me.
Use the code from Anbu's answer to get the screen height and set the image to aspectFit to avoid it from getting huge and out of bounds:
yourImageview.contentMode = UIViewContentModeScaleAspectFit;
yourImageview.clipsToBounds = YES;
If your view is directly added to a UIViewController you should use the viewWillLayoutSubviews (doc) method to do the resize. Something like this:
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
self.imageView.frame = self.bounds;
}
I am trying to overlay two images and put text on top in a view that I have. I have this working perfectly in ios7. Here is a screen shot of the results
Right now the gradient is simply an image on top of the other image as seen here in my layout
This works great except for when I test on my phone with ios6. Then everything goes nuts as seen here. *I've actually deleted the gradient layer and ran the app again and the background image remains the same size (about half of what it should be).
As you can see, the background image is only half of what it should be, and the second image is not overlaying. I've been at this for 5 hours and can't seem to find a solution that works.
Here is the code that sets the background image
-(void) SetDetails
{
if(_curInfo)
{
_lblTopName.text = _curInfo.company_name;
if(!_curInfo.img)
{
showActivity(self);
dispatch_queue_t aQueue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(aQueue1, ^{
_curInfo.img = getImageFromURL([NSString stringWithFormat:#"%#%#", g_serverUrl, _curInfo.imgPath]);
dispatch_async(dispatch_get_main_queue(), ^{
hideActivity();
[_imgCompany setImage:_curInfo.img];
});
});
}
[_imgCompany setImage:_curInfo.img];
/* FIX IMAGE SIZE */
_imgCompany.contentMode=UIViewContentModeScaleAspectFill;
CGRect photoFrame = _imgCompany.frame;
photoFrame.size = CGSizeMake(320, 180);
_imgCompany.frame=photoFrame;
[_imgCompany setClipsToBounds:YES];
_lblDistance.text = [NSString stringWithFormat:#"%.2f miles", _curInfo.distance];
_lblReward.text=_curInfo.reward;
CGFloat scrollViewHeight = 0.0f;
for (UIView* view in scroller.subviews)
{
scrollViewHeight += view.frame.size.height;
}
[scroller setContentSize:(CGSizeMake(320, scrollViewHeight))];
}
}
Any help is greatly appreciated. I'm not opposed to drawing the gradient onto the image either.
Additional Info:
Here is how I have the two image views setup.
You need to unstick the 'opaque' option on your image view, given that it isn't opaque.
As to the other spacing issue, I'd guess it's a mismatch between iOS 7 view controllers always acting as if they had wantsFullScreenLayout set to YES but the default having been NO under iOS 6. The rest of your image is probably underneath your navigation bar. It looks like you're part trying the interface builder and part doing programmatic layout — why did you add the code underneath FIX IMAGE SIZE and what happens if you remove it?
I'm working in a project (iOS7 & ARC) in which, I want to display N number of images in the scroll view.These Images already stored into sandbox directory. My App has only landscape orientation I'm facing a problem that ScrollView is not smooth, it stuck after 2-3 times scroll
This is how I configure ScrollView
[self.containerScroll setAutoresizesSubviews:NO];
self.containerScroll.pagingEnabled = YES;
self.containerScroll.showsHorizontalScrollIndicator = NO;
self.containerScroll.showsVerticalScrollIndicator = NO;
self.containerScroll.scrollsToTop = NO;
self.containerScroll.maximumZoomScale = 5.0;
self.containerScroll.minimumZoomScale = 1.0;
self.containerScroll.delegate = self;
I'm maintaining only three Images in the scrollView at a time.
I'm loading Images in ScrollView in below method
-(void) loadScrollViewWithPage:(int) page{
if (page >= self.numberOfSlides)
return;
float image_width;
float image_height;
if(self.isFromListView){
if(IS_IPHONE5){
image_width = 568.0f;
image_height = 320.0f;
} else{
// iPhone retina-3.5 inch
image_width = 480.0f;
image_height = 320.0f;
}
}
else{
image_width = IMAGE_WIDTH;
image_height = IMAGE_HEIGHT;
}
CGFloat xPos = page * image_width;
UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(xPos, 0.0f, image_width, image_height)];
imgView.tag = page;
NSString *imgPath = [self.storageDirPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%d%#", page, Image_Extension_JPG]];
NSFileManager *fileManager = [NSFileManager defaultManager];
__block UIImage *img = nil;
if(![fileManager fileExistsAtPath:imgPath]){
[imgView setContentMode:UIViewContentModeCenter];
img = [UIImage imageNamed:#"icon-loader.png"];
[imgView setImage:img];
}
else{
[imgView setContentMode:UIViewContentModeScaleAspectFit];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
img = [[UIImage alloc] initWithCGImage:[[UIImage imageWithData:[NSData dataWithContentsOfFile:imgPath]] CGImage] scale:1.0 orientation:UIImageOrientationUp];
dispatch_async(dispatch_get_main_queue(), ^{
[imgView setImage:img];
});
});
}
[self.containerScroll addSubview:imgView];
img = nil;
fileManager = nil;
imgView = nil;
}
and this how my ScrollView Delegate methods goes...
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
self.containerScroll.scrollEnabled = YES;
float page = self.containerScroll.contentOffset.x/self.view.frame.size.width;
showingSlide = (UInt16) roundf(page);
if(scrollView == self.containerScroll){
// switch the indicator when more than 50% of the previous/next page is visible
CGFloat pageWidth = CGRectGetWidth(self.containerScroll.frame);
NSUInteger pageNo = floor((self.containerScroll.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
// load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
[self loadScrollViewWithPage:pageNo - 1];
[self loadScrollViewWithPage:pageNo];
[self loadScrollViewWithPage:pageNo + 1];
// a possible optimization would be to unload the views+controllers which are no longer visible
if(scrollView == self.containerScroll)
{
[self.previewTableView reloadData];
[self.previewTableView setContentOffset:CGPointMake(0, (page*220)+64) animated:NO];
[self.previewTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:page inSection:0] atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
[self updateSlideNumber];
[self flashSlideNumber];
}
//unload unnecessary imageviews from scroll view
for (UIView* view in self.containerScroll.subviews) {
if ([view isKindOfClass:[UIImageView class]] && view.tag != page && view.tag != page-1 && view.tag != page+1) {
[view removeFromSuperview];
}
}
}
}
Now the problem is smoothness of scrollView. When I start scrolling it scrolls fine but after 2 or 3 (or after any random number) pages scroll, it stuck and after trying 2-3 times only it moves again and I have to swipe hard to scroll. Thanks in advance.
I think it's a problem of memory somewhere Try #autorelease pool in your code.
using scrollview is not a good approach for showing images, I will recommend you to either use tableview or collevtionview for the same.
Your app's memory will keep on increasing with every scroll because scollview doesn't reuse the memory, on the other hand tableview and collectionview reuses the memory.
As the most effective way to become better, scroll really slowly (one at a time) while you monitor the memory usage in your App. You'll be able to watch it go up as each new image is added to the view, especially if you haven't done any optimisation on the images.
The other thing is that while your code does look like is deallocc-ing the images, you still need to remember that it still has to try to reload the images as you scroll. You're creating your images on the main thread so you're never going to get the smoothness of a UITableView. While I realise that you're creating your image views on async threads, the act of adding and scrolling them is still being taken care of by the mainthread.
I would suggest a UITableView to solve your problem, or a UICollectionView. If you're set on using the scrollview, I would suggest using a crusher of some type to get the image size to as small as possible, while still keeping quality decent.
If you need help on the TableView implementation you should find plenty of information around SO. Probably a good option if you still want it to look like a scroll view is just to make all seperators, headers etc to nil, and then just use lazy loading for the images.
You make two the mistake. At first: never use imageNamed for non graphics content (example, use imageNamed for button background). And second: you try load a big images in real time. So you scroll view have lags therefore. If you load all images before you show the scroll view the amination end lagging. But you can get memory warnings. So, you need optimise it. P.S. Sorry for my english
I'm using a double for loop to add UIButtons to a UIScrollView in a grid format. These UIButtons take time to load as they have subviews that are UIImageViews which get their UIImages by downloading data off the internet.
Right now, the subviews don't show until AFTER the method completely finishes executing. Correct me if I'm wrong, but I'm guessing xcode doesn't show added subviews until a method is done executing.
However, I do want to show each subview getting added one at a time, as a cool loading effect. How would I implement this?
Thanks!
You should use multiple threads to load your pictures so that your main thread does not become sluggish. I recently wrote something similar...Take a look at my code from my viewWillAppear method:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
self.myImages = [self.myModel retrieveAttachments]; //Suppose this takes a long time
for (UIImage *image in self.myImages)
{
dispatch_async(dispatch_get_main_queue(), ^{
[self addImageToScrollView:image animated:YES]; });
}
}
});
The addImageToScrollView method would be like so:
-(void) addImageToScrollView: (UIImage *) image animated: (BOOL) animated
{
//Create image view
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.image = image;
if(animated)
{
imageView.alpha = 0;
[self.myScrollView addSubview:imageView];
[UIView animateWithDuration:ADD_IMAGE_APPEARING_ANIMATION_SPEED animations:^{
imageView.alpha = 1;
}];
}
else
{
[self.myScrollView addSubview:imageView];
}
}