TraitCollectionDidChange behaves different for iphone X - swift

In My case i am changing my layouts of the view depending on the traitCollection.horizontalSizeClass
Here is my Code snippet .
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if traitCollection.horizontalSizeClass == .regular {
// 2
NSLayoutConstraint.deactivate(compactConstraints)
NSLayoutConstraint.activate(regularConstraints)
// 3
socialMediaView.axis = .horizontal
} else {
// 4
NSLayoutConstraint.deactivate(regularConstraints)
NSLayoutConstraint.activate(compactConstraints)
socialMediaView.axis = .vertical
}
}
Every things working as directed in iphone 7 plus and iphone x in portrait-mode
and in landscape mode i want the rabbit image comes to left side and the stackview of all socialMedias axis will be horizontal
but in iphone X landscape mode its not coming while in phone 7 its coming .Check the below screen shots

Looking at your question and condition, I found a problem in your condition. you should check for the verticalSizeClass instead of horizontalSizeClass.
WHEN CHECK FOR HORIZONTAL SIZE CLASS.
IN PORTRAIT: All iPhone Devices has compact width, so every time, it will go to else condition and set the view properly.
IN LANDSCAPE: All iPhone Plus (iPhone 6s Plus, iPhone 7 Plus and iPhone 8 plus) Devices has Regular width and All other iPhone (iPhone 6s, 6SE, iPhone 7 and iPhone 8, iPhone X) Devices has Compact width, so for all plus devices it will works fine but not for others.
FOR PORTRAIT:
FOR LANDSCAPE:
For more, read official doc here
So, update your code to this.
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if traitCollection.verticalSizeClass == .regular {
NSLayoutConstraint.deactivate(compactConstraints)
NSLayoutConstraint.activate(regularConstraints)
socialMediaView.axis = .horizontal
} else {
NSLayoutConstraint.deactivate(regularConstraints)
NSLayoutConstraint.activate(compactConstraints)
socialMediaView.axis = .vertical
}
}
Try and share the results.

Related

UITest tap not working on iOS 12.4 using iPhone X (works on iPhone 7)

Could this be related to SafeArea issues in iOS12.4 (and actually 12.2 as well)?
I use the following function to tap a view during my UITests.
func tapAtLocation(_ element: XCUIElement) -> Self {
let loc = element.coordinate(withNormalizedOffset: .init(dx: 0, dy: 0))
loc.tap()
return self
}
I try to tap at the location of a specific image.
So I get the image and trigger a tap
let myImage = App.images[myImageViewIdentifier].firstMatch
tapAtLocation(myImage)
It works on new iOS versions and also on iPhone 7 iOS 12.4 but not on iPhone X.
And I need it to work on iPhone X :)
What do you propose me to do? Maybe you have a nice debugging trick to see exactly where it tries to tap ?
ok ! After a day of fail and retry, a simple solution worked out!
func tapAtLocation(_ element: XCUIElement) -> Self {
let loc = element.coordinate(withNormalizedOffset: .init(dx: 0.5, dy: 0.5))
loc.tap()
return self
}
This works on all devices (iPhone X, 7 and 11) with iOS 12.4 and 13+

Experiencing limit in number of UILabels added as subviews

Unable to add more than three UILabels to a UIViewController’s view in the IPad Playgrounds app. Is it me or the system?
Simplified code to show the issue. Hardware is a 2018 iPad Pro running iOS 12.3.1 Playgrounds app 3.0. Using UIViews up to five can be added successfully.
import UIKit
import PlaygroundSupport
class MyViewController : UIViewController {
let square50 = CGSize(width: 50, height: 50)
override func viewDidLoad() {
var myFrame = CGRect(origin: .zero, size: square50)
for index in 0...4 {
view.addSubview(UIView(frame: myFrame)) // fails at 6th!
(view.subviews[index] as! UIView).backgroundColor = .red
myFrame.origin.y += 80
}
}
}
PlaygroundPage.current.liveView = MyViewController()
With the index range set as shown the code worked as expected, displaying the set number of coloured rectangles. With the range increased to 0...5 the runtime stopped with the message “There was a problem encountered while running this playground. Check your code for mistakes”.
Just been able to test the code on Xcode 10.3 under OS X 10.16.6 on my iMac Retina 5k 27" late 2015. There is NO problem with the code and there is no short-range limit on the number of sub-views that can be created.
The problem rests with iOS Swift Playgrounds 3.0 running on an iPad Pro 12.9 inch 3rd-gen using iOS 12.3.1. This is therefore a bug!

Size classes on Modal Views

I am trying to set different constraints for iPad and iPhone (4'').
I have set Regular Height and Compact width constraints for iPhone. But these constraints are shown on 7.9'' iPad, 9.7'' iPad.
These constraints are for a modal view.
How do i make my Regular Height and Compact width constraints limit to my iPhones only.
Because the form sheet presentation on iPad is compact width and regular height, It is taking those constraints.
Formsheet ios 8 constraints are same as iphones constraints
The solution is to override traitCollection in the Presented view controller
override var traitCollection: UITraitCollection
{
if UIDevice.isIPad()
{
let traits = UITraitCollection(horizontalSizeClass: UIUserInterfaceSizeClass.Regular)
let traits2 = UITraitCollection(verticalSizeClass: UIUserInterfaceSizeClass.Regular)
let traitCollection = UITraitCollection(traitsFromCollections: [traits, traits2])
return traitCollection
}
else
{
return super.traitCollection
}
}
As a note, iOS Docs have this warning for traitCollection:
Use the traitCollection property directly. Do not override it. Do not provide a custom implementation.
With that known, here's an Obj-C solution which combines super traits w/ updated horizontal/vertical traits:
- (UITraitCollection *)traitCollection {
UITraitCollection *traitCollection = [super traitCollection];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
UITraitCollection *horizontalTraitCollection = [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassRegular];
UITraitCollection *verticalTraitCollection = [UITraitCollection traitCollectionWithVerticalSizeClass:UIUserInterfaceSizeClassRegular];
traitCollection = [UITraitCollection traitCollectionWithTraitsFromCollections:#[traitCollection, horizontalTraitCollection, verticalTraitCollection]];
}
return traitCollection;
}

