pitou pitou - 3 months ago 51
Swift Question

Update views after device rotating

I'm making an application which can be used in landscape and portrait.
It's also possible to move some

views
in a
scrollView
(coordinates saved by
NSUserdefault
).

but I noticed 2 big problems:

1) when I change the orientation of the iPhone, my
views
reset to their first position. this problem is present only when i don't touch yet the
views
. If I touch a
views
, the other
views
change position when the iPhone rotate.

2) same problem but when I scroll. if I don't touch my
views
they change to old position when I scroll, and only once.
ps: after the problem, if I touch a view, all the views change to good position.

I hope I explained well because english is not my first language, so tell me if I forgot data.

Please help me to fix this. Thanks

Answer

You can redefine all your views frames here:

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
}

Here's an example to study the issue

ViewController.swift

import UIKit

class ViewController: UIViewController, UIScrollViewDelegate {

var viewToMove = MyView(frame: CGRect(x: 40, y: 40, width: 80, height: 80))
@IBOutlet var scrollView: UIScrollView!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.


    viewToMove.setupView()

    scrollView.delegate = self
    scrollView.backgroundColor = UIColor.lightGrayColor().colorWithAlphaComponent(0.3)
    scrollView.addSubview(viewToMove)
    scrollView.contentSize = CGSize(width: 800, height: 800)

    let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(ViewController.longPress(_:)))
    viewToMove.addGestureRecognizer(longPressRecognizer)

    updatenavigationItem(UIScreen.mainScreen().bounds.size)

    navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Find", style: UIBarButtonItemStyle.Plain, target: self, action: #selector(scrollToView))
}

func updatenavigationItem (size:CGSize) {
    navigationItem.title = "contentOffset: (\(scrollView.contentOffset.strings.x), \(scrollView.contentOffset.strings.y))"
    navigationItem.prompt = "frame size: \(size)"
}

func scrollViewDidScroll(scrollView: UIScrollView) {
    updatenavigationItem(UIScreen.mainScreen().bounds.size)
}

func scrollToView() {

    let width = UIScreen.mainScreen().bounds.width
    let height = UIScreen.mainScreen().bounds.height

    let x = self.viewToMove.frame.origin.x-width/2
    let y = self.viewToMove.frame.origin.y-height/2

    let centerPoint = CGPoint(x: x, y: y)
    self.scrollView.setContentOffset(centerPoint, animated: true)
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

//Called, when long press occurred
func longPress(longPressGestureRecognizer: UILongPressGestureRecognizer) {
    switch longPressGestureRecognizer.state  {

        case .Began:
            viewToMove.isMoving = true

        case .Changed:
            viewToMove.center = longPressGestureRecognizer.locationInView(scrollView)
            viewToMove.updateTitle()

        case .Ended:
            viewToMove.isMoving = false

        default :
            break
    }
}

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    updatenavigationItem(size)
}
}

MyView.swift

import UIKit

class MyView: UIView {

private var title = UILabel()

func setupView() {

    title = UILabel(frame: self.bounds)
    title.textAlignment = .Center
    title.numberOfLines = 2
    title.font = UIFont.systemFontOfSize(12)
    addSubview(title)

    isMoving = false
    updateTitle()
}

func updateTitle() {
    let x = center.strings.x
    let y = center.strings.y

    title.text = "x: \(x)\ny: \(y)"

}

private var _isMoving = false
var isMoving: Bool {
    set (newValue) {
        if newValue {
            backgroundColor = UIColor.lightGrayColor().colorWithAlphaComponent(0.3)
            layer.borderWidth = 2
            layer.borderColor = UIColor.redColor().CGColor
            title.textColor = UIColor.blackColor()
        } else {
            backgroundColor = UIColor.grayColor()
            layer.borderWidth = 0
            title.textColor = UIColor.whiteColor()
        }
        _isMoving = newValue
    }
    get {
        return _isMoving
    }
}
}

CGPointExtension.swift

import UIKit

extension CGPoint {

var strings: (x:String, y:String) {
    get {
        let format = "%.2f"
        return (String(format: format, x), String(format: format, y))
    }
}
}

