How to pinch with two fingers in iOS app automation with swift - ios11

I want to apply pinch-in and pinch-out gesture into a imageView in my application.
I am using Xcode9 and swift 3.2
I could not able to tap on specific two coordinate at a time of my desired image
app.scrollViews.scrollViews.images.element(boundBy: 0)

For zoom in or zoom out you have to use pinch(withScale:velocity:) method of xctest.
Your code should look like below
let image = app.scrollViews.scrollViews.images.element(boundBy: 0)
Zoom in:
image.pinch(withScale: 3, velocity: 1) // zoom in
Zoom out:
image.pinch(withScale: 0.5, velocity: -1) // zoom out
According to api documentation of pinch(withScale:velocity:) negative velocity is for zoom out and positive velocity is for zoom in
Please use the above code and let me know your feedback.

Use pinch(withScale:velocity:) on your image element.
let image = app.scrollViews.scrollViews.images.element(boundBy: 0)
image.pinch(withScale: 3, velocity: 1) // zoom in
image.pinch(withScale: 0.5, velocity: -1) // zoom out

Related

ARSCNPlaneGeometry update and re-calculate texture coordinates, instead of stretching them

I'm having a problem on the texture coordinates of planes geometries being updated by ARKit. Texture images get stretched, I want to avoid that.
Right now I'm detecting horizontal and vertical walls and applying a texture to them. It's working like a charm...
But when the geometry gets updated because it extents the detection of the wall/floor, the texture coordinates get stretched instead of re-mapping, causing the texture to look stretched like image below.
You can also see an un-edited video of the problem happening: https://www.youtube.com/watch?v=wfwYPwzND74
This is the piece of code where the geometry gets updated:
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
guard let planeAnchor = anchor as? ARPlaneAnchor else {
return
}
let planeGeometry = ARSCNPlaneGeometry(device: device)!
planeGeometry.update(from: planeAnchor.geometry)
//I suppose I need to do some texture re-mapping here.
planeGeometry.materials = node.geometry!.materials
node.geometry = planeGeometry
}
I have seen that you can define the texture coordinates by defining it as a source like this:
let textCords = [] //Array of coordinates
let uvData = Data(bytes: textCords, count: textCords.count * MemoryLayout<vector_float2>.size)
let textureSource = SCNGeometrySource(data: uvData,
semantic: .texcoord,
vectorCount: textCords.count,
usesFloatComponents: true,
componentsPerVector: 2,
bytesPerComponent: MemoryLayout<Float>.size,
dataOffset: 0,
dataStride: MemoryLayout<vector_float2>.size)
But I have no idea how to fill the textCords array to make it fit correctly accordingly to the updated planeGeometry
Edit:
Re-defining the approach:
Thinking deeply on the problem, I came with the idea that I need to modify the texture's transform to fix the stretching part, but then I have two options if I do that:
Either keep the texture big enough to fill the entire geometry but
keeping a ratio of 1:1 to avoid stretching
Or keep the texture the
original size but with 1:1 aspect ratio and repeat the texture
multiple times to fit the entire geometry.
Any of these approaches I'm still lost of how to do it. What would you suggest?

Leaflet - get a map that covers the full screen

