首页 > 解决方案 > 如何相对于图像在背景图像上定位 UI 元素

问题描述

我以前在这里问过如何在 ScrollView 中制作全屏背景图像并保持纵横比并从“ekscrypto”获得很好的回答,再次感谢您。

在此处输入图像描述

我在图像上有带有文本的按钮(1、2、3、4、5 等)以前我使用硬编码的 X 和 Y 坐标来定位背景图像上的 UI 元素(按钮),这个解决方案适用于所有 iPhone 设备,不在 iPad 上。我根据从“ekscrypto”收到的解决方案更改了我的代码,现在这个解决方案当然不适用于任何设备。

图像上有一条道路,我需要在这条道路上安排这些按钮。无论设备和图像比例如何,如何相对于图像正确定位此按钮?

PS Ekscrypto 还提供了 UI 元素定位的解决方案,但我不明白它是如何工作的。

这是我目前尝试创建按钮的方式:

let imageOne = UIImage(named: "level1") as UIImage?
let levelOne = UIButton(type: UIButtonType.system) 
levelOne.frame = CGRect.init(x: 10, y: 10, width: 100, height: 45)
levelOne.setImage(imageOne, for: .normal) 
scrollView.addSubview(levelOne)

但是 iPhone 和 iPad 的按钮位置和大小应该是不同的。我怎样才能让它们相对于图像正确放置?

非常感谢 ekscrypto,很抱歉延迟回答。您的代码正在运行,并解决了我的问题,但有一个小问题。

  1. 必须将此行让按钮 = UIButton(type: .system) 更改为 .custom,或者代替背景图像,您会得到填充蓝色的按钮。

  2. 带有背景图片的按钮太大,特别是在 iPhone 5 上,将 let backgroundDesignHeight: CGFloat = 330.0 更改为 730 以使其更小

  3. iPhone和iPad上的所有按钮都在同一个位置,除了«plus devices»底部(向下)按钮有一个小的偏移量应该略高

  4. 在某些设备上,按钮上的背景图像有点模糊,这是在我将 backgroundDesignHeight 更改为 730 之后发生的

标签: iosswift

解决方案


您可以通过以下几种方式解决此问题:

  • 根据当前屏幕尺寸和“设计”尺寸手动计算最终的 x/y 位置
  • 手动创建基于纵横比的约束,让 iOS 为您计算最终位置

假设您的设备/应用程序方向是恒定的(始终为横向或始终纵向)并且始终为全屏,则手动计算可能更容易。

首先,您需要一个辅助函数来调整图像大小:

private func scaledImage(named imageName: String, scale: CGFloat) -> UIImage? {
    guard let image = UIImage(named: imageName) else { return nil }
    let targetSize = CGSize(width: image.size.width * scale, height: image.size.height * scale)
    return resizeImage(image: image, targetSize: targetSize)
}

// Adapted from https://stackoverflow.com/questions/31314412/how-to-resize-image-in-swift
private func resizeImage(image: UIImage, targetSize: CGSize) -> UIImage? {
    let size = image.size

    let widthRatio  = targetSize.width  / size.width
    let heightRatio = targetSize.height / size.height

    // Figure out what our orientation is, and use that to form the rectangle
    var newSize: CGSize
    if(widthRatio > heightRatio) {
        newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
    } else {
        newSize = CGSize(width: size.width * widthRatio, height: size.height * widthRatio)
    }


    // This is the rect that we've calculated out and this is what is actually used below
    let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)

    // Actually do the resizing to the rect using the ImageContext stuff
    UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
    image.draw(in: rect)
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return newImage
}

接下来,我们将创建一个函数来计算按钮的位置,以及基于图像大小的按钮大小:

private func positionScaledButton(x designX: CGFloat, y designY: CGFloat, imageName: String) -> UIButton {

    // First, compute our "designScale"
    let screenHeight = UIScreen.main.bounds.size.height
    let backgroundDesignHeight: CGFloat = 330.0 // ** see below
    let designScale = screenHeight / backgroundDesignHeight


    // Create button
    let button = UIButton(type: .custom)

    // Get image to use, and scale it as required
    guard let image = scaledImage(named: imageName, scale: designScale) else { return button }

    button.frame = CGRect(x: designX * designScale, y: designY * designScale, width: image.size.width, height: image.size.height)
    button.setImage(image, for: .normal)
    scrollView.addSubview(button)
    return button
}

** 上面代码中的值“330.0”是指滚动条中背景图像的高度,从这里测量按钮的x/y坐标。

假设按钮的左上角应该在 x: 10, y: 10,对于图像“levelOne”:

let levelOneButton = positionScaledButton(x: 10, y: 10, imageName: "imageOne")
// To do: addTarget event handler

推荐阅读