Main.storyboard

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15G31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="JYS-qU-rv4">
<dependencies>
    <deployment identifier="iOS"/>
    <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
    <!--Title-->
    <scene sceneID="tne-QT-ifu">
        <objects>
            <viewController id="BYZ-38-t0r" customClass="ViewController" customModule="stackoverflow_39229415" customModuleProvider="target" sceneMemberID="viewController">
                <layoutGuides>
                    <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
                    <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
                </layoutGuides>
                <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
                    <rect key="frame" x="0.0" y="94" width="600" height="506"/>
                    <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                    <subviews>
                        <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="b1d-Ez-GEw">
                            <rect key="frame" x="0.0" y="0.0" width="600" height="506"/>
                        </scrollView>
                    </subviews>
                    <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
                    <constraints>
                        <constraint firstItem="b1d-Ez-GEw" firstAttribute="bottom" secondItem="wfy-db-euE" secondAttribute="top" id="3nd-VB-tHp"/>
                        <constraint firstItem="b1d-Ez-GEw" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="F0H-xs-R6q"/>
                        <constraint firstItem="b1d-Ez-GEw" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" id="cq1-PT-JDa"/>
                        <constraint firstAttribute="trailing" secondItem="b1d-Ez-GEw" secondAttribute="trailing" id="pen-6z-bT6"/>
                    </constraints>
                </view>
                <navigationItem key="navigationItem" title="Title" prompt="Prompt" id="cYl-MP-OqU"/>
                <connections>
                    <outlet property="scrollView" destination="b1d-Ez-GEw" id="wWc-h3-6FR"/>
                </connections>
            </viewController>
            <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
        </objects>
        <point key="canvasLocation" x="1447" y="580"/>
    </scene>
    <!--Navigation Controller-->
    <scene sceneID="TvF-x4-hHN">
        <objects>
            <navigationController automaticallyAdjustsScrollViewInsets="NO" id="JYS-qU-rv4" sceneMemberID="viewController">
                <toolbarItems/>
                <simulatedNavigationBarMetrics key="simulatedTopBarMetrics" translucent="NO"/>
                <navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="EvU-Vd-zk0">
                    <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
                    <autoresizingMask key="autoresizingMask"/>
                </navigationBar>
                <nil name="viewControllers"/>
                <connections>
                    <segue destination="BYZ-38-t0r" kind="relationship" relationship="rootViewController" id="xj1-QQ-ihb"/>
                </connections>
            </navigationController>
            <placeholder placeholderIdentifier="IBFirstResponder" id="pjs-pr-Pd8" userLabel="First Responder" sceneMemberID="firstResponder"/>
        </objects>
        <point key="canvasLocation" x="635" y="580"/>
    </scene>
</scenes>
</document>

Your fixed code

I suggest you to create view1 and view2 programmatically.

ViewController.swift

import UIKit
class ViewController: UIViewController {

@IBOutlet var scrollView: UIScrollView!

var view1 = UIView(frame: CGRect(x: 50, y: 50, width: 150, height: 150))
var view2 = UIView(frame: CGRect(x: 220, y: 50, width: 150, height: 150))

override func viewDidLoad() {
    super.viewDidLoad()

    scrollView.contentSize.width = 1000
    scrollView.contentSize.height = 1000

    initView(view1, color: UIColor.yellowColor())
    initView(view2, color: UIColor.blueColor())
}

func initView(viewToInit: UIView, color: UIColor) {
    viewToInit.backgroundColor = color
    viewToInit.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(ViewController.dragDrop(_:))))
    scrollView.addSubview(viewToInit)
}

func setupViewsCoordinates() {
    if let coord1 = NSUserDefaults.standardUserDefaults().valueForKey("coord1") as? String {
        self.view1.center = CGPointFromString(coord1)
        NSLog("\(self.view1.center)")
    }

    if let coord2 = NSUserDefaults.standardUserDefaults().valueForKey("coord2") as? String  {
        self.view2.center = CGPointFromString(coord2)
        NSLog("\(self.view2.center)")
    }

}

override func viewDidLayoutSubviews() {
    setupViewsCoordinates()
}