Background of spriteKit exceeds the frame of the phone IOS

I am having deep trouble understanding how the resolution on different devices work. so what I have done is made a background image 1024 x 768 then tested on an iphone 5 device. when i run it, the bottom half of the screen is chopped off so as the top. I did use AspectFill as my scale mode, but even when i test it on iphone 6 or 6+, the background is still chopped off.
the following is my code for gameviewcontroller
import UIKit
import SpriteKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let scene = GameScene(size: CGSize(width: 1024, height: 768))
let skView = self.view as! SKView
skView.multipleTouchEnabled = true
if GameSettings.Debugging.ALL_TellMeStatus {
skView.showsFPS = GameSettings.Debugging.ALL_ShowFrameRate
skView.showsNodeCount = GameSettings.Debugging.ALL_ShowNodeCount
skView.showsDrawCount = GameSettings.Debugging.IOS_ShowDrawCount
skView.showsQuadCount = GameSettings.Debugging.IOS_ShowQuadCount
skView.showsPhysics = GameSettings.Debugging.IOS_ShowPhysics
skView.showsFields = GameSettings.Debugging.IOS_ShowFields
}
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
_ = SGResolution(screenSize: view.bounds.size, canvasSize: scene.size)
skView.presentScene(scene)
}
override func shouldAutorotate() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return .Landscape
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
and my code for adding the background image in.
let background = SKSpriteNode(imageNamed: "Artboard 1")
background.posByCanvas(0.5, y: 0.5)
background.xScale = 1.2
background.yScale = 1.2
background.size = self.frame.size
background.zPosition = -1
addChild(background)
is this the right way to start the screen size or should i start with an iPad screen size then descale it? If anyone can lead me on how to attack this problem that would be great!!
Aspect fill is going to chop off parts of your background.
Your scene has an aspect ratio of 4:3
Your device has an aspect ratio of 16:9
AspectFill will scale your scene in its current aspect ratio(4:3) till the farthest borders are filled, allowing for the entire view to show the scene and have no black borders;
AspectFit will scale till the nearest borders are filled in, which will give you black bars to preserve the aspect ratio.
If you want the 4:3 to not be preserved, then you use .Fill, this of course is going to make your sprites fatter on 16:9 because it will just stretch the scene till it hits all 4 borders
Finally you have .ResizeFill, and what this does is resizes the scene bounds to match your screen size, so if you start with a 1024x768 scene, it will turn it into a 736x414 scene when you view it on iPhone 6+ (This is because we are working in points, not pixels, the pixel count would be x3 (so 2208x1242) which hardware will shrink to 1920x1080).
You need to take a step back and evaluate how you want your game to look on 3 different aspect ratios
16:9,3:2, and 4:3, and determine which of the 4 methods above works best for you.
Now in my opinion, I find that Aspect Fill works best, and I just plan for the 16:9 aspect ratio, making sure I do not put any important information in the areas that may be cropped for a game, but this does not work for everybody, and unfortunately nobody can help you with this part, since it is your game and you are the one that determines its look and feel.

How to let iPhone 6 use Retina 4 2x image size in Xcode 6

I'm using swift for my game, and i need to know how to let iPhone 6 use Retina 4 2x in Xcode.
My images are green-square#2x green-square-568h#2x green-square#3x
My objectif : is to force iPhone 6 use Retina 4 2x image for sprite
i use this code to apply image for my sprite
let GSquare = SKSpriteNode(imageNamed: "green-square")
and How i can load specific image from assets like
let GSquare = SKSpriteNode(imageNamed: "green-square-568h#2x")
Thanks
You are not forced to use the assets catalog that has device-type sized images 1x, 2x, 3x....
You can include PNG or JPG images of any resolution in your app resources directly, and then load the image by its full file name, to ensure that you use a specific image resolution sized exactly as you want that way. When you load a specific file, you have to specify the extension in the filename for the UIImage().
Instead of:
var image = UIImage(named: "myGraphic") //load from assets
Use this form:
var image = UIImage(named: "myGraphic.png") //load from file
Keep in mind that for UIImageView, the image is scaled to the size of your UIImageView subview. That means your image will be stretched or shrink if the rectangle you create by the view's frame or Auto Layout constraints is not the exact size of the image you loaded.
You can detect which device you're on like this in your view controller:
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
adjustViewLayout(size)
}
func adjustViewLayout(size: CGSize) {
switch(size.width, size.height) {
case (320, 480): // iPhone 4S in portrait
// do something here
case (480, 320): // iPhone 4S in landscape
// do something here
case (320, 568): // iPhone 5/5S in portrait
// do something here
case (568, 320): // iPhone 5/5S in landscape
// do something here
case (375, 667): // iPhone 6 in portrait
// do something here
case (667, 375): // iPhone 6 in landscape
// do something here
case (414, 736): // iPhone 6 Plus in portrait
// do something here
case (736, 414): // iphone 6 Plus in landscape
// do something here
default:
break
}
view.setNeedsLayout()
}
Also Put this in your viewDidLoad() method so that it is detected the first time the view loads as the other method only detects orientation changes:
adjustViewLayout(UIScreen.mainScreen().bounds.size)