У меня есть trailingSwipeAction в UITableViewCell, чей цвет фона должен быть прозрачным.

Это код, где я установил действие:

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let myAction = UIContextualAction.init(style: .normal, title: nil) {
        // My action code
    }
    myAction.backgroundColor = .clear
    myAction.image = UIImage.init(named: "my-icon")
    return UISwipeActionsConfiguration.init(actions: [myAction])
}

Но я получаю серый фон для действия, когда цвет не ожидался:

enter image description here

РЕШЕНИЕ: https://stackoverflow.com/a/52018193/9451152

6
Sergio 20 Авг 2018 в 22:51

4 ответа

Лучший ответ

Вы можете просто установить альфа-значение в 0 для цвета фона действия. Вот пример

let modifyAction = UIContextualAction(style: .normal, title:  "", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
        print("Update action ...")
        success(true)
    })
    modifyAction.backgroundColor = UIColor.init(red: 0/255.0, green: 0/255.0, blue: 0/255.0, alpha: 0.0)
10
Shubham Goel 18 Мар 2019 в 07:42

Что я сделал в своем проекте

func tableView(_ tableView: UITableView, willBeginEditingRowAt indexPath: IndexPath) {

        let subViews = tableView.subviews.filter { (view) -> Bool in
            if NSStringFromClass(view.classForCoder) == "UISwipeActionPullView" {
                return true
            }
            return false
        }
        if subViews.count > 0 {
            let bgView = subViews[0]
            bgView.backgroundColor = bgColor
        }
    }

И цель моего проекта - iOS 9.0 и выше

0
Smit Shah 14 Июн 2019 в 13:03

Вам нужно будет получить доступ к UIView внутри UIActionStandardButton внутри UISwipeActionPullView. а затем измените его цвет фона.

pull view hierarchy

Вы можете видеть иерархию представления вашего приложения, проводя по ячейке, затем перейдя в меню Debug в XCode, затем View Debugging и выберите Capture View Hierarchy.

Прежде всего, давайте добавим это полезное расширение, которое получает все подпредставления и их подпредставления в массиве:

extension UIView {
    var allSubViews : [UIView] {
        var array = [self.subviews].flatMap {$0}
        array.forEach { array.append(contentsOf: $0.allSubViews) }
        return array
    }
}

И затем в viewWillLayoutSubviews():

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    let btn = tableView
              .allSubViews //get all the subviews
              .first(where: {String(describing:type(of: $0)) ==  "UISwipeActionStandardButton"}) // get the first one that is a UISwipeActionStandardButton

    //This UISwipeActionStandardButton has two subviews, I'm getting the one that is not a UILabel, in your case, since you've set the image,  you should get the one that is not an imageView
    if let view = btn?.subviews.first(where: { !($0 is UILabel)})
    {
        view.backgroundColor = .clear //Change the background color of the gray uiview
    }
}

Я использую viewWillLayoutSubviews(), поскольку он вызывается, чтобы уведомить контроллер представления о том, что его представление собирается макетировать свои подпредставления. Посмотрите здесь для получения дополнительной информации.

Это решение оптимизировано для одной кнопки действия смахивания. Если у вас более одной кнопки, код будет выглядеть так:

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    let buttons = tableView
        .allSubViews //get all the subviews
        .filter {String(describing:type(of: $0)) ==  "UISwipeActionStandardButton"}

    buttons.forEach { btn in
        if let view = btn.subviews.first(where: { !($0 is UIImageView)}) //If you're sure that other than the uiview there is a UIImageView in the subviews of the UISwipeActionStandardButton
        {
            view.backgroundColor = .clear //Change the background color of the gray uiview
        }
    }
}
4
ielyamani 25 Авг 2018 в 12:50

РЕШЕНИЕ

Благодаря Carpsen90

enter image description here

Вы должны установить цвет фона этого UIImageView в .clear, но он не существует во время viewWillLayoutSubviews. Он создается после того, как вы проводите.

Возможное решение состоит в том, чтобы иметь Таймер:

var timerCellSwipeButtons: Timer?

Запускается, когда выполняется свайп:

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let editAction = UIContextualAction.init(style: .normal, title: nil) { [weak self] (action, view, completion) in
        // editAction code
    }
    let deleteAction = UIContextualAction.init(style: .normal, title: nil) { [weak self] (action, view, completion) in
        // deleteAction code
    }
    // Set the button's images
    editAction.image = UIImage.init(named: "editIcon")
    deleteAction.image = UIImage.init(named: "deleteIcon")
    // You also must set the background color of the actions to .clear
    editAction.backgroundColor = .clear
    deleteAction.backgroundColor = .clear
    // Launch the timer, that will run a function every 10 milliseconds
    self.timerCellSwipeButtons = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(timerCellSwipeButtonsFunction), userInfo: nil, repeats: true)
    // Return the actions
    return UISwipeActionsConfiguration.init(actions: [deleteAction, editAction])
}

Теперь каждые 10 миллисекунд (вы можете увеличить частоту, если хотите), эта функция проверяет подпредставления tableView, ища все UISwipeActionStandardButton и устанавливая для .clear backgroundColor их UIView:

@objc func timerCellSwipeButtonsFunction() {
    // Gets all the buttons, maybe we have more than one in a row
    let buttons = tableView.allSubViews.filter { (view) -> Bool in
        String(describing: type(of: view)) == "UISwipeActionStandardButton"
    }
    // Loops through all the buttons
    for button in buttons {
        if let view = button.subviews.first(where: { !($0 is UIImageView)})
        {
            // We are interested in the UIView that isn't a UIImageView
            view.backgroundColor = .clear
        }
    }
    // When finish, timer is invalidated because we don't need it anymore.
    // A new one will be launched with every swipe
    self.timerCellSwipeButtons?.invalidate()
}

Чтобы получить все подпредставления UIView, я использовал функцию, указанную Carpsen90 :

extension UIView {
    var allSubViews : [UIView] {
        var array = [self.subviews].flatMap {$0}
        array.forEach { array.append(contentsOf: $0.allSubViews) }
        return array
    }
}

Из соображений безопасности следует также сделать недействительным таймер в методе viewWillDisappear:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    self.timerCellSwipeButtons?.invalidate()
}

И вот результат:

enter image description here

Но, как вы можете видеть, когда у вас есть несколько действий в одной и той же стороне ячейки, и вы проводите полностью, выглядит не очень хорошо:

enter image description here

Чтобы избежать наложения значков, я поместил только одно действие с каждой стороны:

// Remember to launch the timer in both swipe functions, like in the example above

// Function to add actions to the leading side of the cell
tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
// Function to add actions to the trailing side of the cell
tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?

enter image description here

2
Sergio 25 Авг 2018 в 14:22
51937648