Uiview 如何以及何时调用setNeedsLayout()方法在superview上布局子视图?

Uiview 如何以及何时调用setNeedsLayout()方法在superview上布局子视图?,uiview,swift4.2,Uiview,Swift4.2,执行分配,其中提供网格对象,用于将矩形划分为单元格网格。我创建了两个名为GridView和SetView的自定义视图,其中前者是superview,后者是subview。我试图在GridView上添加12个SetView作为子视图,但我的代码(在下面提供的代码中)不会产生任何结果 要调用方法layoutSubviews()是否需要调用setNeedsLayout()方法?layoutSubviews()有助于尽可能地定位子视图,因此从网格对象中获取矩形或单元格后,我将每个子视图的frame.or

执行分配,其中提供网格对象,用于将矩形划分为单元格网格。我创建了两个名为GridView和SetView的自定义视图,其中前者是superview,后者是subview。我试图在GridView上添加12个SetView作为子视图,但我的代码(在下面提供的代码中)不会产生任何结果

要调用方法
layoutSubviews()
是否需要调用
setNeedsLayout()
方法?
layoutSubviews()
有助于尽可能地定位子视图,因此从网格对象中获取矩形或单元格后,我将每个子视图的frame.origin设置为该矩形的原点。我没有得到任何结果

import UIKit
class GridView: UIView {

   lazy var grid = Grid(layout: Grid.Layout.fixedCellSize(CGSize(width: 100.0, height: 120.0)), frame: CGRect(origin: CGPoint(x: bounds.minX, y: bounds.minY), size: CGSize(width: bounds.width, height: bounds.height)))



    private var cardsFlag = false

    lazy var listOfSetCard = createSetCards()
    lazy var cardsOnScreen = countTheNumberOfCards()

    var trackOfCards: Int {
        get {
            return cardsOnScreen
        }
        set(newValue) {
            self.trackOfCards = newValue
        }
    }

    private func createSetCards() -> [SetView] {
        var cards = [SetView]()
        for _ in 0..<12 {
            let card = SetView()
            addSubview(card)
            cards.append(card)
        }
        print("I am here")
        return cards
    }

    private func countTheNumberOfCards() -> Int {

        if !cardsFlag && !listOfSetCard.isEmpty {
            cardsOnScreen = 12
            setNeedsLayout()
            cardsFlag = true
        }
        print("But I come here first")
        return cardsOnScreen

    }

    override func layoutSubviews() {
        for index in listOfSetCard.indices {
            let card = listOfSetCard[index]
            if let rect = grid[index] {
                card.frame.origin = rect.origin
                print(card.frame.origin)
            }
        }
    }
}
/* The Grid Object */ 
import UIKit

struct Grid
{
    enum Layout {
        case fixedCellSize(CGSize)
        case dimensions(rowCount: Int, columnCount: Int)
        case aspectRatio(CGFloat)
    }

    var layout: Layout { didSet { recalculate() } }

    var frame: CGRect { didSet { recalculate() } }

    init(layout: Layout, frame: CGRect = CGRect.zero) {
        self.frame = frame
        self.layout = layout
        recalculate()
    }

    subscript(row: Int, column: Int) -> CGRect? {
        return self[row * dimensions.columnCount + column]
    }

    subscript(index: Int) -> CGRect? {
        return index < cellFrames.count ? cellFrames[index] : nil
    }

    var cellCount: Int {
        get {
            switch layout {
            case .aspectRatio: return cellCountForAspectRatioLayout
            case .fixedCellSize, .dimensions: return calculatedDimensions.rowCount * calculatedDimensions.columnCount
            }
        }
        set { cellCountForAspectRatioLayout = newValue }
    }

    var cellSize: CGSize {
        get { return cellFrames.first?.size ?? CGSize.zero }
        set { layout = .fixedCellSize(newValue) }
    }

    var dimensions: (rowCount: Int, columnCount: Int) {
        get { return calculatedDimensions }
        set { layout = .dimensions(rowCount: newValue.rowCount, columnCount: newValue.columnCount) }
    }

