How to make a view scroll against a scrollview animation? - ios

So I have a UIView and I want to have it animate a translation in the opposite direction of the scrollviews scroll animation. How would I go about doing this? Of course this should be depend on the scrollview.contentOffset I think anyway. So if you scroll the other way it goes back to it's place. So the translation is dependent on how far the user scrolls. I am trying to use the following code. Also note that the UIView I currently do not have as a child of the scrollview. It is suppose to stay on screen at all time, but change positions.
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.x >= scrollView.contentSize.width {
UIView.animate(withDuration: 2.0, animations: {
self.view.layoutIfNeeded()
})
}

A simple solution would be:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let percentage = scrollView.contentOffset.x / scrollView.contentSize.width
self.box.frame.origin.x = UIScreen.main.bounds.width * percentage
}
Just calculate the percentage of the contentSize that you have scrolled and set the X position to the same percentage of the screen width.
It could do with some improvements to make sure the view doesn't go beyond the bounds of the screen in certain conditions. So you may need to factor in the width of the box in the calculations as an enhancement.
Here is the code I used for testing, The background image is a 4K wallpaper image.
class ViewController: UIViewController {
var box = UIView()
var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
self.scrollView = UIScrollView()
self.scrollView.translatesAutoresizingMaskIntoConstraints = false
self.scrollView.delegate = self
self.view.addSubview(self.scrollView)
NSLayoutConstraint(item: scrollView, attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .top, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: scrollView, attribute: .left, relatedBy: .equal, toItem: self.view, attribute: .left, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: scrollView, attribute: .right, relatedBy: .equal, toItem: self.view, attribute: .right, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: scrollView, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1.0, constant: 0).isActive = true
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.image = UIImage(named: "background")
self.scrollView.addSubview(imageView)
NSLayoutConstraint(item: imageView, attribute: .top, relatedBy: .equal, toItem: scrollView, attribute: .top, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: imageView, attribute: .left, relatedBy: .equal, toItem: scrollView, attribute: .left, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: imageView, attribute: .right, relatedBy: .equal, toItem: scrollView, attribute: .right, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: imageView, attribute: .bottom, relatedBy: .equal, toItem: scrollView, attribute: .bottom, multiplier: 1.0, constant: 0).isActive = true
box.frame = CGRect(x: 0, y: UIScreen.main.bounds.height - 110, width: 100, height: 100)
box.backgroundColor = .black
self.view.addSubview(box)
}
}
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let percentage = scrollView.contentOffset.x / scrollView.contentSize.width
let xPosition = UIScreen.main.bounds.width * percentage
self.box.frame.origin.x = xPosition
}
}

Related

How to add subView to anotherSubView with center alignment in iOS swift.

