【问题标题】:Change background color of adjacent buttons in Swift更改 Swift 中相邻按钮的背景颜色
【发布时间】:2021-04-22 17:10:11
【问题描述】:

我想在按下 any 按钮时更改我的 UIStackView 中所有 相邻 按钮的颜色。最后我会把它变成一个动画 - 几乎就像一个涟漪效应。

我查看了 Combine Framework,但它似乎有太多不相关的功能,无法满足我的需求。因为用户可以按下任何按钮,我不认为为每个按钮创建一个观察者是一个经济的解决方案。我希望有一种方法可以找到按钮属性的相邻视图并以某种方式影响它?

这个问题有简单的解决方案吗,还是我需要构建一个复杂的IF语句矩阵,这是我无论如何都准备做的。

我所有的按钮都在一个 UIStackView 中(1 x 垂直堆栈视图中有 8 个水平堆栈视图)

下面是我的非理想解决方案:

if sender.tag == 1 then {
    view1.layer.backgroundColor = blue
    view2.layer.backgroundColor = blue
    view3.layer.backgroundColor = blue
} else if sender.tag == 2 then {
    view4.layer.backgroundColor = blue
    view5.layer.backgroundColor = blue
    view6.layer.backgroundColor = blue
}...

【问题讨论】:

  • 你如何在这里定义“相邻”?换句话说,为什么标签 #1 的结果是 1、2、3,而标签 #2 是 4、5、6?公式是什么?
  • 在 UIStackView 中相邻,对不起,我会更清楚一点。
  • 知道它们的顺序是什么,或者你必须通过比较坐标来确定邻接吗?
  • 简短的回答,只是因为我在 IB 中如何安排它们。我想这是我问题的症结所在,我如何确定哪些按钮与用户按下的按钮相邻。
  • 好的——我已经删除了我的答案,因为它似乎不相关。谨慎的做法似乎是以合乎逻辑的方式分配它们,以便您知道哪些是相邻的,除非您稍后以编程方式移动它们。

标签: swift uibutton uistackview


【解决方案1】:

您可以通过搜索二维数组找到“相邻”按钮。

例如...如果您有一个 8x8 的“网格”按钮,那么您将拥有 8 个“列”的 8 个“行”。当您点击任何按钮时,搜索行以找到被点击按钮的行和列。

假设你在Row 4 : Col 4找到它,然后找到相邻的按钮在每个方向上减去并添加一行和一列:

// arrays are Zero based
// if tapped button is at 
array[3][3]
// the button above it is at
array[3 - 1][3]
// the button to the left it is at
array[3][3 - 1]
// the button to the right it is at
array[3][3 + 1]
// the button below it is at
array[3 + 1][3]

如果通过相邻您还想包括对角线,您只需要另一组“+/-”用于“上方和左侧”/“上方和右侧”/“下方和左侧”/“下方和右侧”:

这是一个完整的示例(仅代码...没有 @IBOutlet@IBAction 连接):

class ViewController: UIViewController {

    // 2-D array to track the buttons
    //  we could use the stack views and their arrangedSubviews, but
    //  this will avoid repeated unwrapping of optionals
    
    var arrayOfButtons: [[UIButton]] = []
    
    // add a reset button above the grid
    let resetBtn = UIButton()

    // add a segmented control to select fully adjacent or diagonal
    let segCtrl = UISegmentedControl(items: ["Full Only", "Include Diagonal"])

    override func viewDidLoad() {
        super.viewDidLoad()

        // create an 8x8 "grid" of buttons
        
        let outerStack = UIStackView()
        outerStack.axis = .vertical
        outerStack.distribution = .fillEqually

        // we'll use Row:Col for the button labels
        for row in 0..<8 {
            var thisRow: [UIButton] = []
            let rowStack = UIStackView()
            rowStack.distribution = .fillEqually
            for col in 0..<8 {
                let b = UIButton()
                b.backgroundColor = .blue
                b.setTitle("\(row):\(col)", for: [])
                b.setTitleColor(.white, for: .normal)
                b.setTitleColor(.gray, for: .highlighted)
                // add a border so we can see the frames
                b.layer.borderWidth = 1.0
                b.layer.borderColor = UIColor.yellow.cgColor
                // square buttons
                b.heightAnchor.constraint(equalTo: b.widthAnchor).isActive = true
                // add button to rowStack
                rowStack.addArrangedSubview(b)
                // add button to 2-D array
                thisRow.append(b)
                // add target for button
                b.addTarget(self, action: #selector(btnTapped(_:)), for: .touchUpInside)
            }
            // add rowStack to outerStack
            outerStack.addArrangedSubview(rowStack)
            // add this row of buttons to 2-D array
            arrayOfButtons.append(thisRow)
        }

        // outerStack properties
        outerStack.translatesAutoresizingMaskIntoConstraints = false
        
        view.addSubview(outerStack)
        
        // respect safe area
        let g = view.safeAreaLayoutGuide
        
        NSLayoutConstraint.activate([
            
            // constrain outerStack width
            outerStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 16.0),
            outerStack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -16.0),
            
            // center vertically
            outerStack.centerYAnchor.constraint(equalTo: g.centerYAnchor),

        ])
        
        resetBtn.backgroundColor = .systemTeal
        resetBtn.setTitle("Reset", for: [])
        resetBtn.setTitleColor(.white, for: .normal)
        resetBtn.setTitleColor(.gray, for: .highlighted)
        resetBtn.addTarget(self, action: #selector(resetTapped(_:)), for: .touchUpInside)
        
        [resetBtn, segCtrl].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview($0)
        }
        
        NSLayoutConstraint.activate([
            
            resetBtn.bottomAnchor.constraint(equalTo: outerStack.topAnchor, constant: -20.0),
            resetBtn.leadingAnchor.constraint(equalTo: outerStack.leadingAnchor),
            resetBtn.trailingAnchor.constraint(equalTo: outerStack.trailingAnchor),
            
            segCtrl.topAnchor.constraint(equalTo: outerStack.bottomAnchor, constant: 20.0),
            segCtrl.leadingAnchor.constraint(equalTo: outerStack.leadingAnchor),
            segCtrl.trailingAnchor.constraint(equalTo: outerStack.trailingAnchor),

        ])

        segCtrl.selectedSegmentIndex = 0
    }
    
    @objc func resetTapped(_ sender: Any?) -> Void {
        arrayOfButtons.forEach { thisRow in
            thisRow.forEach { btn in
                btn.backgroundColor = .blue
            }
        }
    }

    @objc func btnTapped(_ sender: Any?) -> Void {
        guard let tappedBtn = sender as? UIButton else {
            return
        }
        
        // find the row and column for the tapped button
        var row: Int = -1
        var col: Int = -1
        
        for r in 0..<arrayOfButtons.count {
            let thisRow = arrayOfButtons[r]
            if let c = thisRow.firstIndex(of: tappedBtn) {
                // found the tapped button
                row = r
                col = c
                break
            }
        }
        
        if row == -1 || col == -1 {
            // did not find the tapped button in the grid!!!
            return
        }
        
        // we found the row:col of the tapped button
        var adjacentButtons: [UIButton] = [
            tappedBtn
        ]
        
        if segCtrl.selectedSegmentIndex == 0 {
            
            // adjacent means ONLY above, left, right, below
            if row > 0 {
                // get button above
                adjacentButtons.append(arrayOfButtons[row - 1][col])
            }
            if col > 0 {
                // get button to the left
                adjacentButtons.append(arrayOfButtons[row][col - 1])
            }
            if row < arrayOfButtons.count - 1 {
                // get button below
                adjacentButtons.append(arrayOfButtons[row + 1][col])
            }
            if col < arrayOfButtons[row].count - 1 {
                // get button to the right
                adjacentButtons.append(arrayOfButtons[row][col + 1])
            }
            
        } else {

            // adjacent includes diagonals
            if row > 0 {
                
                // get button above and to the left
                if col > 0 {
                    adjacentButtons.append(arrayOfButtons[row - 1][col - 1])
                }
                
                // get button above
                adjacentButtons.append(arrayOfButtons[row - 1][col])
                
                // get button above and to the right
                if col < arrayOfButtons[row].count - 1 {
                    adjacentButtons.append(arrayOfButtons[row - 1][col + 1])
                }
                
            }
            
            if col > 0 {
                // get button to the left
                adjacentButtons.append(arrayOfButtons[row][col - 1])
            }
        
            if col < arrayOfButtons[row].count - 1 {
                // get button to the right
                adjacentButtons.append(arrayOfButtons[row][col + 1])
            }
            
            if row < arrayOfButtons.count - 1 {
                
                // get button below and to the left
                if col > 0 {
                    adjacentButtons.append(arrayOfButtons[row + 1][col - 1])
                }
                
                // get button below
                adjacentButtons.append(arrayOfButtons[row + 1][col])
                
                // get button below and to the right
                if col < arrayOfButtons[row].count - 1 {
                    adjacentButtons.append(arrayOfButtons[row + 1][col + 1])
                }
                
            }
    
        }
        
        adjacentButtons.forEach { btn in
            btn.backgroundColor = .red
        }

    }
    
}

【讨论】:

    猜你喜欢
    • 2015-06-04
    • 1970-01-01
    • 2021-06-22
    • 2015-04-03
    • 2014-08-17
    • 2011-06-26
    相关资源
    最近更新 更多