UITableViewRowAction image for title

后端 未结 8 1790
情歌与酒
情歌与酒 2020-12-02 15:44

I made a custom UITableViewRowAction. Now I\'d like to add an image instead of the text. I know that it\'s possible but don\'t know how to do it. Does someone of you knows

相关标签:
8条回答
  • 2020-12-02 16:04

    Swift 4 (iOS 11+):

    iOS 11 now supports images (only) to display in action buttons. You simply have to initialize a UISwipeActionsConfiguration object in your table view delegate object:

    extension MyTableViewController:UITableViewDelegate {
    
        func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    
            let deleteAction = UIContextualAction(style: .normal, title:  nil, handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
    
                    debugPrint("Delete tapped")
    
                    success(true)
                })
    
            deleteAction.image = UIImage(named: "icon_delete.png")
            deleteAction.backgroundColor = UIColor.red
    
            return UISwipeActionsConfiguration(actions: [deleteAction])
        }
    

    }

    0 讨论(0)
  • 2020-12-02 16:06

    I just implement better version of https://stackoverflow.com/a/48122210 1. In majority of cases height of cell and width of custom swipe part are different, you have to calculate this in your function 2. Image can have different size than square, so you have to calculate proportions not just for height. So, code with my fixes

    func setIcon(iconImage: UIImage, backColor: UIColor, cellHeight: CGFloat, customSwipPartWidth: CGFloat, iconSizePercentage: CGFloat) {
            let iconWidth = customSwipPartWidth * iconSizePercentage
            let iconHeight = iconImage.size.height / iconImage.size.width * iconWidth
            let marginY = (cellHeight - iconHeight) / 2 as CGFloat
            let marginX = (customSwipPartWidth - iconWidth) / 2 as CGFloat
    
    
            UIGraphicsBeginImageContextWithOptions(CGSize(width: customSwipPartWidth, height: cellHeight), false, 0)
            let context = UIGraphicsGetCurrentContext()
    
            backColor.setFill()
            context!.fill(CGRect(x:0, y:0, width:customSwipPartWidth, height:cellHeight))
    
            iconImage.draw(in: CGRect(x: marginX, y: marginY, width: iconWidth, height: iconHeight))
    
            let actionImage = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
    
            self.backgroundColor = UIColor.init(patternImage: actionImage!)
        } 
    
    0 讨论(0)
  • 2020-12-02 16:11

    iOS 11.0

    Swift

    Apple introduced flexible way to declare row actions with great benefits.

    extension ViewController: UITableViewDelegate {
      func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let askAction = UIContextualAction(style: .normal, title: nil) { action, view, complete in
          print("Ask!")
          complete(true)
        }
    
        // here set your image and background color
        askAction.image = IMAGE
        askAction.backgroundColor = .darkGray
    
        let blockAction = UIContextualAction(style: .destructive, title: "Block") { action, view, complete in
          print("Block")
          complete(true)
        }
    
        return UISwipeActionsConfiguration(actions: [blockAction, askAction])
      }
    
      func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        cell.textLabel?.text = "row: \(indexPath.row)"
      }
    }
    

    Example:

    iOS 8.0

    You need to set UIImage to backgroundColor of row action, concretely by:

    Swift:

    UIColor(patternImage: UIImage(named: "IMAGE_NAME"))
    

    Objective-C:

    [UIColor colorWithPatternImage:[UIImage imageNamed:@"IMAGE_NAME"]];
    
    0 讨论(0)
  • 2020-12-02 16:13

    My variation tries to use UImageView's contentMode behavior and when that was not enough, I found some good use for a couple of the Core Geometry Rect methods because they keep the target frame centered within the cell frame. Using an eye test, It appears that swiping was removing half of my normal cell width so that's where the magic numbers show up.

    Swift 3.0

    extension UITableViewRowAction {
    
        func setIcon(iconImage: UIImage, backColor: UIColor, cellHeight: CGFloat, cellWidth:CGFloat) ///, iconSizePercentage: CGFloat)
        {
            let cellFrame = CGRect(origin: .zero, size: CGSize(width: cellWidth*0.5, height: cellHeight))
            let imageFrame = CGRect(x:0, y:0,width:iconImage.size.width, height: iconImage.size.height)
            let insetFrame = cellFrame.insetBy(dx: ((cellFrame.size.width - imageFrame.size.width) / 2), dy: ((cellFrame.size.height - imageFrame.size.height) / 2))
            let targetFrame = insetFrame.offsetBy(dx: -(insetFrame.width / 2.0), dy: 0.0)
            let imageView = UIImageView(frame: imageFrame)
            imageView.image = iconImage
            imageView.contentMode = .left
            guard let resizedImage = imageView.image else { return }
            UIGraphicsBeginImageContextWithOptions(CGSize(width: cellWidth, height: cellHeight), false, 0)
            guard let context = UIGraphicsGetCurrentContext() else { return }
            backColor.setFill()
            context.fill(CGRect(x:0, y:0, width:cellWidth, height:cellHeight))
            resizedImage.draw(in: CGRect(x:(targetFrame.origin.x / 2), y: targetFrame.origin.y, width:targetFrame.width, height:targetFrame.height))
            guard let actionImage = UIGraphicsGetImageFromCurrentImageContext() else { return }
            UIGraphicsEndImageContext()
            self.backgroundColor = UIColor.init(patternImage: actionImage)
        }
    }
    

    Usage: from the editActions... method of the tableview delegate.

    let cellHeight = (self.tableView(tableView, cellForRowAt: indexPath)).frame.size.height
    let cellWidth = (self.tableView(tableView, cellForRowAt: indexPath)).frame.size.width
    let favorite = UITableViewRowAction(style: .normal, title: nil) { action, index in
                    //perform action
                    debugPrint("Test")
    
                }
    favorite.setIcon(iconImage: #imageLiteral(resourceName: "favorite"), backColor: .green, cellHeight: cellHeight, cellWidth:cellWidth)
    
    0 讨论(0)
  • 2020-12-02 16:18

    The problem with the basic pattern-color approach is that your image need to be of the same size than the action button, or at least to have some more flat background at the bottom to prevent the image repetition (even though it will be anchored on top, which is not really nice).

    I had to deal with dynamic-height cells so I implemented the following:

    - (UIColor *)backgroundImageForActionAtIndexPath:(NSIndexPath *)indexPath withImage:(UIImage *)image tintColor:(UIColor *)tintColor backgroundColor:(UIColor *)backgrounfColor expectedWith:(CGFloat)width {
    //
    CGRect cellFrame = [self.tableView rectForRowAtIndexPath:indexPath];
    CGSize expectedSize = CGSizeMake(width, cellFrame.size.height);
    
    UIGraphicsBeginImageContextWithOptions(expectedSize, NO, 0.0);
    
    CGContextRef ctx = UIGraphicsGetCurrentContext ();
    if (ctx) {
        // set the background
        CGContextSetFillColorWithColor(ctx, backgrounfColor.CGColor);
        CGRect fillRect = CGRectZero;
        fillRect.size = expectedSize;
        CGContextFillRect(ctx, fillRect);
        // put the image
        CGContextSetFillColorWithColor(ctx, tintColor.CGColor);
        CGRect rect = CGRectMake((expectedSize.width - image.size.width) / 2., (expectedSize.height - image.size.height) / 2., image.size.width, image.size.height);
        [image drawInRect:rect];
    }
    
    UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return [UIColor colorWithPatternImage:newImage];
    

    }

    You still have to set the expectedWidth so it matches the empty label you put in the action's title. e.g: @" " -> 64.f

    As you see with this approach you can set the button's background and tint color in code and not in the artwork itself.

    0 讨论(0)
  • 2020-12-02 16:19

    I made this simple UITableViewRowAction category, in order to set the icon for my actions. You can set the image, the background color, the cell height (to manage dynamic cells) and the icon size in percentage.

    extension UITableViewRowAction {
    
      func setIcon(iconImage: UIImage, backColor: UIColor, cellHeight: CGFloat, iconSizePercentage: CGFloat)
      {
        let iconHeight = cellHeight * iconSizePercentage
        let margin = (cellHeight - iconHeight) / 2 as CGFloat
    
        UIGraphicsBeginImageContextWithOptions(CGSize(width: cellHeight, height: cellHeight), false, 0)
        let context = UIGraphicsGetCurrentContext()
    
        backColor.setFill()
        context!.fill(CGRect(x:0, y:0, width:cellHeight, height:cellHeight))
    
        iconImage.draw(in: CGRect(x: margin, y: margin, width: iconHeight, height: iconHeight))
    
        let actionImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        self.backgroundColor = UIColor.init(patternImage: actionImage!)
      }
    }
    
    0 讨论(0)
提交回复
热议问题