I'm using lottie library for animation. I loaded lottieFile as subView to anotherSubView but it's not aligned in center. I tried using center attributes as below:
#IBOutlet weak var viewOn: UIView!
let animationView = LOTAnimationView(name: "restless_gift_ii") {
animationView.loopAnimation = true
animationView.contentMode = .scaleToFill
animationView.animationSpeed = 1
animationView.backgroundColor = UIColor.black
animationView.frame.size = viewOn.frame.size
animationView.center.x = viewOn.center.x
animationView.center.y = viewOn.center.y
viewOn.addSubview(animationView) }
You can use auto layout programmatically to center align your animation view into it’s super view.
Here, I have added two ways to add animationView center align and also added comments for understanding.
if let animationView = LOTAnimationView(name: "4_bar_loop") {
animationView.loopAnimation = true
animationView.contentMode = .scaleToFill
animationView.animationSpeed = 1
animationView.backgroundColor = UIColor.black
self.viewOn.addSubview(animationView)
animationView.translatesAutoresizingMaskIntoConstraints = false
// Apply these constrains if you want animation size should be same as super view.
self.viewOn.addConstraint(NSLayoutConstraint(item: animationView, attribute: .leading, relatedBy: .equal, toItem: self.viewOn, attribute: .leading, multiplier: 1.0, constant: 1))
self.viewOn.addConstraint(NSLayoutConstraint(item: animationView, attribute: .trailing, relatedBy: .equal, toItem: self.viewOn, attribute: .trailing, multiplier: 1.0, constant: 1))
self.viewOn.addConstraint(NSLayoutConstraint(item: animationView, attribute: .top, relatedBy: .equal, toItem: self.viewOn, attribute:.top, multiplier: 1.0, constant: 1))
self.viewOn.addConstraint(NSLayoutConstraint(item: animationView, attribute: .bottom, relatedBy: .equal, toItem: self.viewOn, attribute: .bottom, multiplier: 1.0, constant: 1))
// Apply these constraint if you want animationView with fixed height and width and center of super view.
// self.viewOn.addConstraint(NSLayoutConstraint(item: animationView, attribute: .centerX, relatedBy: .equal, toItem: self.viewOn, attribute: .centerX, multiplier: 1.0, constant: 1))
// self.viewOn.addConstraint(NSLayoutConstraint(item: animationView, attribute: .centerY, relatedBy: .equal, toItem: self.viewOn, attribute: .centerY, multiplier: 1.0, constant: 1))
// animationView.addConstraint(NSLayoutConstraint(item: animationView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 100))
// animationView.addConstraint(NSLayoutConstraint(item: animationView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 100))
}
you can do it like code below programmatically i hope this help you
import UIKit
class ViewController: UIViewController {
let firstView:UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.blue
return view
}()
let secondView:UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.orange
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
setupViews()
}
func setupViews(){
view.addSubview(firstView)
firstView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor, constant: 0).isActive = true
firstView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0).isActive = true
firstView.widthAnchor.constraint(equalToConstant: 100).isActive = true
firstView.heightAnchor.constraint(equalToConstant: 100).isActive = true
// second view
firstView.addSubview(secondView)
secondView.centerYAnchor.constraint(equalTo: firstView.centerYAnchor, constant: 0).isActive = true
secondView.centerXAnchor.constraint(equalTo: firstView.centerXAnchor, constant: 0).isActive = true
secondView.widthAnchor.constraint(equalToConstant: 50).isActive = true
secondView.heightAnchor.constraint(equalToConstant: 50).isActive = true
}
}
#IBOutlet weak var viewOn: UIView!
let animationView = LOTAnimationView(name: "restless_gift_ii")
{
animationView.loopAnimation = true
animationView.contentMode = .scaleToFill
animationView.animationSpeed = 1
animationView.backgroundColor = UIColor.black
animationView.frame = viewOn.frame
viewOn.addSubview(animationView)
}
You can try it, hope it's OK
I was having several problems with the alignment and scaling of my Lottie animations. They would show up centered on emulator but not on devices. After debugging for hours, I found out the layout issues were happening because I was setting up the animations on the viewDidLoad(). When I moved the code to viewDidAppear(_ animated: Bool) everything worked like a charm. I hope this may help someone else.

Constraints programmatically for custom UIView in Dynamic ViewController

I'm creating new UIViewController dynamycally using this code
#IBAction func newVCBtnPressed(_ sender: Any) {
let controller = DynamicVC()
show(controller, sender: sender)
}
In the new UIViewController I'm using this code for creation of the new UIView:
override func loadView() {
view = UIView()
view.backgroundColor = .lightGray
}
In result I have view with .lightGray backgroundcolor.
I want to add custom UIView and setup the constraints programmatically, and in result i want UIView with following constraints:
top: 0
bottom:(view.frame.height*0.9)
leading:0
trailing:(view.frame.width*0.15)
width:(view.frame.width*0.85)
height:(view.frame.height*0.1)
Example:
Here is my code:
topMenuView = UIView()
topMenuView.backgroundColor = .red
view.addSubview(topMenuView)
topMenuView.translatesAutoresizingMaskIntoConstraints = false
setupConstraints(item: topMenuView, topC: 0, topToItem: view, bottomC: (view.frame.height*0.9), bottomToItem: view, widthC: (view.frame.width*0.85), heightC: (view.frame.height*0.1), leadingCon: 0, trailingCon: (view.frame.width*0.15))
I'm using this constructed function for constraints:
func setupConstraints(item:UIView, topC:CGFloat, topToItem:UIView, bottomC:CGFloat, bottomToItem:UIView, widthC:CGFloat, heightC:CGFloat, leadingCon:CGFloat, trailingCon:CGFloat) {
let topConstraint = NSLayoutConstraint(item: item, attribute: .top, relatedBy: .equal, toItem: topToItem, attribute: .bottom, multiplier: 1, constant: topC)
let bottomConstraint = NSLayoutConstraint(item: item, attribute: .bottom, relatedBy: .equal, toItem: bottomToItem, attribute: .top, multiplier: 1, constant: bottomC)
let widthConstraint = NSLayoutConstraint(item: item, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: widthC)
let heightConstraint = NSLayoutConstraint(item: item, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: heightC)
let leading = NSLayoutConstraint(item: item,attribute: .leading,relatedBy: .equal, toItem: view, attribute: .leadingMargin, multiplier: 1.0, constant: leadingCon)
let trailing = NSLayoutConstraint(item: item,attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailingMargin,multiplier: 1.0,constant: trailingCon)
view?.addConstraints([topConstraint, bottomConstraint, widthConstraint, heightConstraint, leading, trailing])
NSLayoutConstraint.activate([topConstraint, bottomConstraint, widthConstraint, heightConstraint, leading, trailing])
}
But in the result i receive only UIView with gray background, the new UIView with red background doesn't appears.
What I'm doing wrong???
You should only specify bottom OR height and width OR trailing, otherwise you are going to get conflicts here.
see playground:
import PlaygroundSupport
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let red = UIView()
red.backgroundColor = .red
view.addSubview(red)
red.translatesAutoresizingMaskIntoConstraints = false
red.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
red.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
red.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.85).isActive = true
red.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.1).isActive = true
}
}
PlaygroundPage.current.liveView = ViewController()

