有没有一种方法可以在for循环中显示字符而不重复代码?

时间:2020-09-22 21:56:00

标签: swift

我对学习Swift还是很陌生,并且有一个框架可以在其中均匀显示字母。

我有3个for循环,其中字母A-X在4行中显示6列,而Y和Z在2-3列的第5行中显示(因此居中)。但是,要实现这一点,我必须复制代码。有没有更好的方法可以解决此问题,所以我不必重复代码?

let allLetters = (65...90).map { Character(Unicode.Scalar($0)) }
    let width = 80
    let height = 80

    for row in 0..<4 {
        for col in 0..<6 {
            let letterButton = UIButton(type: .system)
                letterButton.titleLabel?.font = UIFont.systemFont(ofSize: 36)
                letterButton.addTarget(self, action: #selector(letterTapped), for: .touchUpInside)
            
            let frame = CGRect(x: col * width, y: row * height, width: width, height: height)
            letterButton.frame = frame
            
            buttonsView.addSubview(letterButton)
            letterButtons.append(letterButton)
        }
    }
   
        for col in 2..<4 {
            let letterButton = UIButton(type: .system)
                letterButton.titleLabel?.font = UIFont.systemFont(ofSize: 36)
                letterButton.addTarget(self, action: #selector(letterTapped), for: .touchUpInside)
           
            let frame = CGRect(x: col * width, y: 4 * height, width: width, height: height)
            letterButton.frame = frame
        
            buttonsView.addSubview(letterButton)
            letterButtons.append(letterButton)
    }
            
    for (index, button) in letterButtons.enumerated() {
        button.setTitle(String(allLetters[index]), for: .normal)
    }
}

2 个答案:

答案 0 :(得分:0)

您可以简化和提高性能,删除两个for循环,如下所示:

let allLetters = (65...90).map { Character(Unicode.Scalar($0)) }
let width = 80
let height = 80

var letterIndex = 0
let lastRowIndex = 4
let defaultRowColumnRange = 0..<6
let lastRowColumnRange = 2..<4

for row in 0...lastRowIndex {
    let rangeForRow = row == lastRowIndex ? lastRowColumnRange : defaultRowColumnRange
    for col in rangeForRow {
        let letterButton = UIButton(type: .system)
        letterButton.titleLabel?.font = UIFont.systemFont(ofSize: 36)
        letterButton.addTarget(self, action: #selector(letterTapped), for: .touchUpInside)

        if allLetters.count > letterIndex {
            letterButton.setTitle(String(allLetters[letterIndex]), for: .normal)
            letterIndex += 1
        }
        
        let frame = CGRect(x: col * width, y: row * height, width: width, height: height)
        letterButton.frame = frame
        
        view.addSubview(letterButton)
        letterButtons.append(letterButton) // Might not be necessary anymore
    }
}

答案 1 :(得分:0)

首先,我仍将所有按钮操作移至其自身的功能中:

func addButton(letter: Character, x: Int, y: Int) {

    let letterButton = UIButton(type: .system)
    letterButton.setTitle(String(letter), for: .normal)
    letterButton.titleLabel?.font = UIFont.systemFont(ofSize: 36)
    letterButton.addTarget(self, action: #selector(letterTapped), for: .touchUpInside)
        
    let frame = CGRect(x: x, y: y, width: width, height: height)
    letterButton.frame = frame
        
    buttonsView.addSubview(letterButton)
    letterButtons.append(letterButton)
}

因为这为所有ui操作提供了很好的隔离。即使使用此功能替换了重复的代码,您也得到了改善。

但也要假设

let numberOfLettersPerRow = 6

您知道每行有多少个按钮:

let buttonsInCurrentRow = min(numberOfLettersPerRow, allLetters.count - row * numberOfLettersPerRow) // i.e. 6 or less

因此,您可以决定按钮是背靠背还是在按钮前后都有空白:

let gap = (numberOfLettersPerRow - buttonsInCurrentRow) * width / 2

对于numberOfLettersPerRow == buttonsInCurrentRow行,该间隙将为0,而对于numberOfLettersPerRow < buttonsInCurrentRow行,该间隙将大于0,我们希望该间隙为总间隙的一半(因此,前面有相等的空间并返回)

所以现在您将按钮放置如下:

let frame = CGRect(x: gap + col * width, y: row * height, width: width, height: height)

然后在您拥有的按钮上而不是在行和列上运行循环。为什么?因为如果明天您改变主意如何放置按钮,则无需更改很多代码:

for i in 0...allLetters.count - 1 {

    let row = Int(i / numberOfLettersPerRow)
    let col = i % numberOfLettersPerRow
    let buttonsInCurrentRow = min(numberOfLettersPerRow, allLetters.count - row * numberOfLettersPerRow)
    let gap = (numberOfLettersPerRow - buttonsInCurrentRow) * width / 2
    addButton(letter: allLetters[i], x: gap + col * width, y: row * height)
}

就是这样。