Search code examples
iosipadresolutionios-autolayout

iPad: Specific/exact position of items for different resolutions


I would like to position UI elements at specific positions on an image, for all iPad resolutions. Imagine a ground plan with different icons/buttons on top. Each icon should be at a very specific position (e.g. exactly in the kitchen, floor, ...). When changing the device/resolution (iPad only) the icons should stay at the correct position, according to the background/ground plan imageView.

See the images (only quick examples): The smallest iPad (9.7") would be the correct position. The other image (12.9") shows the wrong position. (For all iPad sizes, I only chose two examples)

9.7": enter image description here 12.9": enter image description here

I can't get a way or idea to achieve this positioning problem.


Solution

  • You can do this by making your "bulb" positions relative to the size of the "floor plan" image view.

    For example:

    • suppose your floor plan image is 1800 x 1500 and your bulb images are 96 x 96 (I'm estimating, based on the images you posted)...
    • and let's say the center of the top-left bulb is at 276, 486
    • and the imageView holding your floor plan is 900 x 750 (half the original size)

    You would set:

    xScale = 900 / 1800 (0.5)
    yScale = 750 / 1500 (0.5)
    
    bulb width = 96 * xScale
    bulb height = 96 * yScale
    
    bulb center = 276 * xScale, 486 * yScale
    

    Here is some sample code that may help you get started:

    class FloorPlanViewController: UIViewController {
    
        @IBOutlet var floorPlanView: UIImageView!
    
        var bulbs: [UIImageView] = [UIImageView]()
    
        var centers: [CGPoint] = [
            CGPoint(x: 276, y: 486),
            CGPoint(x: 276, y: 648),
            CGPoint(x: 640, y: 486),
            CGPoint(x: 640, y: 648),
            CGPoint(x: 877, y: 486),
            CGPoint(x: 877, y: 648),
            ]
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            for _ in centers {
                let v = bulbImageView()
                floorPlanView.addSubview(v)
                bulbs.append(v)
            }
    
        }
    
        override func viewDidLayoutSubviews() {
            super.viewDidLayoutSubviews()
    
            if let fpImage = floorPlanView.image {
    
                let xScale = floorPlanView.frame.width / fpImage.size.width
                let yScale = floorPlanView.frame.height / fpImage.size.height
    
                for i in 0..<centers.count {
    
                    let thisCenter = centers[i]
                    let thisBulb = bulbs[i]
    
                    thisBulb.frame.size.width = 96.0 * xScale
                    thisBulb.frame.size.height = 96.0 * yScale
    
                    thisBulb.center = CGPoint(x: thisCenter.x * xScale, y: thisCenter.y * yScale)
    
                }
            }
    
        }
    
        func bulbImageView() -> UIImageView {
            let v = UIImageView()
            if let img = UIImage(named: "bulb96x96") {
                v.image = img
            } else {
                v.backgroundColor = .red
            }
            return v
        }
    
    }