My main app has to do some work in a webview, so I want to keep the launch image up longer while this work takes place. To do this, I created a controller with a UIImageView and I'm loading the Default image up in it:
self.imageView.image = [UIImage imageNamed:"Default"];
// These all tend to fill the screen, but end up distorting the image
//self.imageView.contentMode = UIViewContentModeScaleAspectFill;
//self.imageView.contentMode = UIViewContentModeScaleAspectFit;
//self.imageView.contentMode = UIViewContentModeScaleToFill;
// This keeps the aspect the same, but doesn't fill the screen
self.imageView.contentMode = UIViewContentModeCenter;
This mostly works, except when the real launch image goes away and is replaced with mine, I have two white bars - one at the top and one at the bottom - where the image doesn't completely fill. I've tried to set the contentMode to the various fill/fit's, and even though this has the desired effect of filling the full screen, it stretches and distorts the image slightly.
So what I'm wondering is - what does the launch image do that I'm not doing? How can I replicate the display exactly so that the user can't tell it's a different image?
Like in your project I use a launch image and then in the first UIViewController called I have an UIImageView inside. The image resolution, must be exactly the same as the screen's definition.
The code in the UIViewController is something like this :
CGRect fullFrame = [[UIScreen mainScreen] bounds];
// Img Background
UIImageView *background;
if (fullFrame.size.height <= 480) {
background = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"image-480h.png"]];
}
else if (fullFrame.size.height <= 568) {
background = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"image-568h.png"]];
}
else if (fullFrame.size.height <= 668) {
background = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"image-668h.png"]];
}
else {
background = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"image-736h.png"]];
}
background = CGRectMake(0, 0, frame.size.width, fullFrame.size.height);
myMainView = [[UIView alloc] initWithFrame:frame];
[myMainView addSubview:background];
self.view = myMainView;
I check the different screen size depending on the iPhone 4, 5, 6 and 6 plus.
Related
I am using the following code to show the splash screen :
UIImageView *defaultImage = [[UIImageView alloc] init];
defaultImage.frame = defaultImageFrame;
// for iOS 9 Compatability
//NSMutableArray *buttonsArray = [[NSMutableArray alloc] initWithCapacity:1];
NSMutableArray *buttonsArray = [NSMutableArray arrayWithCapacity:1];
for (int i = 1; i<=3; i++)
{
[buttonsArray addObject:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"img00%d", i] ofType:#"png"]]];
}
mAnimatedButtons = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, WIDTH_DEVICE, HEIGHT_DEVICE)];
[mAnimatedButtons setUserInteractionEnabled:NO];
[mAnimatedButtons setAnimationImages:buttonsArray];
[mAnimatedButtons setAnimationRepeatCount:0];
[mAnimatedButtons setAnimationDuration:2.0];
[mAnimatedButtons startAnimating];
[defaultImage addSubview:mAnimatedButtons];
[self.view addSubview:defaultImage];
And i will remove the splash screen after this
[mAnimatedButtons stopAnimating]; //here animation stops
[mAnimatedButtons removeFromSuperview]; // here view removes from view hierarchy
mAnimatedButtons = nil;
self.defaultImage=nil;
[self.defaultImage removeFromSuperview];
[self.view.layer removeAllAnimations];
for (CALayer* layer in [self.view.layer sublayers])
{
[layer removeAllAnimations];
}
Adding this code increases the memory usage upto 300 Mb.
Removing this it has only 100 Mb.
I tried the following code also
self.defaultImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, WIDTH_DEVICE, HEIGHT_DEVICE)];
self.defaultImage.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"img001.png"],
[UIImage imageNamed:#"img002.png"],
[UIImage imageNamed:#"img003.png"],
nil];
//self.defaultImage.animationDuration = 1.0f;
self.defaultImage.animationRepeatCount = 0;
[self.defaultImage setAnimationDuration:2.0];
[ self.defaultImage startAnimating];
[self.view addSubview: self.defaultImage];
Even though the result is same.
Images, when used in the app, may require considerably more memory than the size of the asset in persistent storage might otherwise suggest. Assets are frequently compressed (e.g. JPG or PNG), but when you use the image, they're uncompressed, often requiring 4 bytes per pixel (one byte for red, green, blue, and alpha, respectively). So, for example, a iPhone 7+ full-screen retina image can require 14mb when you use the image. So, the memory-efficient technique is to employ lazy loading, not creating the UIImage objects until you absolutely need them. And, as Jerry suggested, because the amount of memory is determined by the size of the image and not the imageview in which you use the image, if your images have dimensions greater than required by the UIImageView in which you use them (i.e. width and height of the imageview times the "scale" of the device), you may want to resize the image accordingly.
I'm trying to set up my app so that on an iPhone4s, a different background image is displayed, but the code below produces a black background. Can anyone see what I'm doing wrong?
Thank you
UIImageView *bgImageView = [[UIImageView alloc] initWithFrame: self.view.bounds];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
bgImageView.image = [UIImage imageNamed: #"background_rest-ipad.png"];
}
else if ( [GUIHelper isPhone5] ) {
bgImageView.image = [UIImage imageNamed: #"info-screen-bg#2x.png"];
}
else {
bgImageView.image = [UIImage imageNamed: #"info-screen-bg-i4s.png"];
}
bgImageView.userInteractionEnabled = YES;
bgImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview: bgImageView];
You can use Asset Catalog and it will manage your images based on device...
Thought, with your code, make sure the names of the image files are correct and the files itself are present.
I'm trying to create some composite UIImage objects with this code:
someImageView.image = [ImageMaker coolImage];
ImageMaker:
- (UIImage*)coolImage {
UIView *composite = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 400, 400)];
UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"coolImage"]]; //This is a valid image - can be viewed when debugger stops here
[composite addSubview:imgView];
UIView *snapshotView = [composite snapshotViewAfterScreenUpdates:YES];
//at this point snapshotView is just a blank image
UIImage *img = [self imageFromView:snapshotView];
return img;
}
- (UIImage *)imageFromView:(UIView *)view
{
UIGraphicsBeginImageContextWithOptions(view.bounds.size, YES, 0.0);
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:NO];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
I just get back a blank black image. How can I fix?
Supplying YES for -snapshotViewAfterScreenUpdates: means it needs a trip back to the runloop to actually draw the image. If you supply NO, it will try immediately, but if your view is off screen or otherwise hasn't yet drawn to the screen, the snapshot will be empty.
To reliably get an image:
- (void)withCoolImage:(void (^)(UIImage *))block {
UIView *composite = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 400, 400)];
UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"coolImage"]]; //This is a valid image - can be viewed when debugger stops here
[composite addSubview:imgView];
UIView *snapshotView = [composite snapshotViewAfterScreenUpdates:YES];
// give it a chance to update the screen…
dispatch_async(dispatch_get_main_queue(), ^
{
// … and now it'll be a valid snapshot in here
if(block)
{
block([self imageFromView:snapshotView]);
}
});
}
You would use it like this:
[someObject withCoolImage:^(UIImage *image){
[self doSomethingWithImage:image];
}];
The snapshotted view has to be drawn to the screen for a snapshot view to not be blank. In your case, the composite view must have a superview for drawing to work.
However, you should not be using the snapshotting API for this kind of action. It is very inefficient to create a view hierarchy for the sole purpose of creating an image. Instead, use the Core Graphics API's to setup a bitmap image context, perform drawing and get back the result using UIGraphicsGetImageFromCurrentImageContext().
The reason it's only rendering a black rectangle is because you're drawing the view hierarchy of the snapshot view, which is non-existent.
To make it work, you should pass composite as the parameter like so:
- (UIImage*)coolImage {
UIView *composite = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 400, 400)];
UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"coolImage"]]
[composite addSubview:imgView];
UIImage *img = [self imageFromView:composite];
// Uncomment if you don't want composite to have imgView as its subview
// [imgView removeFromSuperview];
return img;
}
I'm running into a problem trying to perform a certain effect on iOS with tableviews...I know this can be done with normal UIViewControllers, but can't seem to pull it off with UITableViewControllers.
The effect is showing a clear background image behind a tableview and and as the user scrolls down the tableview, the background blurs. No problem getting that to happen.
The issue I'm having is that using a UITableViewController, I can only seem to have 1 ImageView behind the TableView and to create the blurring effect, the extension i am using will require 2 image views, one of which is the blurred image and has it's opacity set to 0 at launch.
This is code I know works using a UIViewController:
UIImage *background = [UIImage imageNamed:#"bg_004.png"];
self.backgroundImageView = [[UIImageView alloc] initWithImage:background];
self.backgroundImageView.contentMode = UIViewContentModeScaleAspectFill;
[self.view addSubview:self.backgroundImageView];
self.blurredImageView = [[UIImageView alloc] init];
self.blurredImageView.contentMode = UIViewContentModeScaleAspectFill;
self.blurredImageView.alpha = 0;
[self.blurredImageView setImageToBlur:background blurRadius:10 completionBlock:nil];
[self.view addSubview:self.blurredImageView];
This is the code I am trying on the UITableViewController that does not work:
UIImage *background = [UIImage imageNamed:#"bg_004.png"];
self.backgroundImageView = [[UIImageView alloc] initWithImage:background];
self.backgroundImageView.contentMode = UIViewContentModeScaleAspectFill;
[self.tableView setBackgroundView:self.backgroundImageView];
// Also tried this, to no success
[self.tableView.backgroundView addSubview:self.blurredBackgroundView];
self.blurredBackgroundView = [[UIImageView alloc] init];
self.blurredBackgroundView.contentMode = UIViewContentModeScaleAspectFill;
self.blurredBackgroundView.alpha = 0;
[self.blurredBackgroundView setImageToBlur:background blurRadius:10 completionBlock:nil];
[self.tableView setBackgroundView:self.blurredBackgroundView];
// Also tried this, to no success
[self.tableView.backgroundView addSubview:self.blurredBackgroundView];
If anyone has some suggestions how how to make this work, i'd love some advice. I really wouldn't like to change my code from a TableViewController to a UIViewController
Set the table view's backgroundView property to point to an instance of UIView, and then add your image views as subviews of the new view. You can't directly add subviews to instances of UIImageView
The code below works fine in one of two possible landscape orientations but when i turn the device 180 to the other lanscepe orientation the images i load are bottom up compared with the views that are underneath.
So what I have is a view (to overlay over the whole screen, that has images on it) created in code on-top of views created on a storyboard.
And the QUESTION IS : Can the top left corner of the semi-transparent-overlay-view be drawn at the same place that the top left corner of where a underlying view is?. I need the overlay view to turn with underlying views.
Here I let the view cover (overlay) the whole screen
self.overlayView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0,[[UIScreen mainScreen] bounds].size.width,[[UIScreen mainScreen] bounds].size.height)];
Then I load up the images I like to show on the view.
UIImage* image = [UIImage imageNamed:#"image.png"];
and here I set the image
[overlayView setImage:image];
I have tried everything with orientation with no luck. Note that my app auto-rotates 360° so the status bar is always up top.
Hope this makes sens to somebody!
Edit: Here is the whole code used
UIWindow* keyWindow = [UIApplication sharedApplication].keyWindow;
self.overLayView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0,[[UIScreen mainScreen] bounds].size.width,[[UIScreen mainScreen] bounds].size.height)];
[overLayView setImage:[UIImage imageNamed:#"someImage1.png"]];
overLayView.tag = 1; //Used to remove the view in another function
overLayView.backgroundColor = [UIColor colorWithWhite:0.5 alpha:0.5]; //Semi transparent
CGRect viewFrames = CGRectMake([[UIScreen mainScreen] bounds].size.width - 100, [[UIScreen mainScreen] bounds].size.height - 100, 75, 75);
self.exitHelpView = [[UIImageView alloc] initWithFrame:viewFrames];
[self.exitHelpView setImage:[UIImage imageNamed:#"imageOfXUsedToCloseWhenClicked.png"]];
self.exitHelpView.tag = 2; //Used to remove the view in another function
[keyWindow addSubview:overLayView]; //The view covering the whole screen
[keyWindow addSubview:self.exitHelpView]; //Image of an X
And in my .h file
#property (strong, nonatomic) IBOutlet UIImageView* overLayView;
#property (strong, nonatomic) IBOutlet UIImageView* exitHelpView;
Things you add to the UIWindow will not respect device rotations. This is one of the big features of the UIViewController--responding to rotation events automatically. If you can't find a way for it to work by adding the view to a UIViewController's view hierarchy, then you'll need to manually listen for rotation events and programmatically adjust the positioning of your UIView.