Background image too large in window/view - Part 2 - objective-c

This code here by sangony work for me really well but only on iPhone
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
CGRect viewFrame = CGRectMake(0, 0, 320, 568);
UIImage *background = [UIImage imageNamed:#"BG.png"];
UIImage *scaledImage = [UIImage imageWithCGImage:[background CGImage]
scale:(background.scale * 2.0)
orientation:(background.imageOrientation)];
UIImageView *backgroundView = [[[UIImageView alloc] initWithImage:scaledImage] initWithFrame:viewFrame];
[[self window] addSubview:backgroundView];
[[self window] sendSubviewToBack:backgroundView];
self.window.backgroundColor = [UIColor clearColor];
[self.window makeKeyAndVisible];
return YES;
}
Now how can I do the same idea, targeting both iPhones and iPads?
Original post can be found Here:

CGRect viewFrame = CGRectMake(0, 0, 320, 568);
I'm pretty sure you can get rid of this line of code completely:
UIImageView *backgroundView = [[[UIImageView alloc] initWithImage:scaledImage] initWithFrame:viewFrame];
Now change viewFrame to self.window.frame.
In your example, you hard-coded the frame, so no matter what the device, it will always be that size.

Although I am not a UI expert, one thing which is peculiar is:
CGRect viewFrame = CGRectMake(0, 0, 320, 568);
Why is the size of viewFrame hard coded? Shouldn't it depend on the screen you are targeting? It should be proportional to the screen size.
And also, the background image should be a different size than the size of screen, and resolution is different on iPad and iPhone.
For this, either you can use the size of the screen to pick the appropriate image, as per the screen-size, or you can scale the image.

Get the bounds of the window and set the frame
UIImageView *backgroundView = [[[UIImageView alloc] initWithImage:scaledImage] initWithFrame:self.window.bounds];

Related

iAd banner position and screen height

I'm integrating iAds for the first time. It works. What I cannot seem to do is get it at the bottom on my screen. When I do what I think is the correct math it stops showing (or rather I dont see it) but changing the position to a hardcoded value works.
// Use RootViewController manage CCEAGLView
_viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];
_viewController.wantsFullScreenLayout = YES;
_viewController.view = eaglView;
// Set RootViewController to window
if ([[UIDevice currentDevice].systemVersion floatValue] < 6.0)
{
// warning: addSubView doesn't work on iOS6
[window addSubview: _viewController.view];
}
else
{
// use this method on ios6
[window setRootViewController:_viewController];
}
// iAd
adView = [[ADBannerView alloc] initWithFrame:CGRectZero];
CGRect adFrame = adView.frame;
adFrame.origin.y = adView.frame.size.height;
adView.frame = adFrame;
[_viewController.view addSubview:adView];
works but it shows like this:
When I try and change the position to the bottom based upon screen height - adView height I stop seeing it.
adFrame.origin.y = _viewController.view.frame.size.height - adView.frame.size.height;
I placed break points and it seems that this should be working based upon the values for height (1024) and adView (66)
UPDATE: I'm now trying to init specifying a rect
adView = [[ADBannerView alloc] initWithFrame:CGRectMake(0, [[UIScreen mainScreen] bounds].size.height - adView.frame.size.height, [[UIScreen mainScreen] bounds].size.width, adView.frame.size.height)];
[adView setDelegate:self];
[_viewController.view addSubview:adView];
Still not working, nothing shows anymore.
UPDATE 2: Trying this it does show, obviously not at the bottom
adView = [[ADBannerView alloc] initWithFrame:CGRectMake(0, 200, [[UIScreen mainScreen] bounds].size.width, 200)];
UPDATE 3: Trying this, it does show, obviously not at the bottom
adView = [[ADBannerView alloc] initWithFrame:CGRectMake(0, 200, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height)];
UPDATE 4: Trying this, works and it at the bottom, but I just made this up. Changing the 300 to 200 then nothing shows.
adView = [[ADBannerView alloc] initWithFrame:CGRectMake(0, [[UIScreen mainScreen] bounds].size.height - 300, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height)];
Why not use initWithFrame directly when creating banner view?
I do it as below in my app and it works fine for me
CGFloat adBannerHeight = 100.0f;
bannerView = [[ADBannerView alloc]initWithFrame:CGRectMake(0, [[UIScreen mainScreen] bounds].size.height - adBannerHeight,[[UIScreen mainScreen] bounds].size.width,adBannerHeight)];
[bannerView setDelegate:self];
[[self view] addSubview:bannerView];
Also, Please make sure you implement all necessary delegate methods

UIView does not show properly when the uitableview is scrolled down