Adding leading constraint programmatically crashes app

I'm trying to get my head around how adding constraints programmatically works. So far I have my code like so:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//addViewStandard()
addConstraintsView()
}
func addConstraintsView() {
let someView = UIView(frame: CGRect.zero)
someView.backgroundColor = UIColor.blue
// I want to mimic a frame set of CGRect(x: 20, y: 50, width: 50, height: 50)
let widthConstraint = NSLayoutConstraint(item: someView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 50)
let heightConstraint = NSLayoutConstraint(item: someView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 50)
let leadingConstraint = NSLayoutConstraint(item: someView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 20)
someView.translatesAutoresizingMaskIntoConstraints = false
someView.addConstraints([widthConstraint, heightConstraint, leadingConstraint])
view.addSubview(someView)
}
}
Now when I run the app it crashes because of the leading constraint. The error message is "Impossible to set up layout with view hierarchy unprepared for constraint". What am I doing wrong here? Should I be adding the constraints to the object (the blue box on this case) or adding them to its superview?
EDIT:
After code changes I have:
func addConstraintsView() {
let someView = UIView(frame: CGRect.zero)
someView.backgroundColor = UIColor.blue
view.addSubview(someView)
someView.translatesAutoresizingMaskIntoConstraints = false
let widthConstraint = NSLayoutConstraint(item: someView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 50)
let heightConstraint = NSLayoutConstraint(item: someView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 50)
let leadingConstraint = NSLayoutConstraint(item: someView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1.0, constant: 20)
someView.addConstraints([widthConstraint, heightConstraint])
view.addConstraints([leadingConstraint])
}
First of all,
view.addSubview(someView)
someView.translatesAutoresizingMaskIntoConstraints = false
should come before the constraints phase; you have to apply the constraints AFTER someView is added to its superview.
Also, if you are targeting iOS 9, I'd advise you to use layout anchors like
let widthConstraint = someView.widthAnchor.constraint(equalToConstant: 50.0)
let heightConstraint = someView.heightAnchor.constraint(equalToConstant: 50.0)
let leadingConstraint = someView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20.0)
NSLayoutConstraint.activate([widthConstraint, heightConstraint, leadingConstraint])
This way you don't have to worry about which view to apply the constraints to.
Finally (and to clear up your doubt), if you can't use layout anchors, you should add the leading constraint to the superview, not the view.

How to create Auto layout equal width constraint programmatically in ios swift?