func dragDrop (sender: UIPanGestureRecognizer) {

    if let senderView = sender.view {

        let newPoint = sender.locationInView(scrollView)
        senderView.center = newPoint

        switch sender.state  {

            // case .Began:
            //case .Changed:

        case .Ended:

            switch senderView {
            case view1:
                NSUserDefaults.standardUserDefaults().setValue(NSStringFromCGPoint(newPoint), forKey: "coord1")

            case view2:
                NSUserDefaults.standardUserDefaults().setValue(NSStringFromCGPoint(newPoint), forKey: "coord2")

            default:
                break
            }

        default :
            break
        }
    }
}
}

Main.storyboard

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15G31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="sZy-5d-rmJ">
<dependencies>
    <deployment identifier="iOS"/>
    <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
    <!--View Controller-->
    <scene sceneID="tne-QT-ifu">
        <objects>
            <viewController id="BYZ-38-t0r" customClass="ViewController" customModule="stackoverflow_39229415" customModuleProvider="target" sceneMemberID="viewController">
                <layoutGuides>
                    <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
                    <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
                </layoutGuides>
                <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
                    <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                    <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                    <subviews>
                        <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="iH0-w9-3Vi">
                            <rect key="frame" x="0.0" y="20" width="600" height="580"/>
                            <subviews>
                                <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="r4F-iB-85e">
                                    <rect key="frame" x="24" y="19" width="46" height="30"/>
                                    <state key="normal" title="back"/>
                                    <connections>
                                        <segue destination="sZy-5d-rmJ" kind="show" id="oqB-nQ-Cbx"/>
                                    </connections>
                                </button>
                            </subviews>
                        </scrollView>
                    </subviews>
                    <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
                    <constraints>
                        <constraint firstItem="iH0-w9-3Vi" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="0JR-2o-xMa"/>
                        <constraint firstItem="iH0-w9-3Vi" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" id="H6h-8P-2lO"/>
                        <constraint firstItem="iH0-w9-3Vi" firstAttribute="bottom" secondItem="wfy-db-euE" secondAttribute="top" id="SXz-HG-hhh"/>
                        <constraint firstAttribute="trailing" secondItem="iH0-w9-3Vi" secondAttribute="trailing" id="s9E-4S-nuH"/>
                    </constraints>
                </view>
                <connections>
                    <outlet property="scrollView" destination="iH0-w9-3Vi" id="y87-TR-x9X"/>
                </connections>
            </viewController>
            <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
        </objects>
        <point key="canvasLocation" x="1064" y="532"/>
    </scene>
    <!--View Controller-->
    <scene sceneID="jm6-I7-f2e">
        <objects>
            <viewController id="sZy-5d-rmJ" sceneMemberID="viewController">
                <layoutGuides>
                    <viewControllerLayoutGuide type="top" id="FVf-Ax-2ZB"/>
                    <viewControllerLayoutGuide type="bottom" id="LjK-dO-wuz"/>
                </layoutGuides>
                <view key="view" contentMode="scaleToFill" id="ERa-Mg-7aJ">
                    <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                    <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                    <subviews>
                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="pYW-PU-huc">
                            <rect key="frame" x="269" y="285" width="63" height="30"/>
                            <constraints>
                                <constraint firstAttribute="width" constant="63" id="5JS-Ml-DRK"/>
                                <constraint firstAttribute="height" constant="30" id="UDb-RY-Nvb"/>
                            </constraints>
                            <state key="normal" title="start test"/>
                            <connections>
                                <segue destination="BYZ-38-t0r" kind="show" id="PaJ-ee-tBZ"/>
                            </connections>
                        </button>
                    </subviews>
                    <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                    <constraints>
                        <constraint firstItem="pYW-PU-huc" firstAttribute="centerX" secondItem="ERa-Mg-7aJ" secondAttribute="centerX" id="PFN-01-ccJ"/>
                        <constraint firstItem="pYW-PU-huc" firstAttribute="centerY" secondItem="ERa-Mg-7aJ" secondAttribute="centerY" id="ooK-Nd-fOP"/>
                    </constraints>
                </view>
            </viewController>
            <placeholder placeholderIdentifier="IBFirstResponder" id="9JD-Yr-djy" userLabel="First Responder" sceneMemberID="firstResponder"/>
        </objects>
        <point key="canvasLocation" x="170" y="757"/>
    </scene>
</scenes>
</document>