I'm implementing some sort of loading screen consisting of a black coloured uiview with a spinner at it's center.
When the tableview has been scrolled down and the loading goes, the loading screen is at the top and if the tableview has been scrolled to the bottom, the loading screen disappears.
Function:
UIView *blackScreen = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
blackScreen.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5];
blackScreen.tag = LOADING_SCREEN_TAG;
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
spinner.center = CGPointMake(CGRectGetWidth(self.view.bounds)/2,
CGRectGetHeight(self.view.bounds)/2.3);
spinner.tag = SPINNER_TAG;
[spinner startAnimating];
[self.view addSubview:blackScreen];
[self.view addSubview:spinner];
[self.view setUserInteractionEnabled:NO];
You need to add contentOffset, I would like to refer you to this page which explains the use of it.
Here's the solution anyway, this is assuming that the variable name of your tableview is tableView and is set as a property of the class:
CGRect loadingScreenFrame = CGRectMake([[UIScreen mainScreen] bounds].origin.x + self.tableView.contentOffset.x,
[[UIScreen mainScreen] bounds].origin.y + self.tableView.contentOffset.y,
[[UIScreen mainScreen] bounds].size.width,
[[UIScreen mainScreen] bounds].size.height);
UIView *blackScreen = [[UIView alloc] initWithFrame:loadingScreenFrame];
blackScreen.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5];
blackScreen.tag = LOADING_SCREEN_TAG;
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
spinner.center = CGPointMake((CGRectGetWidth(self.view.bounds)/2) + self.tableView.contentOffset.x,
(CGRectGetHeight(self.view.bounds)/2.3) + self.tableView.contentOffset.y);
spinner.tag = SPINNER_TAG;
[spinner startAnimating];
[self.view addSubview:blackScreen];
[self.view addSubview:spinner];
[self.view setUserInteractionEnabled:NO];
A solution would be to not add the spinning view to the tableview but rather to its superview. It seems like you are probably using a UITableViewController which would mean that you would need to restructure your code to use a UIViewController to make this work. Adding both the UITableView and the spinner view to the view of the UIViewController would also achieve what you are looking for without having to set the center based on the content offset.

Trying to display images using UIScrollView

I want to create an simple app that will contain one centered image at the first start screen, than upon swipe gesture(right, left) change images.
I'm very new to this so here is what I though is what I'm looking for http://idevzilla.com/2010/09/16/uiscrollview-a-really-simple-tutorial/ .
This is the code I have in my controller implementation :
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] init];
[myDictionary setObject:#"img1.jpg" forKey:#"http://www.testweb.com"];
[myDictionary setObject:#"img2.jpg" forKey:#"http://www.test2.com"];
UIScrollView *scroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
scroll.pagingEnabled = YES;
NSInteger numberOfViews = [myDictionary count];
for (NSString* key in myDictionary) {
UIImage * image = [UIImage imageNamed:[NSString stringWithFormat:[myDictionary objectForKey:key]]];
CGRect rect = CGRectMake(10.0f, 90.0f, image.size.width, image.size.height);
UIImageView * imageView = [[UIImageView alloc] initWithFrame:rect];
[imageView setImage:image];
CGPoint superCenter = CGPointMake([self.view bounds].size.width / 2.0, [self.view bounds].size.height / 2.0);
[imageView setCenter:superCenter];
self.view.backgroundColor = [UIColor whiteColor];
[scroll addSubview:imageView];
}
scroll.contentSize = CGSizeMake(self.view.frame.size.width * numberOfViews, self.view.frame.size.height);
[self.view addSubview:scroll];
}
My first issue here is that I get img2 on my initial screen instead of img1. And second issue is when I swipe right I get white screen and no image on it. Any suggestions what I missed, what I can try/read etc?
EDIT :
I'm looking to do this the "lightest" possible way, using no fancy galleries api etc. Just display couple of really small images(i.e 200x200 px) centered on the screen that I can swipe back and forth(should't be too hard). Well everything is hard when learning a new language.
There is a project on github MWPhotoBrowser that allows you to put in a set of images which are viewed one at a time. You can then scroll from one image to the next with a swipe gesture. It is also easy to add functionality and it should give you a good understanding of how this is done. There is also Apple's PhotoScroller example which gives you straight forward code in how to do this same thing and also tile your images. Since you are new to iOS you may want to first look at both of these examples or possibly just use them as your photo viewer.
Your problem is likely to be the fact that you are setting CGRect rect = CGRectMake(10.0f, 90.0f, image.size.width, image.size.height); for both of your image views. This means that both of your UIImageView objects are placed in exactly the same position (both are positioned at 10.f on the x-coordinate of the scrollview). As the second image view is added last it covers the first and means that there is white space to the right of it.
In order to fix this you could try something like...
- (void)viewDidLoad
{
//your setup code
float xPosition = 10.f;
for (NSString* key in myDictionary) {
UIImage * image = [UIImage imageNamed:[NSString stringWithFormat:[myDictionary objectForKey:key]]];
CGRect rect = CGRectMake(xPosition, 90.0f, image.size.width, image.size.height);
xPosition += image.size.width;
//rest of your code...
}
//rest of your code
}
The above would mean that the second view is positioned on the x-coordinate at 10 + the width of the first image. Note that I haven't tested my answer.
First off the images are placed on top of each other.
CGPoint superCenter = CGPointMake([self.view bounds].size.width / 2.0, [self.view bounds].size.height / 2.0);
[imageView setCenter:superCenter];
Right here you are setting both images to be placed at the center of the screen. The second thing is your using an NSDictionary and looping through the keys. NSDictionary are not orders like an array is. You would have to sort the keys to us it in a specific order. So Barjavel had it right but skipped over the fact your setting the images to center. Try this:
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *myArray = [[NSArray alloc] initWithObjects:#"img1.jpg", #:image2.jpg", nil];
UIScrollView *scroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
scroll.pagingEnabled = YES;
NSInteger numberOfViews = [myArray count];
int xPosition = 0;
for (NSString* image in myArray) {
UIImage * image = [UIImage imageNamed:image];
CGRect rect = CGRectMake(xPosition, 90.0f, image.size.width, image.size.height);
UIImageView * imageView = [[UIImageView alloc] initWithFrame:rect];
[imageView setImage:image];
self.view.backgroundColor = [UIColor whiteColor];
[scroll addSubview:imageView];
xPosition += image.size.width;
}
scroll.contentSize = CGSizeMake(self.view.frame.size.width * numberOfViews, self.view.frame.size.height);
[self.view addSubview:scroll];
}

