更改Swift中相邻按钮的背景色

更改Swift中相邻按钮的背景色,swift,uibutton,uistackview,Swift,Uibutton,Uistackview,当按下任何按钮时,我想更改视图中所有相邻按钮的颜色。最后,我将把它变成一个动画-几乎像一个涟漪效应 我查看了Combine框架,但它似乎有太多与我需要的功能无关的功能。因为用户可以按下任何按钮,我不认为为每个按钮创建一个观察者是一个经济的解决方案。我希望有一种方法可以找到按钮属性的相邻视图,并以某种方式影响它 这个问题有没有一个简单的解决方案,或者我需要构建一个复杂的IF语句矩阵,这是我在任何情况下都准备要做的 所有“我的按钮”都在UIStack视图中(1 x垂直堆栈视图中有8个水平堆栈视图)

当按下任何按钮时,我想更改视图中所有相邻按钮的颜色。最后,我将把它变成一个动画-几乎像一个涟漪效应

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

这个问题有没有一个简单的解决方案,或者我需要构建一个复杂的IF语句矩阵,这是我在任何情况下都准备要做的

所有“我的按钮”都在UIStack视图中(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
}...
通过搜索二维数组,可以找到“相邻”按钮

例如。。。如果您有一个8x8“网格”的按钮,您将有8行8列。点击任何按钮时,搜索各行以查找点击按钮的行和列

假设您在
第4行:第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
连接):

类ViewController:UIViewController{
//用于跟踪按钮的二维阵列
//我们可以使用堆栈视图及其排列的子视图,但是
//这将避免重复展开选项
变量arrayOfButtons:[[UIButton]]=[]
//在网格上方添加重置按钮
让resetBtn=ui按钮()
//添加分段控件以选择完全相邻或对角
设segCtrl=UISegmentedControl(项:[“仅限完整”、“包括对角线”])
重写func viewDidLoad(){
super.viewDidLoad()
//创建一个8x8“网格”按钮
让outerStack=UIStackView()
outerStack.axis=.vertical
outerStack.distribution=.fills
//我们将使用Row:Col作为按钮标签
对于0..Void中的行{
guard let tappedBtn=发送器为?uI按钮其他{
返回
}
//找到点击按钮的行和列
变量行:Int=-1
变量列:Int=-1
对于0..0中的r{
//按上面的按钮
append(arrayOfButtons[row-1][col])
}
如果col>0{
//按左边的按钮
append(arrayOfButtons[row][col-1])
}
如果行0{
//按左上方的按钮
如果col>0{
append(arrayOfButtons[row-1][col-1])
}
//按上面的按钮
append(arrayOfButtons[row-1][col])
//按上面和右边的按钮
如果列0{
//按左边的按钮
append(arrayOfButtons[row][col-1])
}
如果列0{
append(arrayOfButtons[row+1][col-1])
}
//点击下面的按钮
append(arrayOfButtons[row+1][col])
//按下面和右边的按钮
如果列
您是如何定义“相邻”的?换句话说,为什么tag#1会导致1、2、3,而tag#2是4,5,6?公式是什么?在UIStackView中相邻,对不起,我会让它更清楚一点。你知道它们的顺序吗,或者你必须通过比较坐标来确定相邻吗?简短的答案,只是因为我在IB中如何排列它们。我想这是我问题的关键,如何确定哪些按钮与用户按下的按钮相邻。好吧,我已经删除了我的答案,因为它似乎不相关。看起来明智的做法是以逻辑的方式分配它们,这样您就可以知道哪些是相邻的,除非您以后以编程方式移动它们。
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
        }

    }
    
}