How to achieve the desired landscape and portrait layout (swift)

I am trying to include resizing functionality to my app by supporting landscape portion as well as portrait. I have no problem achieving the portrait layout which is this one:

whoever when I rotate the emulator everything becomes a mess. I am trying to set the frames of all of the components to the desired values when the rotation changes. However, what I get is a big mess and the components are not placed where I want. Any suggestions on how to achieve the portrait and landscape layouts? I want to achieve this landscape layout:

Here is my code in the view controller:

class EditViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {
@IBOutlet weak var hideKeyboardOutlet: UIButton!
@IBOutlet weak var iconPicker: UIPickerView!
@IBOutlet weak var resolutionTitleDeadLabel: UILabel!
@IBOutlet weak var achievingDateDeadLabel: UILabel!
@IBOutlet weak var chooseAnIconDeadLabel: UILabel!
@IBOutlet weak var cancelButtonOutlet: UIButton!
@IBOutlet weak var saveButtonOutlet: UIButton!


@IBOutlet weak var resolutionTitle: UITextField!

@IBOutlet weak var datePicker: UIDatePicker!

let kComponentCount: Int = 1
let kIconComponent: Int = 0
var iconStruct: Icons?

override func viewDidLoad() {
    super.viewDidLoad()
    iconStruct = Icons()
    updateInterface()
}

@IBAction func hideKeyboard(sender: AnyObject) {
    resolutionTitle.resignFirstResponder()
}

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

override func supportedInterfaceOrientations() -> Int {
    return Int(UIInterfaceOrientationMask.All.rawValue)
}

override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
    updateInterface()
}


@IBAction func saveButton(sender: AnyObject) {
    var dateFormatter = NSDateFormatter()
    dateFormatter.dateFormat = "dd-MM-yyyy"
    var strDate = dateFormatter.stringFromDate(datePicker.date)
    NSLog("\(datePicker.date)")
    var currentDate = dateFormatter.stringFromDate(NSDate())
    var pickedIcon: String = iconStruct!.urlImageStrings[iconPicker.selectedRowInComponent(kIconComponent)]

    var newResolution = ["name":resolutionTitle.text,"achievingDate":strDate,"startingDate":"\(currentDate)","icon":"\(pickedIcon)","isAchieved":"N"] as Dictionary<String,String>
    //if the resolution title is not empty...
    if(!resolutionTitle.text.isEmpty){
        //... create new resolution, it and save it to the file.
        var destinationController = (presentingViewController as! UINavigationController).viewControllers[0] as! MasterViewController
        destinationController.resolutions.insert(newResolution, atIndex: 0)
        destinationController.notifyTableViewForNewInsertion()
        destinationController.saveDateToFile()
        self.dismissViewControllerAnimated(true, completion: {})
    }else{
        // Notify the user that the title text field is empty
        let alertController = UIAlertController(title: "Flower Selection", message: "Cannot create a resolution with empty title!", preferredStyle: .Alert)
        let defaultAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.Cancel, handler: nil)

        alertController.addAction(defaultAction)
        presentViewController(alertController, animated: true, completion: nil)
    }


}
@IBAction func cancelButton(sender: AnyObject) {
    self.dismissViewControllerAnimated(true, completion: {})
}

func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
    return kComponentCount
}


func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    return iconStruct!.length!
}

func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent   component: Int, reusingView view: UIView!) -> UIView {
    let chosenImage: UIImageView = UIImageView(image: iconStruct?.getImageAtIndex(index: row))
    let workaroundImageView: UIImageView = UIImageView(frame: chosenImage.frame)
    workaroundImageView.backgroundColor = UIColor(patternImage: chosenImage.image!)
    return workaroundImageView
}

func pickerView(pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
    return 95
}


func updateInterface(){
    if interfaceOrientation == UIInterfaceOrientation.Portrait || interfaceOrientation == UIInterfaceOrientation.PortraitUpsideDown{
        self.hideKeyboardOutlet.frame = CGRectMake(0, 54, 375, 667)
        self.resolutionTitleDeadLabel.frame = CGRectMake(100, 39, 174, 21)
        self.resolutionTitle.frame = CGRectMake(43, 68, 289, 30)
        self.achievingDateDeadLabel.frame = CGRectMake(101, 106, 174, 21)
        self.datePicker.frame = CGRectMake(27, 135, 320, 162)
        self.chooseAnIconDeadLabel.frame = CGRectMake(101, 315, 181, 21)
        self.iconPicker.frame = CGRectMake(57,344,262,150)
        self.cancelButtonOutlet.frame = CGRectMake(86, 516, 62, 45)
        self.saveButtonOutlet.frame = CGRectMake(213, 516, 62, 45)
        NSLog("Portret")
    }else{
        self.hideKeyboardOutlet.frame = CGRectMake(0,38, 667,339)
        self.resolutionTitleDeadLabel.frame = CGRectMake(100,39,446,21)
        self.resolutionTitle.frame = CGRectMake(43,68,581,30)
        self.achievingDateDeadLabel.frame = CGRectMake(115,106,144,21)
        self.datePicker.frame = CGRectMake(43,135,255,162)
        self.chooseAnIconDeadLabel.frame = CGRectMake(391,106,181,21)
        self.iconPicker.frame = CGRectMake(352,135,258,187)
        self.cancelButtonOutlet.frame = CGRectMake(147,322,62,45)
        self.saveButtonOutlet.frame = CGRectMake(450,322,62,45)
        NSLog("Landscape")
    }

}


}

Answers


The easiest way (by a country mile) to do this is to use UIStackView (or rather nested UIStackViews).

You will have several "components" of your view where each component is a collection of views inside a UIStackView.

  1. The titleStackView
  2. The dateStackView
  3. The iconStackView
  4. The buttonStackView
The setup

Each of these should be a UIStackView.

The titleStackView will be vertical because the UILabel is above the UITextField same for the others except the buttonStackView will be horizontal. (There is an axis property on UIStackView).

Next you need another UIStackView. This will contain the dateComponent and the iconStackView. I'll call this stack view the mainStackView.

Finally you need another stack view (outerStackView) that is vertical and contains the titleStackView the mainStackView and the buttonStackView.

The switch

Now, when the orientation changes between landscape and portrait all you have to do is update the axis property on the mainStackView. If the orientation is portrait set...

mainStackView.axis = .vertical

and if the orientation is landscape set...

mainStackView.axis = .horizontal

All you need is three lines of code to actually make the change and not a single UILayoutConstraint in sight! (Well, 4 to pin the outerStackView to the edges of the screen but that's it).


Need Your Help

How to display short read only FlowDocument in a label-like control

c# wpf .net-3.5 label flowdocument

I am looking for a way to present short FlowDocument strings in a label-like control.

CakePHP 2 how to do multiple pagination with same model

jquery ajax cakephp pagination cakephp-2.0

So, I have 1 view, and I need to do pagination for 2 tables for the same model, but different conditions. e.g: