简体   繁体   English

(Swift) 如何在单元格滑动操作中设置清晰的背景?

[英](Swift) How to set clear background in cell swipe action?

I have a trailingSwipeAction in a UITableViewCell, whose background color must be clear.我在 UITableViewCell 中有一个 trailingSwipeAction,其背景颜色必须清晰。

This is the code where I set the action :这是我设置操作的代码:

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])
}

But I am getting gray background for the action, when no color was expected:但是当没有颜色时,我得到了该动作的灰色背景:

在此处输入图片说明

SOLUTION: https://stackoverflow.com/a/52018193/9451152解决方案: https : //stackoverflow.com/a/52018193/9451152

You can just set the alpha value to 0 for background color of the action Here is the example您可以将动作的背景颜色的 alpha 值设置为 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)

You'll have to access the UIView inside the UIActionStandardButton inside the UISwipeActionPullView .您必须访问UISwipeActionPullView内的UIActionStandardButton内的UISwipeActionPullView and then change its background color.然后改变它的背景颜色。

拉视图层次结构

You can see the view hierarchy of your app swiping on a cell, then going the Debug menu in Xcode, then View Debugging , and choose Capture View Hierarchy .您可以看到在单元格上滑动的应用程序的视图层次结构,然后转到 Xcode 中的Debug菜单,然后是View Debugging ,然后选择Capture View Hierarchy

First of all, let add this useful extension that gets all subviews and their subviews in an array:首先,让我们添加这个有用的扩展来获取数组中的所有子视图及其子视图:

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

And then in viewWillLayoutSubviews() :然后在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
    }
}

I am using viewWillLayoutSubviews() since it's called to notify the view controller that its view is about to layout its subviews.我正在使用viewWillLayoutSubviews()因为它被调用来通知视图控制器它的视图即将布局它的子视图。 Have a look here for more details.看看这里了解更多详情。

This solution is optimized for one swipe action button.此解决方案针对一个滑动操作按钮进行了优化。 If you have more than one button, the code would look like this:如果您有多个按钮,则代码如下所示:

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
        }
    }
}

SOLUTION解决方案

Thanks to Carpsen90感谢Carpsen90

在此处输入图片说明

You have to set the backgroundColor of that UIImageView to .clear, but it doesn't exist in the time of viewWillLayoutSubviews.您必须将该 UIImageView 的 backgroundColor 设置为 .clear,但它在 viewWillLayoutSubviews 时不存在。 It is created after you swipe.它是在您滑动后创建的。

A posible solution is to have a Timer:一个可能的解决方案是有一个计时器:

var timerCellSwipeButtons: Timer?

Launched when the swipe is done:滑动完成后启动:

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])
}

Now every 10 milliseconds (you can increase the frequency if you want), this function checks the tableView subviews looking for all the UISwipeActionStandardButton and setting to .clear the backgroundColor of their UIView:现在每 10 毫秒(如果需要,您可以增加频率),此函数检查 tableView 子视图以查找所有 UISwipeActionStandardButton 并设置为 .clear 其 UIView 的 backgroundColor:

@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()
}

To get all the subviews of a UIView, I used the function given by Carpsen90 :为了获取 UIView 的所有子视图,我使用了Carpsen90给出的函数

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

For safety reasons, you should also invalidate the timer in the viewWillDisappear method:出于安全原因,您还应该使 viewWillDisappear 方法中的计时器无效:

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

And this is the result:这是结果:

在此处输入图片说明

But as you can see, when you have more than one action in the same side of the cell and you swipe completely, doesn't look very nice:但是正如您所看到的,当您在单元格的同一侧有多个操作并完全滑动时,看起来不太好:

在此处输入图片说明

To avoid icons overlapping I put only one action in each side:为了避免图标重叠,我只在每一侧放置一个动作:

// 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?

在此处输入图片说明

Apparently if you set the background color to white with zero alpha, it will stay clear but without the gray default color.显然,如果您将背景颜色设置为白色且 alpha 为零,它将保持清晰但没有灰色默认颜色。

Try this:尝试这个:

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
{
    let deleteAction = UIContextualAction(style: .destructive, title: nil) { [weak self] (action, view, completion) in
        // weak self to prevent memory leak if needed
        guard let self = self else { return }
        
        // do your nasty stuff here 
        
        completion(true)
    }
    
    deleteAction.backgroundColor = UIColor(white: 1, alpha: 0)
    deleteAction.image = UIImage(systemName: "trash")
    
    return UISwipeActionsConfiguration(actions: [deleteAction])
}

在此处输入图片说明

100 % Working in IOS swift for change swipe button image color and background color change. 100% 使用 IOS swift 更改滑动按钮图像颜色和背景颜色更改。

 func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    if isInbox
    {

        let action =  UIContextualAction(style: .normal, title: "", handler: { (action,view,completionHandler ) in
            self.selectedIndex  = indexPath.row
            self.deleteNotification()
            completionHandler(true)

        })
        let cgImageX =  UIImage(named: "delete-1")?.cgImage
        action.image = OriginalImageRender(cgImage: cgImageX!)
        action.backgroundColor = UIColor.init(hex: "F7F7F7")
        let confrigation = UISwipeActionsConfiguration(actions: [action])

        return confrigation
    }
    return nil
}

Add this Class also for original image color display otherwise its showing only white image添加此类也用于原始图像颜色显示,否则仅显示白色图像

   class OriginalImageRender: UIImage {
        override func withRenderingMode(_ renderingMode: UIImage.RenderingMode) -> UIImage {
             return self
     } }

在此处输入图片说明

What I have done in my project is我在我的项目中所做的是

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
        }
    }

And my project's target is iOS 9.0 and above我项目的目标是iOS 9.0及以上

Following the solution from @Maulik Patel I just added a tint color option to the action.image:按照@Maulik Patel 的解决方案,我刚刚在 action.image 中添加了一个色调选项:

let imageDelete = UIImage(systemName: "trash")?.cgImage
        deleteAction.image = OriginalImageRender(cgImage: imageDelete!).withTintColor(UIColor(named: ("colorButton"))!)
        deleteAction.backgroundColor = UIColor.init(red: 0/255.0, green: 0/255.0, blue: 0/255.0, alpha: 0.0)
        
        
        let configuration = UISwipeActionsConfiguration(actions: [deleteAction])
        
        return configuration

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM