I am just testing some animation of "falling" views. I want to simulate leafs that fall from the sky. I have made this really simple code which is unfinished, but was used to check if I was doing it right.
However, should the "falling" views have auto layout constraints attached to them? Is it bad to just add views to the screen like this when the rest of the view is done with auto layout? I am using Swift 2 and iOS 9.
let rectangleView = UIView(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
rectangleView.backgroundColor = UIColor.redColor()
backgroundView.addSubview(rectangleView)
UIView.animateWithDuration(10, delay: 0, options: [UIViewAnimationOptions.CurveEaseIn], animations: {
rectangleView.center = CGPoint(x: rectangleView.center.x, y: 300)
}, completion: nil)
If your views are moving freely on the screen, then I don't see any reason to use auto layout constraints.
There is no issue adding a subview to a UI that uses auto layout and animating it yourself, as you are doing. Not everything on the screen has to be managed by auto layout.
Related
I am wondering if I can use UI elements like UIButton, UILabel in an augmented reality app with ARKit.
If you are also interested in transparency modes for that UIView subclasses try my sample https://github.com/erikhric/ar-menu
You can use different blending modes. I guess .alpha will work for your purposes.
Yes, you can use UIKit elements by adding them to a UIView that's positioned above the view displaying the AR scene (ARSKView or ARSCNView).
If you create a new project in Xcode and select the "Augmented Reality App" template, you can see that the AR content is just a view like any other UIKit view.
What worked best for me
in main.storyboard:
- delete SceneView
- add regular UIView
- add ARKit SceneKit View on top of that
- then you can add buttons, etc.
Yes you can place UI elements on top of the ARSKView or ARSCNView displaying the AR scene:
let scanningPanel = UIImageView()
scanningPanel.backgroundColor = UIColor(white: 0.33, alpha: 0.6)
scanningPanel.layer.masksToBounds = true
scanningPanel.frame = CGRect(x: -2,
y: self.sceneView.frame.height-270,
width: 178,
height: 50)
scanningPanel.layer.cornerRadius = 10
let scanInfo = UILabel(frame: CGRect(x: 8,
y: self.sceneView.frame.height-268,
width: 160,
height: 45))
scanInfo.textAlignment = .left
scanInfo.font = scanInfo.font.withSize(15)
scanInfo.textColor = UIColor.white
scanInfo.text = "SCAN A SURFACE"
Adding:
self.sceneView.addSubview(scanningPanel)
self.sceneView.addSubview(scanInfo)
Removing:
if(scanInfo.isDescendant(of: self.sceneView)) {
scanInfo.removeFromSuperview()
}
You can insert content of any view on a plane in ARKit like this:
let plane = SCNPlane(width: sceneView.bounds.width/3000,
height: sceneView.bounds.height/3000)
plane.firstMaterial?.diffuse.contents = self.anyView`
Gestures and taps are automatically sent to that view.
Try my example.
I having two sub views inside scrollview. I need to position that both subviews programmatically. I did it correctly by writing code inside DispatchQueue.main.async. Here is the code:
DispatchQueue.main.async {
self.SelectClientDetailView.frame = CGRect(x: 0, y: 637, width: self.SelectClientDetailView.frame.size.width, height: self.SelectClientDetailView.frame.size.height)
self.SelectClientDetailView2.frame = CGRect(x: 0, y: 837, width: self.SelectClientDetailView2.frame.size.width, height: self.SelectClientDetailView2.frame.size.height)
}
Its working good but when I scrolling my scrollview this both views set back to old positions. How to fix it. Its Default y position will be SelectClientDetailView:400 and SelectClientDetailView2: 600
If you are using Auto Layout then setting frame will cause some weird effects. Auto Layout and Frames doesn't go together. You'll need to rearrange the constrains, not the frames. While using Auto Layout changing the frames will cause some weird effects and will eventually revert back to the constraints you've created in the original UIView.
Some solutions:
If you want to use Autolayout approach then, You need to create an outlet to each constrain just like you would to a view and change its constant when needed.
disable Auto Layout in that specific xib and start playing with frames.
If you only want to change the frame Y position, try this instead:
self.SelectClientDetailView.frame.origin.y = 637
self.SelectClientDetailView.frame.origin.y = 837
As already mentioned, you might need to check your view hierarchy to be sure you are actually adding them to the UIScrollView (and not elsewhere).
I'm having trouble figuring out how to lay out views in Swift Playgrounds for iPad, though this may also be relevant to Mac users.
The following code should create a view with a red square (also a view) that is near the edges of its' super view, but not touching them.
let v = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
let sqv = UIView(frame: CGRect(x: 400, y: 400, width: 50, height: 50))
sqv.backgroundColor = .red
v.addSubview(sqv)
PlaygroundPage.current.liveView = v
The result is not what you'd expect:
I suspect I know what is going on here; live views are at a fixed size that is larger than the display area. Some characteristics of the view are ignored when it is acting as the live view. However, I can't find where this is mentioned in the documentation, which vexes me. More importantly, how do I deal with this? I would like to be able to layout simple UIs that change to fit the current size of the live view. I don't know how to address this issue without trial & error and hardcoding, which are two things I would really like to avoid.
I suspect I know what is going on here; live views are at a fixed size that is larger than the display area.
Actually it's more like the other way around. An iPad screen is 1024 points wide (in landscape orientation). The right-hand pane (where it shows your live view) is 512 points wide. The playground forces your root view (v) to fill that pane, inset by 40 points on the left, right, and top (and more on the bottom). So your root view's width is forced to 432 ( = 512 - 2 * 40), less than the 500 you specified.
Views created in code (like yours) have translatesAutoresizingMaskIntoConstraints = true, and a resizing mask of 0, which means don't adjust the view's frame at all when its parent is resized. So the playground resizes your root view to width 432, but your root view doesn't move or resize its subview (sqv).
The easiest fix is to set the autoresizing mask of the subview to express your intent that it remain near the right and bottom edges of the root view. That means it should have flexible top and left margins:
let v = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
let sqv = UIView(frame: CGRect(x: 400, y: 400, width: 50, height: 50))
sqv.autoresizingMask = [.flexibleLeftMargin, .flexibleTopMargin]
sqv.backgroundColor = .red
v.addSubview(sqv)
PlaygroundPage.current.liveView = v
Result:
let sqv = UIView(frame: CGRect(x: UIScreen.mainScreen().bounds.width-50-1, y:400, width: 50, height: 50))
The above code places your subview 1 point away from the right of the main view. Try changing the value 1 after 50 in x to desired value.
This may be too basic or require rephrasing. I am in the process of learning Swift and iOS programming and have developed a basic application that runs successfully on my iPhone 5. The app consists of a label, a button, and a UIImageView. It looks the way I want it to on my iPhone 5.
I figured most of this out by just playing around and so I am creating all these elements programatically. The code looks like this:
let banner = UILabel(frame: CGRect(x: 10, y: 10, width: 300.0, height: 75.0))
let button = UIButton(frame: CGRect(x: 45, y: 75, width: 235.0, height: 60.0))
let imageView = UIImageView(frame: CGRect(x: 22, y: 150, width: 280.0, height: 410.0))
And then I configure them in viewDidLoad to make them show stuff.
Now the question...how to I make them all the right size when running on different devices? I can load up the app on my iPad Mini but it's all scrunched over to the left of the view. So I need to do some kind of dynamic layout but not sure where to start.
All help appreciated!
Rather than creating the view sizes explicitly with initWithFrame: constructors, you can programmatically create and NSLayoutConstraints to your views to automatically layout your views, the same as if you used Auto Layout with the Interface Builder. See Apple's Auto Layout Guide for more details.
I have an image called sampleImage, and I am trying to stretch it along x and y axis, as follows when it is in landscape and it did not work at all
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
{
if (UIDevice.current.orientation == UIDeviceOrientation.portrait)
{
sampleImage.frame = CGRect(x: 0, y: 0, width: 220, height: 120)
}
else
{
sampleImage.frame = CGRect(x: 0.2, y: 0.2, width: 220, height: 120)
}
}
Then, I did in viewDidLayoutSubviews() as follows,
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if (UIDevice.current.orientation == UIDeviceOrientation.portrait)
{
sampleImage.frame = CGRect(x: 0, y: 0, width: 220, height: 120)
}
else
{
sampleImage.frame = CGRect(x: 0.2, y: 0.2, width: 220, height: 120)
}
}
This works if the device is in landscape, but once you rotate it to portrait and back, all the changes are gone.How to make sure that those dimensions stay same on rotation?
Basically, it's all about constraints. First approach to solve your problem is to handle device rotation (good so answer) and change it manually via setNeedsUpdateConstratints method (another good so answer). This way good for heavy screen with complex changes with UI and constraints. In your case you better use specific constant for constraint base on device orientation that can be set in storyboard.
So, follow this steps:
Set Equal Heights and Equal Widths constraints to the UIImageView, then double click for Width Equals: 120 constraint:
Open View as: iPhone ... bottom bar:
Select specific device and landscape orientation at right side and hit the + before Constant at the right panel.
It will automatically set right Width and Height base on selected device and orientation, so you just need to enter the constant for this case. Run the project and see the result.
Portrait:
Landscape:
Note, also don't forget that different devices may have different size classes (compact x compact, compact x regular, etc.), so maybe you will need to add few more constants to handle this problem (see the table at the bottom of the article).
Finally, you solved the problem by working with storyboard, not programmatically. Pros of that - you code not grow up and not responsible for the UI things, cons - you should add the constant to every size class you want to use.