    var aspectRatio: CGFloat {
        get {
            switch layout {
            case .aspectRatio(let aspectRatio):
                return aspectRatio
            case .fixedCellSize(let size):
                return size.height > 0 ? size.width / size.height : 0.0
            case .dimensions(let rowCount, let columnCount):
                if rowCount > 0 && columnCount > 0 && frame.size.width > 0 {
                    return (frame.size.width / CGFloat(columnCount)) / (frame.size.width / CGFloat(rowCount))
                } else {
                    return 0.0
                }
            }
        }
        set { layout = .aspectRatio(newValue) }
    }

    private var cellFrames = [CGRect]()
    private var cellCountForAspectRatioLayout = 0 { didSet { recalculate() } }
    private var calculatedDimensions: (rowCount: Int, columnCount: Int) = (0, 0)

    private mutating func recalculate() {
        switch layout {
        case .fixedCellSize(let cellSize):
            if cellSize.width > 0 && cellSize.height > 0 {
                calculatedDimensions.rowCount = Int(frame.size.height / cellSize.height)
                calculatedDimensions.columnCount = Int(frame.size.width / cellSize.width)
                updateCellFrames(to: cellSize)
            } else {
                assert(false, "Grid: for fixedCellSize layout, cellSize height and width must be positive numbers")
                calculatedDimensions = (0, 0)
                cellFrames.removeAll()
            }
        case .dimensions(let rowCount, let columnCount):
            if columnCount > 0 && rowCount > 0 {
                calculatedDimensions.rowCount = rowCount
                calculatedDimensions.columnCount = columnCount
                let cellSize = CGSize(width: frame.size.width/CGFloat(columnCount), height: frame.size.height/CGFloat(rowCount))
                updateCellFrames(to: cellSize)
            } else {
                assert(false, "Grid: for dimensions layout, rowCount and columnCount must be positive numbers")
                calculatedDimensions = (0, 0)
                cellFrames.removeAll()
            }
        case .aspectRatio:
            assert(aspectRatio > 0, "Grid: for aspectRatio layout, aspectRatio must be a positive number")
            let cellSize = largestCellSizeThatFitsAspectRatio()
            if cellSize.area > 0 {
                calculatedDimensions.columnCount = Int(frame.size.width / cellSize.width)
                calculatedDimensions.rowCount = (cellCount + calculatedDimensions.columnCount - 1) / calculatedDimensions.columnCount
            } else {
                calculatedDimensions = (0, 0)
            }
            updateCellFrames(to: cellSize)
            break
        }
    }

    private mutating func updateCellFrames(to cellSize: CGSize) {
        cellFrames.removeAll()

        let boundingSize = CGSize(
            width: CGFloat(dimensions.columnCount) * cellSize.width,
            height: CGFloat(dimensions.rowCount) * cellSize.height
        )
        let offset = (
            dx: (frame.size.width - boundingSize.width) / 2,
            dy: (frame.size.height - boundingSize.height) / 2
        )
        var origin = frame.origin
        origin.x += offset.dx
        origin.y += offset.dy

        if cellCount > 0 {
            for _ in 0..<cellCount {
                cellFrames.append(CGRect(origin: origin, size: cellSize))
                origin.x += cellSize.width
                if round(origin.x) > round(frame.maxX - cellSize.width) {
                    origin.x = frame.origin.x + offset.dx
                    origin.y += cellSize.height
                }
            }
        }
    }

    private func largestCellSizeThatFitsAspectRatio() -> CGSize {
        var largestSoFar = CGSize.zero
        if cellCount > 0 && aspectRatio > 0 {
            for rowCount in 1...cellCount {
                largestSoFar = cellSizeAssuming(rowCount: rowCount, minimumAllowedSize: largestSoFar)
            }
            for columnCount in 1...cellCount {
                largestSoFar = cellSizeAssuming(columnCount: columnCount, minimumAllowedSize: largestSoFar)
            }
        }
        return largestSoFar
    }

    private func cellSizeAssuming(rowCount: Int? = nil, columnCount: Int? = nil, minimumAllowedSize: CGSize = CGSize.zero) -> CGSize {
        var size = CGSize.zero
        if let columnCount = columnCount {
            size.width = frame.size.width / CGFloat(columnCount)
            size.height = size.width / aspectRatio
        } else if let rowCount = rowCount {
            size.height = frame.size.height / CGFloat(rowCount)
            size.width = size.height * aspectRatio
        }
        if size.area > minimumAllowedSize.area {
            if Int(frame.size.height / size.height) * Int(frame.size.width / size.width) >= cellCount {
                return size
            }
        }
        return minimumAllowedSize
    }
}

private extension CGSize {
    var area: CGFloat {
        return width * height
    }
}
导入UIKit
类GridView:UIView{
lazy var grid=grid(布局:grid.layout.fixedCellSize(CGSize(宽度:100.0,高度:120.0)),帧:CGRect(原点:CGPoint(x:bounds.minX,y:bounds.minY),大小:CGSize(宽度:bounds.width,高度:bounds.height)))
private var cardsFlag=false
lazy var listOfSetCard=createSetCards()
lazy var cardsOnScreen=countTheNumberOfCards()
var跟踪卡:Int{
得到{
返回卡片屏幕
}
设置(新值){
self.trackOfCards=newValue
}
}
private func createSetCards()->[SetView]{
var卡=[SetView]()
对于0..Int中的u{
if!cardsFlag&!listOfSetCard.isEmpty{
cardsOnScreen=12
setNeedsLayout()
cardsFlag=true
}
打印(“但我先来这里”)
返回卡片屏幕
}
覆盖func布局子视图(){
对于listOfSetCard.index中的索引{
let card=列表设置卡[索引]
如果let rect=网格[索引]{
card.frame.origin=rect.origin
打印(卡、框、原点)
}
}
}
}
/*网格对象*/
导入UIKit
结构网格
{
枚举布局{
案例固定单元大小(CGSize)
大小写维度(行数:Int,列数:Int)
案例方面(CGFloat)
}
变量布局:布局{didSet{recalculate()}
变量帧:CGRect{didSet{recalculate()}
init(布局:布局,帧:CGRect=CGRect.zero){
self.frame=frame
self.layout=布局
重新计算()
}
下标(行:Int,列:Int)->CGRect{
返回self[row*dimensions.columnCount+column]
}
下标(索引:Int)->CGRect{
返回索引0?size.width/size.height:0.0
大小写维度(让行计数,让列计数):
如果rowCount>0&&columnCount>0&&frame.size.width>0{
返回(frame.size.width/CGFloat(columnCount))/(frame.size.width/CGFloat(rowCount))
}否则{
返回0.0
}
}
}
集合{layout=.aspectRatio(newValue)}
}
私有变量cellFrames=[CGRect]()
private var cellcountforaspectatiolayout=0{didSet{recalculate()}
私有变量calculatedDimensions:(行计数:Int,列计数:Int)=(0,0)
私有变异函数重新计算(){
交换机布局{
案例。固定单元格大小(let cellSize):
如果cellSize.width>0&&cellSize.height>0{
calculatedDimensions.rowCount=Int(frame.size.height/cellSize.height)
calculatedDimensions.columnCount=Int(frame.size.width/cellSize.width)
updateCellFrames(到:cellSize)
}否则{
断言(false,“网格:对于fixedCellSize布局,cellSize高度和宽度必须为正数”)
计算的维度=(0,0)
cellFrames.removeAll()
}
大小写维度(让行计数,让列计数):
如果columnCount>0&&rowCount>0{
calculatedDimensions.rowCount=rowCount
calculatedDimensions.columnCount=columnCount
设cellSize=CGSize(宽度:frame.size.width/CGFloat(columnCount),高度:frame.size.height/CGFloat(rowCount))
updateCellFrames(到:cellSize)
}否则{
断言(false,“网格:对于维度布局,行数和列数必须为正数”)
计算的维度=(0,0)
cellFrames.removeAll()
}
案例.方面:
断言(aspectRatio>0,“网格:对于aspectRatio布局,aspectRatio必须是正数”)
设cellSize=LargestCellSizeThatFitsSpectratio()
如果cellSize.area>0{
calculatedDimensions.columnCount=Int(frame.size.width/cellSize.width)
calculatedDimensions.rowCount=(cellCount+calculatedDimensions.columnCount-1)/calculatedDimensions.columnCount
}否则{
计算尺寸