UIImage/UIImageView redraw when containing UIView is scaled

My iPad app has a navigation where I show screenshots of the different pages and because I want to show more than one screenshot at once I scale the container to around 24% of the original screenshots (1024x768).
- (void) loadView
{
// get landscape screen frame
CGRect screenFrame = [UIScreen mainScreen].bounds;
CGRect landscapeFrame = CGRectMake(0, 0, screenFrame.size.height, screenFrame.size.width);
UIView *view = [[UIView alloc] initWithFrame:landscapeFrame];
view.backgroundColor = [UIColor grayColor];
self.view = view;
// add container view for 2 images
CGRect startFrame = CGRectMake(-landscapeFrame.size.width/2, 0, landscapeFrame.size.width*2, landscapeFrame.size.height);
container = [[UIView alloc] initWithFrame:startFrame];
container.backgroundColor = [UIColor whiteColor];
// add image 1 (1024x768)
UIImage *img1 = [UIImage imageNamed:#"01.jpeg"];
UIImageView *img1View = [[UIImageView alloc] initWithImage:img1];
[container addSubview:img1View];
// add image 2 (1024x768)
UIImage *img2 = [UIImage imageNamed:#"02.jpeg"];
UIImageView *img2View = [[UIImageView alloc] initWithImage:img2];
// move img2 to the right of img1
CGRect newFrame = img2View.frame;
newFrame.origin.x = 1024.0;
img2View.frame = newFrame;
[container addSubview:img2View];
// scale to 24%
container.transform = CGAffineTransformMakeScale(0.24, 0.24);
[self.view addSubview:container];
}
but when I scale images with "small" text it looks sth like this:
I have to use the big screenshots because if a user taps the image it should scale to 100% and be crispy clear.
is there a way how I can scale the images "smoothly" (on the fly) without ruining performance?
it would be enough to have two versions: the full-px one and another for the 24% version.
The reason the scaled-down image looks crappy is it's being scaled in OpenGL, which is using fast-but-low-quality linear interpolation. As you probably know, UIView is built on top of CALayer, which is in turn a sort of wrapper for OpenGL textures. Because the contents of the layer reside in the video card, CALayer can do all of its magic on the GPU, independent of whether the CPU is busy loading a web site, blocked on disk access, or whatever. I mention this only because it's useful to pay attention to what's actually in the textures inside your layers. In your case, the UIImageView's layer has the full 1024x768 bitmap image on its texture, and that isn't affected by the container's transform: The CALayer inside the UIImageView doesn't see that it's going to be (let's see..) 246x185 on-screen and re-scale its bitmap, it just lets OpenGL do its thing and scale down the bitmap every time it updates the display.
To get better scaling, we'll need to do it in CoreGraphics instead of OpenGL. Here's one way to do it:
- (UIImage*)scaleImage:(UIImage*)image by:(float)scale
{
CGSize size = CGSizeMake(image.size.width * scale, image.size.height * scale);
UIGraphicsBeginImageContextWithOptions(size, YES, 0.0);
[image drawInRect:CGRectMake(0, 0, size.width, size.height)];
UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return imageCopy;
}
- (void)loadView
{
// get landscape screen frame
CGRect screenFrame = [UIScreen mainScreen].bounds;
CGRect landscapeFrame = CGRectMake(0, 0, screenFrame.size.height, screenFrame.size.width);
UIView *view = [[UIView alloc] initWithFrame:landscapeFrame];
view.backgroundColor = [UIColor grayColor];
self.view = view;
// add container view for 2 images
CGRect startFrame = CGRectMake(-landscapeFrame.size.width/2, 0, landscapeFrame.size.width*2, landscapeFrame.size.height);
container = [[UIView alloc] initWithFrame:startFrame];
container.backgroundColor = [UIColor whiteColor];
// add image 1 (1024x768)
UIImage *img1 = [UIImage imageNamed:#"01.png"];
img1View = [[TapImageView alloc] initWithFrame:CGRectMake(0, 0, 1024, 768)];
img1View.userInteractionEnabled = YES; // important!
img1View.image = [self scaleImage:img1 by:0.24];
[container addSubview:img1View];
// add image 2 (1024x768)
UIImage *img2 = [UIImage imageNamed:#"02.png"];
img2View = [[TapImageView alloc] initWithFrame:CGRectMake(1024, 0, 1024, 768)];
img2View.userInteractionEnabled = YES;
img2View.image = [self scaleImage:img2 by:0.24];
[container addSubview:img2View];
// scale to 24% and layout subviews
zoomed = YES;
container.transform = CGAffineTransformMakeScale(0.24, 0.24);
[self.view addSubview:container];
}
- (void)viewTapped:(id)sender
{
zoomed = !zoomed;
[UIView animateWithDuration:0.5 animations:^
{
if ( zoomed )
{
container.transform = CGAffineTransformMakeScale(0.24, 0.24);
}
else
{
img1View.image = [UIImage imageNamed:#"01.png"];
img2View.image = [UIImage imageNamed:#"02.png"];
container.transform = CGAffineTransformMakeScale(1.0, 1.0);
}
}
completion:^(BOOL finished)
{
if ( zoomed )
{
UIImage *img1 = [UIImage imageNamed:#"01.png"];
img1View.image = [self scaleImage:img1 by:0.24];
UIImage *img2 = [UIImage imageNamed:#"02.png"];
img2View.image = [self scaleImage:img2 by:0.24];
}
}];
}
And here's TapImageView, a UIImageView subclass that tells us when it's been tapped by sending an action up the responder chain:
#interface TapImageView : UIImageView
#end
#implementation TapImageView
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
[[UIApplication sharedApplication] sendAction:#selector(viewTapped:) to:nil from:self forEvent:event];
}
#end
Instead of scaling the container and all of its subviews. Create a UIImageView from the contents of the container and adjust its frame size to 24% of the original.
UIGraphicsBeginImageContext(container.bounds.size);
[container renderInContext:UIGraphicsGetCurrentContext()];
UIImage *containerImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView *containerImageView = [[UIImageView alloc] initWithImage:containerImage];
CGRectFrame containerFrame = startFrame;
containerFrame.size.with *= 0.24;
containerFrame.size.height *= 0.24;
containerImageView.frame = containerFrame;
[self.view addSubView:containerImageView];

Creating Views without IB

It's pretty embarrassing asking this because I've been building apps for a while now. In the past I've always used Interface Builder to set up my views etc.
Here is my loadView:
- (void)loadView {
UIView *splashView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
splashView.backgroundColor = [UIColor clearColor];
UIImageView *splashImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[[NSBundle mainBundle]pathForResource:#"splash" ofType:#"jpg"]]];
splashImage.frame = [splashView bounds];
[splashView addSubview:splashImage];
self.view = splashView;
}
For some reason the imageView isn't appearing. No errors, but just no appearance. The UIView is added, but the UIImageView isn't.
Like I said, I've traditionally done this with IB so I'm not so familiar with the programatic method.
Any help appreciated.
Add splashView to self.view:
self.view = splashView;
or add your splashImage into self.view. In this case you don't need the UIView - splashView:
UIImageView *splashImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[[NSBundle mainBundle]pathForResource:#"splash" ofType:#"jpg"]]];
splashImage.frame = [splashView bounds];
[self.view addSubview:splashImage];
Try not creating a new view called splash view and just add the image view to your self.view.