In leaflet and mapbox I would like to get rid of the two gray bars above and under the map as seen on the picture below. My #map DOM element takes the full screen and the gray bars disappear when I zoom in (e.g., zoomLevel = 3). So the gray bars seem to be caused by the fact that a zoomLevel has a given height (in px) of the tiles which is smaller than my screen.
I want to keep the tiles of the same zoom level but make sure the height of the tiles cover at least the full screen.
Here is my map setup code:
vm.map = L.map('map', {
center: [35, 15],
zoom: 2,
maxZoom: 21,
scrollWheelZoom: true,
maxBounds: [
[89.9, 160.9],
[-89.9, -160.9]
],
zoomControl: false,
noWrap: true,
zoomAnimation: true,
markerZoomAnimation: true,
});
I am using angular and my screen dimensions are 1920 x 1080
Sounds like you need to calculate the minimum zoom level at which the map only shows the area between 85°N and 85°S.
The getBoundsZoom() method of L.Map helps with this, e.g.:
var bounds = L.latLngBounds([[85, 180],[-85, -180]]);
var wantedZoom = map.getBoundsZoom(bounds, true);
var center = bounds.getCenter();
map.setView(center, wantedZoom);
Note that this is a generic solution, and works for any size of the map container.
You could also set the minZoom of the map to that value, and experiment with fractional zoom (see the zoomSnap option). If you want the user to be unable to drag outside the painted area, use the map's maxBounds option with something like [[85, Infinity],[-85, -Infinity]].
(And if you are wondering why 85°N and 85°S, do read https://en.wikipedia.org/wiki/Web_Mercator )

Openlayers 3 Circle radius in meters

How to get Circle radius in meters
May be this is existing question, but i am not getting proper result. I am trying to create Polygon in postgis with same radius & center getting from openlayers circle.
To get radius in meters I followed this.
Running example link.
var radiusInMeters = circleRadius * ol.proj.METERS_PER_UNIT['m'];
After getting center, radius (in meters) i am trying to generate Polygon(WKT) with postgis (server job) & drawing that feature in map like this.
select st_astext(st_buffer('POINT(79.25887485937808 17.036647682474722 0)'::geography, 365.70644956827164));
But both are not covering same area. Can any body please let me know where i am doing wrong.
Basically my input/output to/from Circle will be in meters only.
ol.geom.Circle might not represent a circle
OpenLayers Circle geometries are defined on the projected plane. This means that they are always circular on the map, but the area covered might not represent an actual circle on earth. The actual shape and size of the area covered by the circle will depend on the projection used.
This could be visualized by Tissot's indicatrix, which shows how circular areas on the globe are transformed when projected onto a plane. Using the projection EPSG:3857, this would look like:
The image is from OpenLayer 3's Tissot example and displays areas that all have a radius of 800 000 meters. If these circles were drawn as ol.geom.Circle with a radius of 800000 (using EPSG:3857), they would all be the same size on the map but the ones closer to the poles would represent a much smaller area of the globe.
This is true for most things with OpenLayers geometries. The radius, length or area of a geometry are all reported in the projected plane.
So if you have an ol.geom.Circle, getting the actual surface radius would depend on the projection and features location. For some projections (such as EPSG:4326), there would not be an accurate answer since the geometry might not even represent a circular area.
However, assuming you are using EPSG:3857 and not drawing extremely big circles or very close to the poles, the Circle will be a good representation of a circular area.
ol.proj.METERS_PER_UNIT
ol.proj.METERS_PER_UNIT is just a conversion table between meters and some other units. ol.proj.METERS_PER_UNIT['m'] will always return 1, since the unit 'm' is meters. EPSG:3857 uses meters as units, but as noted they are distorted towards the poles.
Solution (use after reading and understanding the above)
To get the actual on-the-ground radius of an ol.geom.Circle, you must find the distance between the center of the circle and a point on it's edge. This could be done using ol.Sphere:
var center = geometry.getCenter()
var radius = geometry.getRadius()
var edgeCoordinate = [center[0] + radius, center[1]];
var wgs84Sphere = new ol.Sphere(6378137);
var groundRadius = wgs84Sphere.haversineDistance(
ol.proj.transform(center, 'EPSG:3857', 'EPSG:4326'),
ol.proj.transform(edgeCoordinate, 'EPSG:3857', 'EPSG:4326')
);
More options
If you wish to add a geometry representing a circular area on the globe, you should consider using the method used in the Tissot example above. That is, defining a regular polygon with enough points to appear smooth. That would make it transferable between projections, and appears to be what you are doing server side. OpenLayers 3 enables this by ol.geom.Polygon.circular:
var circularPolygon = ol.geom.Polygon.circular(wgs84Sphere, center, radius, 64);
There is also ol.geom.Polygon.fromCircle, which takes an ol.geom.Circle and transforms it into a Polygon representing the same area.
My answer is a complement of the great answer by Alvin.
Imagine you want to draw a circle of a given radius (in meters) around a point feature. In my particular case, a 200m circle around a moving vehicle.
If this circle has a small diameter (< some kilometers), you can ignore earth roudness. Then, you can use the marker "Circle" in the style function of your point feature.
Here is my style function :
private pointStyle(feature: Feature, resolution: number): Array<Style> {
const viewProjection = map.getView().getProjection();
const coordsInViewProjection = (<Point>(feature.getGeometry())).getCoordinates();
const longLat = toLonLat(coordsInViewProjection, viewProjection);
const latitude_rad = longLat[1] * Math.PI / 180.;
const circle = new Style({
image: new CircleStyle({
stroke: new Stroke({color: '#7c8692'});,
radius: this._circleRadius_m / (resolution / viewProjection.getMetersPerUnit() * Math.cos(latitude_rad)),
}),
});
return [circle];
}
The trick is to scale the radius by the latitude cosine. This will "locally" disable the distortion effect we can observe in the Tissot Example.

IOS6 MKMapView maximum zoom level

I'm having trouble with the maximum zoom level on the MapView using IOS6. The user can zoom in too much and the tiles are blank.
A quick fix was to do this:
- (void)mapView:(MKMapView *)theMapView regionDidChangeAnimated:(BOOL)animated {
if([theMapView zoomLevel] > 18) {
[theMapView setCenterCoordinate:[theMapView centerCoordinate] zoomLevel:18 animated:TRUE];
}
}
and zoom out again automatically, but sometimes it still zooms too far in and does not zoom out again.
I think I need to get the maximum zoom level of the current region that i'm in but there doesn't seem to be a easy way of doing that. How did you guys get past this issue?
A fix would be to do something like this:
- (void)setRegionWithMaximumZoomLevel:(MKCoordinateRegion)region animated:(BOOL)animated
{
if ([self zoomLevelForRegion:region] > 17)
{
[self setCenterCoordinate:region.center zoomLevel:17 animated:TRUE];
}else
{
[self setRegion:region animated:animated];
}
}
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
zoomLevel:(NSUInteger)zoomLevel
animated:(BOOL)animated
{
// clamp large numbers to 28
zoomLevel = MIN(zoomLevel, 17);
// use the zoom level to compute the region
MKCoordinateSpan span = [self coordinateSpanWithMapView:self centerCoordinate:centerCoordinate andZoomLevel:zoomLevel];
MKCoordinateRegion region = MKCoordinateRegionMake(centerCoordinate, span);
// set the region like normal
[self setRegion:region animated:animated];
}
Maybe it's not perfect but it's good enough for what I needed.
I did run in to the same problem as you, it's iOS6.0's bug, this is tough. Your program should not have the problem of tile blank in iOS 5.0, hope apple can fix it.
The MKMapView+ZoomLevel in gitHub is a good tools in set mapView's zoom level, but you will also run in to some trouble for tiles blank problem. but, may be this can help you:
https://github.com/DeepFriedTwinkie/iOS6MapZoomIssue

iOS 6: Porting iPhone 4 application to iPhone 5 [duplicate]

The new iPhone 5 display has a new aspect ratio and a new resolution (640 x 1136 pixels).
What is required to develop new or transition already existing applications to the new screen size?
What should we keep in mind to make applications "universal" for both the older displays and the new widescreen aspect ratio?
Download and install latest version of Xcode.
Set a Launch Screen File for your app (in the general tab of your target settings). This is how you get to use the full size of any screen, including iPad split view sizes in iOS 9.
Test your app, and hopefully do nothing else, since everything should work magically if you had set auto resizing masks properly, or used Auto Layout.
If you didn't, adjust your view layouts, preferably with Auto Layout.
If there is something you have to do for the larger screens specifically, then it looks like you have to check height of [[UIScreen mainScreen] bounds] as there seems to be no specific API for that. As of iOS 8 there are also size classes that abstract screen sizes into regular or compact vertically and horizontally and are recommended way to adapt your UI.
If you have an app built for iPhone 4S or earlier, it'll run letterboxed on iPhone 5.
To adapt your app to the new taller screen, the first thing you do is to change the launch image to: Default-568h#2x.png. Its size should be 1136x640 (HxW). Yep, having the default image in the new screen size is the key to let your app take the whole of new iPhone 5's screen.
(Note that the naming convention works only for the default image. Naming another image "Image-568h#2x.png" will not cause it to be loaded in place of "Image#2x.png". If you need to load different images for different screen sizes, you'll have to do it programmatically.)
If you're very very lucky, that might be it... but in all likelihood, you'll have to take a few more steps.
Make sure, your Xibs/Views use auto-layout to resize themselves.
Use springs and struts to resize views.
If this is not good enough for your app, design your xib/storyboard
for one specific screen size and reposition programmatically for the
other.
In the extreme case (when none of the above suffices), design the two Xibs and load the appropriate one in the view controller.
To detect screen size:
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
    CGSize result = [[UIScreen mainScreen] bounds].size;
    if(result.height == 480)
{
// iPhone Classic
    }
    if(result.height == 568)
{
// iPhone 5
    }
}
The only really required thing to do is to add a launch image named "Default-568h#2x.png" to the app resources, and in general case (if you're lucky enough) the app will work correctly.
In case the app does not handle touch events, then make sure that the key window has the proper size. The workaround is to set the proper frame:
[window setFrame:[[UIScreen mainScreen] bounds]]
There are other issues not related to screen size when migrating to iOS 6. Read iOS 6.0 Release Notes for details.
Sometimes (for pre-storyboard apps), if the layout is going to be sufficiently different, it's worth specifying a different xib according to device (see this question - you'll need to modify the code to deal with iPhone 5) in the viewController init, as no amount of twiddling with autoresizing masks will work if you need different graphics.
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
NSString *myNibName;
if ([MyDeviceInfoUtility isiPhone5]) myNibName = #"MyNibIP5";
else myNibName = #"MyNib";
if ((self = [super initWithNibName:myNibName bundle:nibBundleOrNil])) {
...
This is useful for apps which are targeting older iOS versions.
Here you can find a nice tutorial (for MonoTouch, but you can use the information for Non-MonoTouch-projects, too):
http://redth.info/get-your-monotouch-apps-ready-for-iphone-5-ios-6-today/
Create a new image for your splash/default screen (640 x 1136 pixel) with the name "Default-568h#2x.png"
In the iOS Simulator, go to the Hardware -> Device menu, and select "iPhone (Retina 4-inch)"
Create other images, e.g. background images
Detect iPhone 5 to load your new images:
public static bool IsTall
{
get {
return UIDevice.currentDevice.userInterfaceIdiom
== UIUserInterfaceIdiomPhone
&& UIScreen.mainScreen.bounds.size.height
* UIScreen.mainScreen.scale >= 1136;
}
}
private static string tallMagic = "-568h#2x";
public static UIImage FromBundle16x9(string path)
{
//adopt the -568h#2x naming convention
if(IsTall())
{
var imagePath = Path.GetDirectoryName(path.ToString());
var imageFile = Path.GetFileNameWithoutExtension(path.ToString());
var imageExt = Path.GetExtension(path.ToString());
imageFile = imageFile + tallMagic + imageExt;
return UIImage.FromFile(Path.Combine(imagePath,imageFile));
}
else
{
return UIImage.FromBundle(path.ToString());
}
}
It's easy for migrating iPhone5 and iPhone4 through XIBs.........
UIViewController *viewController3;
if ([[UIScreen mainScreen] bounds].size.height == 568)
{
UIViewController *viewController3 = [[[mainscreenview alloc] initWithNibName:#"iphone5screen" bundle:nil] autorelease];
}
else
{
UIViewController *viewController3 = [[[mainscreenview alloc] initWithNibName:#"iphone4screen" bundle:nil] autorelease];
}
I solve this problem here. Just add ~568h#2x suffix to images and ~568h to xib's. No needs more runtime checks or code changes.
I had added the new default launch image and (in checking out several other SE answers...) made sure my storyboards all auto-sized themselves and subviews but the retina 4 inches still letterboxed.
Then I noticed that my info plist had a line item for "Launch image" set to "Default.png", which I thusly removed and magically letterboxing no longer appeared. Hopefully, that saves someone else the same craziness I endured.
I guess, it is not going to work in all cases, but in my particular project it avoided me from duplication of NIB-files:
Somewhere in common.h you can make these defines based off of screen height:
#define HEIGHT_IPHONE_5 568
#define IS_IPHONE ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
#define IS_IPHONE_5 ([[UIScreen mainScreen] bounds ].size.height == HEIGHT_IPHONE_5)
In your base controller:
- (void)viewDidLoad
{
[super viewDidLoad];
if (IS_IPHONE_5) {
CGRect r = self.view.frame;
r.size.height = HEIGHT_IPHONE_5 - 20;
self.view.frame = r;
}
// now the view is stretched properly and not pushed to the bottom
// it is pushed to the top instead...
// other code goes here...
}
In a constants.h file you can add these define statements:
#define IS_IPAD UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad
#define IS_IPHONE UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone
#define IS_WIDESCREEN (fabs((double)[[UIScreen mainScreen] bounds].size.height - (double)568) < DBL_EPSILON)
#define IS_IPHONE_5 (!IS_IPAD && IS_WIDESCREEN)
To determine if your app can support iPhone 5 Retina use this:
(This could be more robust to return the type of display, 4S Retina, etc., but as it is written below, it just returns if the iPhone supports iOS5 Retina as a YES or NO)
In a common ".h" file add:
BOOL IS_IPHONE5_RETINA(void);
In a common ".m" file add:
BOOL IS_IPHONE5_RETINA(void) {
BOOL isiPhone5Retina = NO;
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
if ([UIScreen mainScreen].scale == 2.0f) {
CGSize result = [[UIScreen mainScreen] bounds].size;
CGFloat scale = [UIScreen mainScreen].scale;
result = CGSizeMake(result.width * scale, result.height * scale);
if(result.height == 960){
//NSLog(#"iPhone 4, 4s Retina Resolution");
}
if(result.height == 1136){
//NSLog(#"iPhone 5 Resolution");
isiPhone5Retina = YES;
}
} else {
//NSLog(#"iPhone Standard Resolution");
}
}
return isiPhone5Retina;
}
First of all create two xibs and attach all delegates,main class to the xib and then u can put in this condition mentioned below in your appdelegate.m file in
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
if ([[UIScreen mainScreen] bounds].size.height == 568)
{
self.ViewController = [[ViewController alloc] initWithNibName:#"ViewControlleriphone5" bundle:nil];
}
else
{
self.ViewController = [[ViewController alloc] initWithNibName:#"ViewControlleriphone4" bundle:nil];
}
you can use it any where in the program depending upon your requirements even in your ViewController classes. What matters the most is that you have created two xib files separate for iphone 4(320*480) and iphone 5(320*568)
Try the below method in a singleton class:
-(NSString *)typeOfDevice
{
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
CGSize result = [[UIScreen mainScreen] bounds].size;
if(result.height == 480)
{
return #"Iphone";
}
if(result.height == 568)
{
return #"Iphone 5";
}
}
else{
return #"Ipad";;
}
return #"Iphone";
}
You can use the Auto Layout feature and create the design using iPhone 5 screen resolution and it will work for the both 4" and 3.5" devices, but in this case you should have a enough knowledge of layout manager.
Checking bounds with 568 will fail in landscape mode. iPhone 5 launches only in portrait mode but if you want to support rotations then the iPhone 5 "check" will need to handle this scenario as well.
Here's a macro which handles orientation state:
#define IS_IPHONE_5 (CGSizeEqualToSize([[UIScreen mainScreen] preferredMode].size, CGSizeMake(640, 1136)))
The use of the 'preferredMode' call is from another posting I read a few hours ago so I did not come up with this idea.
First show this image. In that image you show warning for Retina 4 support so click on this warning and click on add so your Retina 4 splash screen automatically add in your project.
and after you use this code :
if([[UIScreen mainScreen] bounds].size.height == 568)
{
// For iphone 5
}
else
{
// For iphone 4 or less
}
I never faced such an issue with any device as I've had one codebase for all, without any hardcoded values. What I do is to have the maximum sized image as resource instead of one for each device. For example, I would have one for retina display and show it as aspect fit so it will be views as is on every device.
Coming to deciding the frame of button, for instance, at run time. For this I use the % value of the patent view, example , if I want the width to be half of parent view take 50 % of parent and same applies for height and center.
With this I don't even need the xibs.
You can use this define to calculate if you are using the iPhone 5 based on screen size:
#define IS_IPHONE_5 ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )568 ) < DBL_EPSILON )
then use a simple if statement :
if (IS_IPHONE_5) {
// What ever changes
}
Peter, you should really take a look at Canappi, it does all that for you, all you have to do is specify the layout as such:
button mySubmitButton 'Sumbit' (100,100,100,30 + 0,88,0,0) { ... }
From there Canappi will generate the correct objective-c code that detects the device the app is running on and will use:
(100,100,100,30) for iPhone4
(100,**188**,100,30) for iPhone 5
Canappi works like Interface Builder and Story Board combined, except that it is in a textual form. If you already have XIB files, you can convert them so you don't have to recreate the entire UI from scratch.
You can manually check the screen size to determine which device you're on:
#define DEVICE_IS_IPHONE5 ([[UIScreen mainScreen] bounds].size.height == 568)
float height = DEVICE_IS_IPHONE5?568:480;
if (height == 568) {
// 4"
} else {
// 3"
}
You could add this code:
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){
if ([[UIScreen mainScreen] respondsToSelector: #selector(scale)]) {
CGSize result = [[UIScreen mainScreen] bounds].size;
CGFloat scale = [UIScreen mainScreen].scale;
result = CGSizeMake(result.width * scale, result.height * scale);
if(result.height == 960) {
NSLog(#"iPhone 4 Resolution");
}
if(result.height == 1136) {
NSLog(#"iPhone 5 Resolution");
}
}
else{
NSLog(#"Standard Resolution");
}
}
This is a real universal code, you can create 3 different story board:
Set your project Universal mode, and set your main story iPhone with the iPhone5 storyboard and the ipad main with iPad target storyboard, now add new storyboard target for iphone and modify the resolution for iphone 4s or less now implement your AppDelegate.m
iPhone4/4s (is the same for 3/3Gs) one for iPhone5 and make the project universal, with a new Storyboard target for iPad, now in to AppDelegate.m under the didFinishLaunching add this code:
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){
UIStoryboard *storyBoard;
CGSize result = [[UIScreen mainScreen] bounds].size;
CGFloat scale = [UIScreen mainScreen].scale;
result = CGSizeMake(result.width *scale, result.height *scale);
//----------------HERE WE SETUP FOR IPHONE4/4s/iPod----------------------
if(result.height == 960){
storyBoard = [UIStoryboard storyboardWithName:#"iPhone4_Storyboard" bundle:nil];
UIViewController *initViewController = [storyBoard instantiateInitialViewController];
[self.window setRootViewController:initViewController];
}
//----------------HERE WE SETUP FOR IPHONE3/3s/iPod----------------------
if(result.height == 480){
storyBoard = [UIStoryboard storyboardWithName:#"iPhone4_Storyboard" bundle:nil];
UIViewController *initViewController = [storyBoard instantiateInitialViewController];
[self.window setRootViewController:initViewController];
}
}
return YES;
}
So you have created a Universal app for iPhone 3/3Gs/4/4s/5 All gen of iPod, and All type of iPad
Remember to integrate all IMG with myImage.png and myImage#2x.png
According to me the best way of dealing with such problems and avoiding couple of condition required for checking the the height of device, is using the relative frame for views or any UI element which you are adding to you view for example: if you are adding some UI element which you want should at the bottom of view or just above tab bar then you should take the y origin with respect to your view's height or with respect to tab bar (if present) and we have auto resizing property as well. I hope this will work for you
Rather than using a set of conditionals you can resize your view automatically using the screen size.
int h = [[UIScreen mainScreen] bounds].size.height;
int w = [[UIScreen mainScreen] bounds].size.width;
self.imageView.frame = CGRectMake(20, 80, (h-200), (w-100));
In my case I want a view that fills the space between some input fields at the top and some buttons at the bottom, so fixed top left corner and variable bottom right based on screen size. My app fills the image view with the photo taken by the camera so I want all the space I can get.
If you need to convert an already existing app to universal, you need to select corresponding xib file->show Utilities-> Show Size inspector.
In Size inspector you can see Autosizing, by using this tool you can convert to existing iOS App.
Using xCode 5, select "Migrate to Asset Catalog" on Project>General.
Then use "Show in finder" to find your launch image, you can dummy-edit it to be 640x1136, then drag it into the asset catalog as shown in the image below.
Make sure that both iOS7 and iOS6 R4 section has an image that is 640x1136. Next time you launch the app, the black bars will disappear, and your app will use 4 inch screen
Point worth notice - in new Xcode you have to add this image file Default-568h#2x.png to assets
Use the Auto Layout feature for views. It will adjust automatically to all resolutions.
Create two xibs for a controller having controller name with suffix either ~iphone or ~ipad. At compile time, Xcode will take the right xib based on the device.
Use size classes, if you want to create a single xib for both iPhone and iPad, if the view is simple enough to port to iPhone and iPad.
There is a slight problem when testing on both iOS device and iOS Simulator. It appears that simulator (XCode 6.0.1) gives switched values for width and height in [[UIScreen mainScreen] bounds].size depending on a device orientation.
So this might be a problem when determinating the right physical screen size. This code helps also to distinct all 2014. iPhone model generations:
iPhone4s
iPhone5 (and iPhone5s)
iPhone6 (and iPhone6+)
It can also be easily changed to make the distinction between e.g. iPhone6 from iPhone6+.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
CGSize iOSDeviceScreenSize = [[UIScreen mainScreen] bounds].size;
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone)
{
if (iOSDeviceScreenSize.width > 568 || // for iOS devices
iOSDeviceScreenSize.height > 568) // for iOS simulator
{ // iPhone 6 and iPhone 6+
// Instantiate a new storyboard object using the storyboard file named Storyboard_iPhone6
storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone6" bundle:nil];
NSLog(#"loaded iPhone6 Storyboard");
}
else if (iOSDeviceScreenSize.width == 568 || // for iOS devices
iOSDeviceScreenSize.height == 568) // for iOS simulator
{ // iPhone 5 and iPod Touch 5th generation: 4 inch screen (diagonally measured)
// Instantiate a new storyboard object using the storyboard file named Storyboard_iPhone5
storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone5" bundle:nil];
NSLog(#"loaded iPhone5 Storyboard");
}
else
{ // iPhone 3GS, 4, and 4S and iPod Touch 3rd and 4th generation: 3.5 inch screen (diagonally measured)
// Instantiate a new storyboard object using the storyboard file named Storyboard_iPhone4
storyboard = [UIStoryboard story boardWithName:#"MainStoryboard_iPhone" bundle:nil];
NSLog(#"loaded iPhone4 Storyboard");
}
}
else if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
{ // The iOS device = iPad
storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPadnew" bundle:nil];
NSLog(#"loaded iPad Storyboard");
}
// rest my code
}
I would suggest to use Autoresizing Mask in your applications according to your UI interface, it saves a lot of trouble and is better than making different UI for iPhone 4 and 5 screens.

Resources