How to give programmatically constraints equal width and equal height with multiple views.I check google but not perfect answer for programmatically equal width and height constraints through auto layout.
my code look like below:
var countNoOfViews:Int = 3
#IBOutlet var viewForRow1: UIView!
override func viewDidLoad() {
super.viewDidLoad()
self.specialButtonViewLeft()
}
func specialButtonViewLeft(){
for i in 0..<countNoOfViews{
var customView:UIView!
customView = UIView(frame: CGRect.zero)
customView.translatesAutoresizingMaskIntoConstraints = false
viewForRow1.addSubview(customView)
let widthConstraint = NSLayoutConstraint(item: customView, attribute: .width, relatedBy: .equal,toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 20.0)
let topConstraint = NSLayoutConstraint(item: customView, attribute: .top, relatedBy: .equal,toItem: self.viewForRow1, attribute: .top, multiplier: 1.0, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: customView, attribute: .bottom, relatedBy: .equal,toItem: self.viewForRow1, attribute: .bottom, multiplier: 1.0, constant: 0)
let leadingConstraint = NSLayoutConstraint(item: customView, attribute: .leading, relatedBy: .equal, toItem: self.viewForRow1, attribute: .leading, multiplier: 1, constant: customLeadingSpaceLeft)
customLeadingSpaceLeft = customLeadingSpaceLeft + customViewWidth
arrayLeftBtnConstraints.append(widthConstraint)
if i == 0{
customView.backgroundColor = UIColor.red
}else if i == 1{
customView.backgroundColor = UIColor.green
}else if i == 2{
leftViewVal = customLeadingSpaceLeft
customView.backgroundColor = UIColor.black
}
customView.alpha = 0.50
viewForRow1.addConstraints([widthConstraint, leadingConstraint,topConstraint,bottomConstraint])
}
}
I want to add equal width constraint programmatically.
You have three possible ways to do that:
1) By using anchors:
view.widthAnchor.constraint(equalTo: otherView.widthAnchor, multiplier: 1.0).isActive = true
2) Visual format:
simple example - "H:|[otherView]-[view(==otherView)]|"
3) "Old school" constraints:
NSLayoutConstraint(item: #view, attribute: .width, relatedBy: .equal, toItem: #otherView, attribute: .width, multiplier: 1.0, constant: 0.0).isActive = true
hope it will help somebody.
Try this:
let widthConstraint = NSLayoutConstraint(item: customView, attribute: .width, relatedBy: .equal, toItem: viewForRow1, attribute: .width, multiplier: 0.25, constant: 0.0)
multiplier: 0.25, denotes that customView's width will be 1/4th of the parent view, viewForRow1.

Swift - Keep UIImageView in the same position on rotate

I have UIWebView and in its scrollView, I added a UIImageView like so:
self.webview.scrollView.addSubview(image)
my problem is when I rotate my device from portrait to landscape the UIImageView does not stay at the position I originally set it to on the scrollView, I understand the width and height of the screen change, I guess what I am trying to do it change the the position on my UIImageView so it appears it did not change.
I have this method in place:
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
var newScrollViewFrame = webview.scrollView.frame
var newFrame = webview.frame
newFrame.size.width = size.width
newFrame.size.height = size.height
newScrollViewFrame.size.width = size.width
newScrollViewFrame.size.height = size.height
webview.frame = newFrame
webview.scrollView.frame = newScrollViewFrame
}
The current code inside this method just resize the UIWebView and its scroll view, but not the UIImageViews in the scrollView
Any help would be appreciated.
Thanks,
I have tried the following:
for views in webview.scrollView.subviews
{
if(views.isKindOfClass(UIImageView))
{
views.transform = CGAffineTransformMakeRotation(CGFloat(M_PI)/2);
}
}
but this puts on UIImageView sideways on rotate
Here is how I am adding the webview to the view:
webview = UIWebView()
webview.frame = self.view.bounds
webview.scrollView.frame = webview.frame
webview.userInteractionEnabled = true
webview.scalesPageToFit = true
webview.becomeFirstResponder()
webview.delegate = self
webview.scrollView.delegate = self
self.view.addSubview(webview)
I have half solved my problem, but doing the following:
webview.translatesAutoresizingMaskIntoConstraints = false
let horizontalConstraint = NSLayoutConstraint(item: webview, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0)
view.addConstraint(horizontalConstraint)
let verticalConstraint = NSLayoutConstraint(item: webview, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0)
view.addConstraint(verticalConstraint)
let widthConstraint = NSLayoutConstraint(item: webview, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 0.1, constant: 500)
view.addConstraint(widthConstraint)
let heightConstraint = NSLayoutConstraint(item: webview, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 500)
view.addConstraint(heightConstraint)
However now, the UIWebView is not full width or height :( Sooooo close.
I also tried this, but the UIImageView do not remain in the same spot.
let left = NSLayoutConstraint(item: self.webView, attribute: .Left, relatedBy: .Equal, toItem: self.view, attribute: .Left, multiplier: 1, constant: 0)
let right = NSLayoutConstraint(item: self.webView, attribute: .Right, relatedBy: .Equal, toItem: self.view, attribute: .Right, multiplier: 1, constant: 0)
let top = NSLayoutConstraint(item: self.webView, attribute: .Top, relatedBy: .Equal, toItem: self.view, attribute: .Top, multiplier: 1, constant: 0)
let bottom = NSLayoutConstraint(item: self.webView, attribute: .Bottom, relatedBy: .Equal, toItem: self.view, attribute: .Bottom, multiplier: 1, constant: 0)
NSLayoutConstraint.activateConstraints([top, bottom, left, right])
I have also tried adding constraints to the UIImageView
let stampView:StampAnnotation = StampAnnotation(imageIcon: UIImage(named: "approved.png"), location: CGPointMake(currentPoint.x, currentPoint.y))
self.webview.scrollView.addSubview(stampView)
let left = NSLayoutConstraint(item: stampView, attribute: .Left, relatedBy: .Equal, toItem: self.webview.scrollView, attribute: .Left, multiplier: 1, constant: 0)
let right = NSLayoutConstraint(item: stampView, attribute: .Right, relatedBy: .Equal, toItem: self.webview.scrollView, attribute: .Right, multiplier: 1, constant: 0)
let top = NSLayoutConstraint(item: stampView, attribute: .Top, relatedBy: .Equal, toItem: self.webview.scrollView, attribute: .Top, multiplier: 1, constant: 0)
let bottom = NSLayoutConstraint(item: stampView, attribute: .Bottom, relatedBy: .Equal, toItem: self.webview.scrollView, attribute: .Bottom, multiplier: 1, constant: 0)
NSLayoutConstraint.activateConstraints([top, bottom, left, right])
same result, UIImageView does not stay in the same spot.
UPDATE
My webview:
webview = UIWebView()
webview.userInteractionEnabled = true
webview.scalesPageToFit = true
webview.becomeFirstResponder()
webview.delegate = self
webview.scrollView.delegate = self
self.view.addSubview(webview)
webview.loadRequest(NSURLRequest(URL:url))
webview.gestureRecognizers = [pinchRecognizer, panRecognizer]
webview.translatesAutoresizingMaskIntoConstraints = false
let left = NSLayoutConstraint(item: webview, attribute: .Left, relatedBy: .Equal, toItem: self.view, attribute: .Left, multiplier: 1, constant: 0)
let right = NSLayoutConstraint(item: webview, attribute: .Right, relatedBy: .Equal, toItem: self.view, attribute: .Right, multiplier: 1, constant: 0)
let top = NSLayoutConstraint(item: webview, attribute: .Top, relatedBy: .Equal, toItem: self.view, attribute: .Top, multiplier: 1, constant: 0)
let bottom = NSLayoutConstraint(item: webview, attribute: .Bottom, relatedBy: .Equal, toItem: self.view, attribute: .Bottom, multiplier: 1, constant: 0)
NSLayoutConstraint.activateConstraints([top, bottom, left, right])
UIImageView
stampView.translatesAutoresizingMaskIntoConstraints = false
let left = NSLayoutConstraint(item: stampView, attribute: .Left, relatedBy: .Equal, toItem: self.webview.scrollView, attribute: .Left, multiplier: 1, constant: 100)
let right = NSLayoutConstraint(item: stampView, attribute: .Right, relatedBy: .Equal, toItem: self.webview.scrollView, attribute: .Right, multiplier: 1, constant: 0)
let top = NSLayoutConstraint(item: stampView, attribute: .Top, relatedBy: .Equal, toItem: self.webview.scrollView, attribute: .Top, multiplier: 1, constant: 100)
let bottom = NSLayoutConstraint(item: stampView, attribute: .Bottom, relatedBy: .Equal, toItem: self.webview.scrollView, attribute: .Bottom, multiplier: 1, constant: 0)
let width = NSLayoutConstraint(item: stampView, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 0.1, constant: 150)
let height = NSLayoutConstraint(item: stampView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 73)
NSLayoutConstraint.activateConstraints([left, right, top, bottom, width, height])
I just need to figure out the math to have this device be at the position of touch. (in percentages ?)
I think these things are always easier to do without using autolayout. To do this, I recomend using viewDidLayoutSubviews(). Here is my code:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
webView.frame = view.bounds
let screen = UIScreen.mainScreen().fixedCoordinateSpace
//These values will give a rect half the size of the screen and centered.
let width = screen.bounds.width / 2
let height = screen.bounds.height / 2
let x = (screen.bounds.width - width) / 2
let y = (screen.bounds.height - height) / 2
let absoluteRect = CGRect(x: x, y: y, width: width, height: height)
let stampRect = screen.convertRect(absoluteRect, toCoordinateSpace: webView)
stampView.frame = stampRect
//Change the orientation of the image
switch UIDevice.currentDevice().orientation {
case .LandscapeLeft:
stampView.image = UIImage(CGImage:originalImage.CGImage!, scale:originalImage.scale, orientation: UIImageOrientation.Left)
break
case .LandscapeRight:
stampView.image = UIImage(CGImage:originalImage.CGImage!, scale:originalImage.scale, orientation: UIImageOrientation.Right)
break
default:
stampView.image = UIImage(CGImage:originalImage.CGImage!, scale:originalImage.scale, orientation: UIImageOrientation.Up)
break
}
}
I am doing several things here...First I set the webViewFrame. Next, it is helpful here to define an absolute coordinate system relative to your screen. When the phone orientation changes, the values of screen will not change (allowing you to keep your imageView in the same place.) Next I define the desired frame for the stampView, then convert the absolute frame into its equivalent inside your scrollView (it's superView) and assign it to the stampView. Finally, if you want the image in your stampView to always be oriented correctly, you need to change the image orientation. CGAffineTransformMakeRotation only works if your view is square, but we can make it more general by actually changing the imageOrientation within the stampView. This requires a property for the original image:
let originalImage = UIImage(named: "image_name")!
Finally, because viewWillLayoutSubViews() is not called for landscape to landscape transitions, do the following:
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
view.setNeedsLayout()
}
This code doesn't make for the prettiest transitions, it should help with your layout problems.
To make the UIImageView keep the same size and stay in the same position relative to the UIWebView, you can set your views to be a percentage of their respective superView. Here I've created some mock views that illustrate the basic idea:
import UIKit
class ViewController: UIViewController {
//we create some views for testing and create references to the size and points we need for positioning
let webView = UIWebView()
let image = UIImageView()
let image2 = UIImageView()
var imageViewSize = CGSize()
var imageViewCenter = CGPoint()
override func viewDidLoad() {
super.viewDidLoad()
//set webView frame
webView.frame = self.view.bounds
webView.backgroundColor = UIColor.clearColor()
webView.userInteractionEnabled = true
webView.scalesPageToFit = true
webView.opaque = false
self.view.addSubview(webView)
//we will hold onto the original size of the UIImageView for later
imageViewSize = CGSizeMake(webView.bounds.size.width * 0.2, webView.bounds.size.height * 0.1)
//mock UIImageView
image.backgroundColor = UIColor.orangeColor()
image.frame.size = CGSizeMake(imageViewSize.width, imageViewSize.height)
image.center = CGPointMake(webView.bounds.size.width / 2, webView.bounds.size.height / 2)
webView.scrollView.addSubview(image)
//I've created a subset image to illustrate the orientation
image2.backgroundColor = UIColor.whiteColor()
image2.frame = CGRectMake(10, 10, 10, 10)
image.addSubview(image2)
}
And then change the frame when rotated (Notice that the position on the UIImageView and the width of the UIWebView are set relative to the height of their superViews and vice versa since the device is rotated):
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
image.frame.size = CGSizeMake(imageViewSize.width, imageViewSize.height)
image.center = CGPointMake(webView.bounds.size.height / 2, webView.bounds.size.width / 2)
webView.frame = CGRectMake(0, 0, self.view.bounds.size.height, self.view.bounds.size.width)
webView.scrollView.contentSize = webView.frame.size
}
}
Since you are creating the position and sizes of your views as percentages of their superViews, the code will play nicer with different device sizes (i.e. iPhone/iPad).

Resources