簡體   English   中英

如何制作自定尺寸 UiImageView?

[英]How to make a Self-sizing UiImageView?

我需要一個可以重復使用的簡單二維碼 class。 我創建了 class 並且它可以工作,但是不需要手動設置大小約束,因為它需要根據設備的 DPI 調整其大小。 在這個最小的示例中,我只使用 100,因為大小計算代碼不相關(在 IB 中設置為 50)。 此外,我將在不同的位置有多個 QR 碼,我將通過 IB 管理它們的定位。 但至少我希望能夠在代碼中設置寬度和高度約束。

下面的代碼顯示了一個正確大小的 QR 碼(在運行時設置),但是當約束設置為水平和垂直居中時,它不會。 同樣,我不想要 IB 中的大小約束,但我確實想要 IB 中的 position 約束

import Foundation
import UIKit

@IBDesignable class QrCodeView: UIImageView {
    var content:String = "test" {
        didSet {
            generateCode(content)
        }
    }
    lazy var filter = CIFilter(name: "CIQRCodeGenerator")
    lazy var imageView = UIImageView()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        imageView.frame = CGRect(x:0, y:0, width:100, height:100)
        frame = CGRect(x:frame.origin.x, y:frame.origin.y, width:100, height:100)

    }

    func setup() {
        //translatesAutoresizingMaskIntoConstraints = false
        generateCode(content)


        addSubview(imageView)
        layoutIfNeeded()

    }

    func generateCode(_ string: String) {
        guard let filter = filter,
        let data = string.data(using: .isoLatin1, allowLossyConversion: false) else {
            return
        }

        filter.setValue(data, forKey: "inputMessage")

        guard let ciImage = filter.outputImage else {
            return
        }
        let transform = CGAffineTransform(scaleX: 10, y: 10)
        let scaled = UIImage(ciImage: ciImage.transformed(by: transform))

        imageView.image = scaled
    }

}

我相信你讓這比需要的更復雜......

讓我們從一個簡單的@IBDesignable UIImageView子類開始。

從一個新項目開始並添加以下代碼:

@IBDesignable
class MyImageView: UIImageView {

    // we'll use this later
    var myIntrinsicSize: CGSize = CGSize(width: 100.0, height: 100.0)
    override var intrinsicContentSize: CGSize {
        return myIntrinsicSize
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }
    
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        setup()
        self.image = UIImage()
    }
    
    func setup() {
        backgroundColor = .green
        contentMode = .scaleToFill
    }

}

現在,在 Storyboard 中,將UIImageView添加到視圖 controller。 將其自定義 class 設置為MyImageView並設置水平和垂直中心約束。

圖像視圖應該自動將自身大小調整為100 x 100 ,以綠色背景為中心(我們只是設置背景以便我們可以看到它):

在此處輸入圖像描述

運行應用程序,您應該會看到相同的內容。

現在,將其作為@IBOutlet添加到視圖 controller:

class ViewController: UIViewController {

    @IBOutlet var testImageView: MyImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        testImageView.myIntrinsicSize = CGSize(width: 300.0, height: 300.0)
    }
}

運行應用程序,您將看到一個居中的綠色圖像視圖,但現在它將是300 x 300點而不是100 x 100

渲染 QRCode 圖像后,您的任務的 rest 幾乎是添加代碼來設置此自定義類的.image屬性。

這是自定義 class:

@IBDesignable
class QRCodeView: UIImageView {
    
    // so we can test changing the QRCode content in IB
    @IBInspectable
    var content:String = "test" {
        didSet {
            generateCode(content)
        }
    }
    
    var qrIntrinsicSize: CGSize = CGSize(width: 100.0, height: 100.0)
    override var intrinsicContentSize: CGSize {
        return qrIntrinsicSize
    }
    
    lazy var filter = CIFilter(name: "CIQRCodeGenerator")
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }
    
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        setup()
        generateCode(content)
    }
    
    func setup() {
        contentMode = .scaleToFill
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        generateCode(content)
    }
    
    func generateCode(_ string: String) {
        guard let filter = filter,
            let data = string.data(using: .isoLatin1, allowLossyConversion: false) else {
                return
        }
        
        filter.setValue(data, forKey: "inputMessage")
        
        guard let ciImage = filter.outputImage else {
            return
        }
        
        let scX = bounds.width / ciImage.extent.size.width
        let scY = bounds.height / ciImage.extent.size.height

        let transform = CGAffineTransform(scaleX: scX, y: scY)

        let scaled = UIImage(ciImage: ciImage.transformed(by: transform))
        
        self.image = scaled
        
    }
    
}

在 Storyboard / IB 中:

在此處輸入圖像描述

這是一個示例視圖 controller:

class ViewController: UIViewController {
    
    @IBOutlet var qrCodeView: QRCodeView!
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        // calculate your needed size
        //  I'll assume it ended up being 240 x 240
        qrCodeView.qrIntrinsicSize = CGSize(width: 240.0, height: 240.0)
    }
    
}

編輯

這是一個修改后的QRCodeView class,它將自己調整為(物理)15x15 毫米圖像。

我使用DeviceKit ://github.com/devicekit/DeviceKit的 DeviceKit 來獲取當前設備的ppi 請參閱評論以將其替換為您自己的(假設您已經在使用其他東西)。

當這個 class 被實例化時,它將:

  • 獲取當前設備的 ppi
  • 將 ppi 轉換為每毫米像素
  • 計算每毫米 15 x 像素
  • 根據屏幕比例轉換
  • 更新其內在大小

QRCodeViewUIImageView的子類)只需要 position 約束……所以您可以使用 Top + Leading、Top + Trailing、Center X & Y、Bottom + CenterX 等。

@IBDesignable
class QRCodeView: UIImageView {
    
    @IBInspectable
    var content:String = "test" {
        didSet {
            generateCode(content)
        }
    }
    
    var qrIntrinsicSize: CGSize = CGSize(width: 100.0, height: 100.0)
    override var intrinsicContentSize: CGSize {
        return qrIntrinsicSize
    }
    
    lazy var filter = CIFilter(name: "CIQRCodeGenerator")
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }
    
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        setup()
        generateCode(content)
    }
    
    func setup() {
        contentMode = .scaleToFill
        
        // using DeviceKit from https://github.com/devicekit/DeviceKit
        // replace with your lookup code that gets
        //  the device's ppi
        let device = Device.current
        guard let ppi = device.ppi else { return }
        
        // convert to pixels-per-millimeter
        let ppmm = CGFloat(ppi) / 25.4
        // we want 15mm size
        let mm15 = 15.0 * ppmm
        // convert based on screen scale
        let mmScale = mm15 / UIScreen.main.scale
        // update our intrinsic size
        self.qrIntrinsicSize = CGSize(width: mmScale, height: mmScale)

    }
    override func layoutSubviews() {
        super.layoutSubviews()
        generateCode(content)
    }
    
    func generateCode(_ string: String) {
        guard let filter = filter,
            let data = string.data(using: .isoLatin1, allowLossyConversion: false) else {
                return
        }
        
        filter.setValue(data, forKey: "inputMessage")
        
        guard let ciImage = filter.outputImage else {
            return
        }
        
        let scX = bounds.width / ciImage.extent.size.width
        let scY = bounds.height / ciImage.extent.size.height

        let transform = CGAffineTransform(scaleX: scX, y: scY)

        let scaled = UIImage(ciImage: ciImage.transformed(by: transform))

        self.image = scaled
        
    }
    
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM