Can a standard accessory view be in a different position within a UITableViewCell?

前端 未结 11 1039
谎友^
谎友^ 2020-12-05 09:57

I want my accessory to be in a slightly different place than normal. Is it possible? This code has no effect:

cell.accessoryType =  UITableViewCellAccessoryD         


        
相关标签:
11条回答
  • 2020-12-05 10:25

    I was working with the ios5 and the solution given by Alexey was not working entirely. I discovered that when an accessoryType is set on a table, the accessoryView is null so the first "if" was not working. I have changed a the code just a little:

    if (self.accessoryType != UITableViewCellAccessoryNone) {
        UIView* defaultAccessoryView = nil;
    
        for (UIView* subview in self.subviews) {
            if (subview != self.textLabel && 
                subview != self.detailTextLabel && 
                subview != self.backgroundView && 
                subview != self.contentView &&
                subview != self.selectedBackgroundView &&
                subview != self.imageView &&
                subview != self.explanationButton && // Own button
                subview.frame.origin.x > 0 // Assumption: the checkmark will always have an x position over 0. 
                ) {
                defaultAccessoryView = subview;
                break;
            }
        }
        r = defaultAccessoryView.frame;
        r.origin.x -= 8;
        defaultAccessoryView.frame = r;
    
    }
    

    and this solution is working for me. As Alexey said, I don't know what is going to happen with future versions but at least in ios 4 is working.

    0 讨论(0)
  • 2020-12-05 10:27

    Following the solution given by Ana I tried to better detect the accessory view, I look on the right side of the cell.

    Create a custom class that extends UITableViewCell and add this method:

    - (void)layoutSubviews {
        [super layoutSubviews];
    
        if (self.accessoryType != UITableViewCellAccessoryNone) {
            float estimatedAccesoryX = MAX(self.textLabel.frame.origin.x + self.textLabel.frame.size.width, self.detailTextLabel.frame.origin.x + self.detailTextLabel.frame.size.width);
    
            for (UIView *subview in self.subviews) {
                if (subview != self.textLabel &&
                    subview != self.detailTextLabel &&
                    subview != self.backgroundView &&
                    subview != self.contentView &&
                    subview != self.selectedBackgroundView &&
                    subview != self.imageView &&
                    subview.frame.origin.x > estimatedAccesoryX) {
    
                    // This subview should be the accessory view, change its frame
                    frame = subview.frame;
                    frame.origin.x -= 10;
                    subview.frame = frame;
                    break;
                }
            }
        } 
    }
    
    0 讨论(0)
  • 2020-12-05 10:28

    The above answers didn't work for me under ios 6.1. So I tried to use UIEdgeInsets, because the DetailDisclosure is a UIButton. And it works fine now. Here the source:

    if (cell.accessoryType == UITableViewCellAccessoryDetailDisclosureButton) {
        UIView* defaultAccessoryView = [cell.subviews lastObject];
        if ([defaultAccessoryView isKindOfClass:[UIButton class]]){
            UIButton *bt = (UIButton*)defaultAccessoryView;            
            bt.contentEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 10);
        }
    }
    
    0 讨论(0)
  • 2020-12-05 10:38

    Maybe this will be sufficient for you:

    UIImageView* accessoryImageView = [[UIImageView alloc] initWithFrame:
            CGRectMake(0, 0, accessoryImage.size.width + MARGIN_RIGHT, accessoryImage.size.height)];
    accessoryImageView.contentMode = UIViewContentModeLeft;
    accessoryImageView.image = accessoryImage;
    
    self.accessoryView = accessoryImageView;
    

    This way I added padding to the right, so accessory button looks shifted to the left. It has a wider area that responds to touches, that is the only side-effect.

    0 讨论(0)
  • 2020-12-05 10:38

    improvements on other answers

    For James Kuang, Kappe, accessoryView is nil for default accessory view.

    For Matjan, subviews.lastObject is easily the wrong view, like an UITableViewCellSeparatorView.

    For Alexey, Ana, Tomasz, enumerating the subviews until we find an unknown one works for now. But it's laborious and could be easily broken in future versions if, let say, Apple adds a backgroundAccessoryView.

    For larshaeuser, enumerating the subviews until we find a UIButton is good idea, but contentEdgeInsets is not adequately visibly changing the accessory view.

    solution for Swift 3.x and 4.0

    We will enumerate and look for the last UIButton.

    class AccessoryTableViewCell: UITableViewCell {
        override func layoutSubviews() {
            super.layoutSubviews()
            if let lastButton = subviews.reversed().lazy.flatMap({ $0 as? UIButton }).first {
                // This subview should be the accessory view, change its origin
                lastButton.frame.origin.x = bounds.size.width - lastButton.frame.size.width - 5
            }
        }
    }
    

    for Swift 4.1 and newer

    class AccessoryTableViewCell: UITableViewCell {
        override func layoutSubviews() {
            super.layoutSubviews()
            // https://stackoverflow.com/a/45625959/1033581
            if let lastButton = subviews.reversed().lazy.compactMap({ $0 as? UIButton }).first {
                // This subview should be the accessory view, change its origin
                lastButton.frame.origin.x = bounds.size.width - lastButton.frame.size.width - 5
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题