I wanna build a gallery, but the my problem is how to load the #2x images?
Will iOS try to search for them or i can specify the path?
When you load the image From server.
Firstly You send request /Connection to Server that time you send imagesSize to server
Example:- www.example.com/iPhone/abc.php?imagesSize = 1
where ! for #2x
0 for simple(means for non retina)
if you use this method then images not starch.
you can store two versions of image, one for retina and one for non retina. when the device is about to download images from the web server, (assuming you are using webservice script)you can have a post data like:
NSString *postData;
if ([[UIScreen mainScreen] respondsToSelector:#selector(displayLinkWithTarget:selector:)] &&
([UIScreen mainScreen].scale == 2.0)) {
postData = #"retina_device";
} else {
postData = #"non_retina_device";
}
you will know what version of image the device is asking, assuming you will write webservice sript in php
<?php
$postData = $_REQUEST['postData'];
if($postData == #"retina_device"){
//return all images for retina device
}
?>
Using this if/else block
if ([[UIScreen mainScreen] respondsToSelector:#selector(displayLinkWithTarget:selector:)] &&
([UIScreen mainScreen].scale == 2.0)) {
// Retina display
} else {
// non-Retina display
}
You can detect whether you're on a retina display or standard display model and then load the correct image.
Related
It seems in macOS 10.14 Mojave, the only way to create NSImage instances that automatically draw a light and dark version is via asset catalogs and +[NSImage imageNamed:]. However, I need to create dynamic images at runtime and there doesn't seem to be a way to do so without using private API.
Under the hood, it seems a private property _appearanceName has been introduced to NSImageRep that is somehow used to select the correct representation. It should be straight forward to create an NSImage with image representations that have the corresponding _appearanceName set but I would like to avoid this.
I found a simple workaround (posted below) but it doesn't seem to work correctly when the system appearance is changing (i.e. user is switching from light to dark or vice versa) or when used in view hierarchies that have the appearance property set to different appearances (e.g. one view hard-coded to dark mode, another view hard-coded to light mode).
So, how can I manually create a dynamic NSImage that is correctly showing a light or dark version, like the asset catalog images do?
#implementation NSImage (CustomDynamic)
+ (NSImage *)imageWithLight:(NSImage *)light dark:(NSImage *)dark
{
if (#available(macOS 10.14, *)) {
return [NSImage
imageWithSize:light.size
flipped:NO
drawingHandler:^(NSRect dstRect) {
if ([NSImage appearanceIsDarkMode:NSAppearance.currentAppearance]) {
[dark drawInRect:dstRect];
} else {
[light drawInRect:dstRect];
}
return YES;
}
];
} else {
return light;
}
}
+ (BOOL)appearanceIsDarkMode:(NSAppearance *)appearance
{
if (#available(macOS 10.14, *)) {
NSAppearanceName basicAppearance = [appearance bestMatchFromAppearancesWithNames:#[
NSAppearanceNameAqua,
NSAppearanceNameDarkAqua
]];
return [basicAppearance isEqualToString:NSAppearanceNameDarkAqua];
} else {
return NO;
}
}
#end
D'uh, it turned out the code posted in the question works just fine! The drawing handler is in fact called at appropriate times and does handle all the appearance situations.
However, I had code that scaled and cached those images and it was still using the ancient [image lockFocus]; … [image unlockFocus]; way of drawing images instead of using +[NSImage imageWithSize:flipped:drawingHandler:].
I am building a note editor using the Text Kit in ios7. Earlier I had trouble in rendering of custom size NSTextAttachment's as it was slowing down the rendering to a great extent.I solved the issue by scaling the images and then adding them to textview.You can find my answer in
iOS 7.0 UITextView gettings terribly slow after adding images to it
After scaling the images the textview rendering runs fine without any lag.The attributed text of textview is stored in core data.During a running session of application the textview displays the images correctly.Even after saving the attributed text in the core data and retrieving it again to display on textview,the images look fine.But after killing the app and again running the application.The images get enlarged to 2x size.while scaling the images I used the following function and used [[UIScreen bounds] scale] to maintain the image quality.
- (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
UIGraphicsBeginImageContextWithOptions(newSize, NO, [UIScreen mainScreen].scale);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
If I scale the images to 1.0 the images doesn't expand but the image quality is very bad.
What I Think where the problem lies?
The problem lies in the layout manager.
What I have Tried
I have tried subclassing the NSLayoutManager and overriding the
- (void)drawGlyphsForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origin
What I see is the attachment size is doubling when running a new session of the application.If I try to check the size of attachment and resize it.The lag starts coming again.
I am stucked with this problem from a quite time.Any suggestions would be much appreciated.
Could the reason due to retina display? If it is retina, you might need to reduce the size by 50% before storing. How about trying this:-
//Original Size that you want to store
CGSize imageSize = CGSizeMake(320.0f, 320.0f);
//Make the image 50% of the size for retina
if ([[UIScreen mainScreen] respondsToSelector:#selector(displayLinkWithTarget:selector:)] &&([UIScreen mainScreen].scale == 2.0)) {
// Retina display
imageSize = CGSizeMake(160.0f, 160.0f);
}
UIImage * storeImage = [self imageWithImage:self.image scaledToSize:imageSize]
//TODO: Store this image locally or whatever you want to do.
#interface MMTextAttachment : NSTextAttachment
{
}
#end
#implementation MMTextAttachment
//I want my emoticon has the same size with line's height
- (CGRect)attachmentBoundsForTextContainer:(NSTextContainer *)textContainer proposedLineFragment:(CGRect)lineFrag glyphPosition:(CGPoint)position characterIndex:(NSUInteger)charIndex NS_AVAILABLE_IOS(7_0)
{
return CGRectMake( 0 , 0 , lineFrag.size.height , lineFrag.size.height );
}
#end
I think you can try this.
I am trying to add a correct sized background image to support iPhone5 4" screen but i am still getting the same letterbox in the bottom. The image is correct sized image.
The code i use:
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
CGSize result = [[UIScreen mainScreen] bounds].size;
if(result.height == kIphone5) {
//====THIS IS AN iPhone5 4" screen====//
UIImage *image = [UIImage imageNamed:#"iphone_frosty-568h#2x.png"];
[backgroundImage setImage:image];
}
I do have the lanch image in place..
UPDATE
I ended up adding the iPhone5 background image to the iPhone5 Storyboard and use that for all iPhone modes. Do not know if that is a correct way of doing this but it seems to work.
Can someone please advice?
Are you just talking about making your app run using the full screen on an iPhone 5 (getting rid of the letterbox)? If so, you don't use the new image size as a background image somewhere in code; you have to add it to your project file as a launch image. See the Launch Images section of the Apple docs for more info.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to develop or migrate apps for iPhone 5 screen resolution?
I was just wondering with how should we deal with the iPhone 5 bigger screen size.
As it has more pixels in height, things like GCRectMake that use coordinates (and just doubled the pixels with the retina/non retina problem) won't work seamlessly between versions, as it happened when we got the Retina.
And will we have to design two storyboards, just like for the iPad?
I personally don't think Apple will require you to check the screen size every time you have to draw something, like many answers say. Does that happen with the iPad?
All apps will continue to work in the vertically stretched screen from what I could tell in today's presentation. They will be letterboxed or basically the extra 88 points in height would simply be black.
If you only plan to support iOS 6+, then definitely consider using Auto Layout. It removes all fixed layout handling and instead uses constraints to lay things out. Nothing will be hard-coded, and your life will become a lot simpler.
However, if you have to support older iOS's, then it really depends on your application. A majority of applications that use a standard navigation bar, and/or tab bar, could simply expand the content in the middle to use up that extra points. Set the autoresizing mask of the center content to expand in both directions.
view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
It works great out of the box for table views, however, if your app used pixel-perfect layout for displaying content, then your best bet would be to re-imagine the content so that it can accommodate varying heights.
If that's not a possibility, then the only remaining option is to have two UIs (pre iPhone 5, and iPhone 5).
If that sounds ugly, then you could go with the default letterboxed model where the extra points/pixels just show up black.
Edit
To enable your apps to work with iPhone 5, you need to add a retina version of the launcher image. It should be named Default-568h#2x.png. And it has to be retina quality - there's no backward compatibility here :)
You could also select this image from within Xcode. Go to the target, and under the Summary section, look for Launch Images. The image has to be 640x1136 pixels in size. Here's a screenshot of where to find it, if that helps.
You need to add a 640x1136 pixels PNG image (Default-568h#2x.png) as a 4 inch default splash image of your project, and it will use extra spaces (without efforts on simple table based applications, games will require more efforts).
I've created a small UIDevice category in order to deal with all screen resolutions. You can get it here, but the code is as follows:
File UIDevice+Resolutions.h:
enum {
UIDeviceResolution_Unknown = 0,
UIDeviceResolution_iPhoneStandard = 1, // iPhone 1,3,3GS Standard Display (320x480px)
UIDeviceResolution_iPhoneRetina4 = 2, // iPhone 4,4S Retina Display 3.5" (640x960px)
UIDeviceResolution_iPhoneRetina5 = 3, // iPhone 5 Retina Display 4" (640x1136px)
UIDeviceResolution_iPadStandard = 4, // iPad 1,2,mini Standard Display (1024x768px)
UIDeviceResolution_iPadRetina = 5 // iPad 3 Retina Display (2048x1536px)
}; typedef NSUInteger UIDeviceResolution;
#interface UIDevice (Resolutions)
- (UIDeviceResolution)resolution;
NSString *NSStringFromResolution(UIDeviceResolution resolution);
#end
File UIDevice+Resolutions.m:
#import "UIDevice+Resolutions.h"
#implementation UIDevice (Resolutions)
- (UIDeviceResolution)resolution
{
UIDeviceResolution resolution = UIDeviceResolution_Unknown;
UIScreen *mainScreen = [UIScreen mainScreen];
CGFloat scale = ([mainScreen respondsToSelector:#selector(scale)] ? mainScreen.scale : 1.0f);
CGFloat pixelHeight = (CGRectGetHeight(mainScreen.bounds) * scale);
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){
if (scale == 2.0f) {
if (pixelHeight == 960.0f)
resolution = UIDeviceResolution_iPhoneRetina4;
else if (pixelHeight == 1136.0f)
resolution = UIDeviceResolution_iPhoneRetina5;
} else if (scale == 1.0f && pixelHeight == 480.0f)
resolution = UIDeviceResolution_iPhoneStandard;
} else {
if (scale == 2.0f && pixelHeight == 2048.0f) {
resolution = UIDeviceResolution_iPadRetina;
} else if (scale == 1.0f && pixelHeight == 1024.0f) {
resolution = UIDeviceResolution_iPadStandard;
}
}
return resolution;
}
#end
This is how you need to use this code.
1) Add the above UIDevice+Resolutions.h & UIDevice+Resolutions.m files to your project
2) Add the line #import "UIDevice+Resolutions.h" to your ViewController.m
3) Add this code to check what versions of device you are dealing with
int valueDevice = [[UIDevice currentDevice] resolution];
NSLog(#"valueDevice: %d ...", valueDevice);
if (valueDevice == 0)
{
//unknow device - you got me!
}
else if (valueDevice == 1)
{
//standard iphone 3GS and lower
}
else if (valueDevice == 2)
{
//iphone 4 & 4S
}
else if (valueDevice == 3)
{
//iphone 5
}
else if (valueDevice == 4)
{
//ipad 2
}
else if (valueDevice == 5)
{
//ipad 3 - retina display
}
I have just finished updating and sending an iOS 6.0 version of one of my Apps to the store. This version is backwards compatible with iOS 5.0, thus I kept the shouldAutorotateToInterfaceOrientation: method and added the new ones as listed below.
I had to do the following:
Autorotation is changing in iOS 6. In iOS 6, the shouldAutorotateToInterfaceOrientation: method of UIViewController is deprecated. In its place, you should use the supportedInterfaceOrientationsForWindow: and shouldAutorotate methods.
Thus, I added these new methods (and kept the old for iOS 5 compatibility):
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
Used the view controller’s viewWillLayoutSubviews method and adjust the layout using the view’s bounds rectangle.
Modal view controllers: The willRotateToInterfaceOrientation:duration:,
willAnimateRotationToInterfaceOrientation:duration:, and
didRotateFromInterfaceOrientation: methods are no longer called on
any view controller that makes a full-screen presentation over
itself—for example, presentViewController:animated:completion:.
Then I fixed the autolayout for views that needed it.
Copied images from the simulator for startup view and views for the iTunes store into PhotoShop and exported them as png files.
The name of the default image is: Default-568h#2x.png and the size is 640×1136. It´s also allowed to supply 640×1096 for the same portrait mode (Statusbar removed). Similar sizes may also be supplied in landscape mode if your app only allows landscape orientation on the iPhone.
I have dropped backward compatibility for iOS 4. The main reason for that is because support for armv6 code has been dropped. Thus, all devices that I am able to support now (running armv7) can be upgraded to iOS 5.
I am also generation armv7s code to support the iPhone 5 and thus can
not use any third party frameworks (as Admob etc.) until they are
updated.
That was all but just remember to test the autorotation in iOS 5 and iOS 6 because of the changes in rotation.
No.
if ([[UIScreen mainScreen] bounds].size.height > 960)
on iPhone 5 is wrong
if ([[UIScreen mainScreen] bounds].size.height == 568)
#interface UIDevice (Screen)
typedef enum
{
iPhone = 1 << 1,
iPhoneRetina = 1 << 2,
iPhone5 = 1 << 3,
iPad = 1 << 4,
iPadRetina = 1 << 5
} DeviceType;
+ (DeviceType)deviceType;
#end
.m
#import "UIDevice+Screen.h"
#implementation UIDevice (Screen)
+ (DeviceType)deviceType
{
DeviceType thisDevice = 0;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
thisDevice |= iPhone;
if ([[UIScreen mainScreen] respondsToSelector: #selector(scale)])
{
thisDevice |= iPhoneRetina;
if ([[UIScreen mainScreen] bounds].size.height == 568)
thisDevice |= iPhone5;
}
}
else
{
thisDevice |= iPad;
if ([[UIScreen mainScreen] respondsToSelector: #selector(scale)])
thisDevice |= iPadRetina;
}
return thisDevice;
}
#end
This way, if you want to detect whether it is just an iPhone or iPad (regardless of screen-size), you just use:
if ([UIDevice deviceType] & iPhone)
or
if ([UIDevice deviceType] & iPad)
If you want to detect just the iPhone 5, you can use
if ([UIDevice deviceType] & iPhone5)
As opposed to Malcoms answer where you would need to check just to figure out if it's an iPhone,
if ([UIDevice currentResolution] == UIDevice_iPhoneHiRes ||
[UIDevice currentResolution] == UIDevice_iPhoneStandardRes ||
[UIDevice currentResolution] == UIDevice_iPhoneTallerHiRes)`
Neither way has a major advantage over one another, it is just a personal preference.
#Pascal's comment on the OP's question is right. By simply adding the image, it removes the black borders and the app will use the full height.
You will need to make adjustments to any CGRects by determining that the device is using the bigger display. I.e. If you need something aligned to the bottom of the screen.
I am sure there is a built in method, but I haven't seen anything and a lot is still under NDA so the method we use in our apps is quite simply a global function. Add the following to your .pch file and then its a simple if( is4InchRetina() ) { ... } call to make adjustments to your CGRects etc.
static BOOL is4InchRetina()
{
if (![UIApplication sharedApplication].statusBarHidden && (int)[[UIScreen mainScreen] applicationFrame].size.height == 548 || [UIApplication sharedApplication].statusBarHidden && (int)[[UIScreen mainScreen] applicationFrame].size.height == 568)
return YES;
return NO;
}
I think you can use [UIScreen mainScreen].bounds.size.height and calculate step for your objects. when you calculate step you can set coordinates for two resolutions.
Or you can get height like above and if(iphone5) then... else if(iphone4) then... else if(ipad). Something like this.
If you use storyboards then you have to create new for new iPhone i think.
As it has more pixels in height, things like GCRectMake that use coordinates won't work seamlessly between versions, as it happened when we got the Retina.
Well, they do work the same with Retina displays - it's just that 1 unit in the CoreGraphics coordinate system will correspond to 2 physical pixels, but you don't/didn't have to do anything, the logic stayed the same. (Have you actually tried to run one of your non-retina apps on a retina iPhone, ever?)
For the actual question: that's why you shouldn't use explicit CGRectMakes and co... That's why you have stuff like [[UIScreen mainScreen] applicationFrame].
So I have a universal app and I'm setting up the content size of a UIScrollView. Obviously the content size is going to be different on iPhones and iPads. How can I set a certain size for iPads and another size for iPhones and iPod touches?
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
// The device is an iPad running iOS 3.2 or later.
}
else
{
// The device is an iPhone or iPod touch.
}
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
and
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
The macros UI_USER_INTERFACE_IDIOM() also works on older iOS versions like iOS 3.0 without crashing.
UI_USER_INTERFACE_IDIOM() is the best solution in your case since your app is universal. But if you are running an iPhone app on iPad than UI_USER_INTERFACE_IDIOM() will return UIUserInterfaceIdiomPhone, regardless of the device. For such purposes as that, you can use the UIDevice.model property:
if ([[UIDevice currentDevice].model rangeOfString:#"iPad"].location != NSNotFound) {
//Device is iPad
}
In Swift 2.x you can use the following equalities to determine the kind of device:
UIDevice.currentDevice().userInterfaceIdiom == .Phone
or
UIDevice.currentDevice().userInterfaceIdiom == .Pad
In Swift 3 for new people coming here.
if UIDevice.current.userInterfaceIdiom == .pad {
\\ Available Idioms - .pad, .phone, .tv, .carPlay, .unspecified
\\ Implement your awesome logic here
}
The UIDevice class will tell you everything you need to know about the device. The model property, for instance, will tell you the model of the device. You can use this to determine which view to use for the current device.
Use the UIScreen class to determine the application's frame.
CGRect usableSpace = [[UIScreen mainScreen] applicationFrame];
The returned rectangle is the screen's size minus the status bar. Don't use the UI idioms for determining available space as they're not future-proof.
By the way, UIViewController can resize content views (including scroll views) automatically, as well as provide you with other goodies, such as auto-rotation. Consider it if it's appropriate in your situation.
if you are using swift,
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.Pad)
{
// device is ipad
}
else
{
//device is iPhone
}
You can also check the UIUSerInterfaceIdiom and choose the device you want to UIUserInterfaceIdiom.Pad or UIUserInterfaceIdiom.Phone or UIUserInterfaceIdiom.TV or UIUserInterfaceIdiom.CarPlay