Ios 删除和替换子视图时如何处理?
我想为iOS制作游戏“设置” 现在我想做的第一件事就是把前12张卡片放到屏幕上 为了处理卡片的位置,老师给了我们这个网格Ios 删除和替换子视图时如何处理?,ios,swift,Ios,Swift,我想为iOS制作游戏“设置” 现在我想做的第一件事就是把前12张卡片放到屏幕上 为了处理卡片的位置,老师给了我们这个网格 // // Grid.swift // // Created by CS193p Instructor. // Copyright © 2017 Stanford University. All rights reserved. // // Arranges the space in a rectangle into a grid of cells. // All
//
// Grid.swift
//
// Created by CS193p Instructor.
// Copyright © 2017 Stanford University. All rights reserved.
//
// Arranges the space in a rectangle into a grid of cells.
// All cells will be exactly the same size.
// If the grid does not fill the provided frame edge-to-edge
// then it will center the grid of cells in the provided frame.
// If you want spacing between cells in the grid, simply inset each cell's frame.
//
// How it lays the cells out is determined by the layout property:
// Layout can be done by (a) fixing the cell size
// (Grid will create as many rows and columns as will fit)
// Or (b) fixing the number of rows and columns
// (Grid will make the cells as large as possible)
// Or (c) ensuring a certain aspect ratio (width vs. height) for each cell
// (Grid will make cellCount cells fit, making the cells as large as possible)
// (you must set the cellCount var for the aspectRatio layout to know what to do)
//
// The bounding rectangle of a cell in the grid is obtained by subscript (e.g. grid[11] or grid[1,5]).
// The dimensions tuple will contain the number of (calculated or specified) rows and columns.
// Setting aspectRatio, dimensions or cellSize, may change the layout.
//
// To use, simply employ the initializer to choose a layout strategy and set the frame.
// After creating a Grid, you can change the frame or layout strategy at any time
// (all other properties will immediately update).
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
}
}
//
//斯威夫特
//
//由CS193p讲师创建。
//版权所有©2017斯坦福大学。版权所有。
//
//将矩形中的空间排列为单元格网格。
//所有单元格的大小将完全相同。
//如果网格未边对边填充提供的框架
//然后,它将在所提供的框架中使单元格网格居中。
//如果需要网格中单元之间的间距,只需插入每个单元的框架即可。
//
//布局单元的布局方式由布局属性决定:
//布局可以通过(a)固定单元大小来完成
//(网格将创建尽可能多的行和列)
//或(b)固定行数和列数
//(网格将使单元格尽可能大)
//或(c)确保每个单元具有一定的纵横比(宽度与高度)
//(网格将使cellCount单元格匹配,使单元格尽可能大)
//(必须为aspectRatio布局设置cellCount变量才能知道该做什么)
//
//网格中单元的边界矩形通过下标获得(例如网格[11]或网格[1,5])。
//维度元组将包含(计算的或指定的)行数和列数。
//设置aspectRatio、尺寸或单元格大小可能会更改布局。
//
//要使用,只需使用初始值设定项来选择布局策略并设置框架。
//创建网格后,可以随时更改框架或布局策略
//(所有其他属性将立即更新)。
导入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
}否则{
计算的维度=(0,0)
}
updateCellFrames(到:cellSize)
打破
}
}
私有变异func updateCellFrames(到单元格大小:CGSize){
cellFrames.removeAll()
让boundingSize=CGSize(
宽度:CGFloat(dimensions.colu
import UIKit
@IBDesignable
class CardBoardView: UIView {
public lazy var grid = Grid(layout: .aspectRatio(values.ratio), frame: self.bounds)
var cards = [CardSubview]()
public var cells = 12
private var selectedCards = [Int]()
private var deck = gameDeck(numbersOfCards: 81)
private var indexOfCards = 0
let values = Values()
var index1 = 1
var index2 = 1
var index3 = 1
var index4 = 1
struct Values {
public let ratio:CGFloat = 2.0
public let insetByX:CGFloat = 2.0
public let insetByY:CGFloat = 2.0
public let allAvailableCards = 81
}
@objc private func tab (recognizer: UITapGestureRecognizer) {
switch recognizer.state {
case .ended:
if let card = recognizer.view as? CardSubview {
card.isSelected = !card.isSelected
if card.isSelected == true {
selectedCards.append(cards.index(of: card)!)
if selectedCards.count == 3 {
if isSet(indexes: selectedCards) == true {
selectedCards.forEach { index in
cards[index].removeFromSuperview()
cards.remove(at: index)
}
} else {
selectedCards.forEach{ index in
cards[index].isSelected = false
}
selectedCards.removeAll()
}
}
} else if card.isSelected == false {
if selectedCards.contains(cards.index(of: card)!) {
selectedCards.remove(at: selectedCards.index(of: cards.index(of:card)!)!)
}
}
}
default: break
}
}
private func isSet(indexes: [Int]) -> Bool {
return deck.isSet(arrayOfIndexes: indexes)
}
private func nextIndex() {
index1+=1
if index1==4 {
index1=1
index2+=1
if index2==4 {
index2=1
index3+=1
if index3==4 {
index3=1
index4+=1
if index4==4 {
index4=1
}
}
}
}
}
override func layoutSubviews() {
super.layoutSubviews()
grid.cellCount = cells
for index in 0...80 {
cards.append(CardSubview())
cards[index].index1=index1
cards[index].index2=index2
cards[index].index3=index3
cards[index].index4=index4
nextIndex()
}
for index in 0..<grid.cellCount{
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(tab))
cards[indexOfCards].addGestureRecognizer(tapRecognizer)
cards[indexOfCards].frame = grid[index]!.insetBy(dx: values.insetByX, dy: values.insetByY)
addSubview(cards[indexOfCards])
indexOfCards+=1
}
}
}