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

无人久伴 提交于 2019-11-26 20:07:59

问题


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

cell.accessoryType =  UITableViewCellAccessoryDisclosureIndicator;
cell.accessoryView.frame = CGRectMake(5.0, 5.0, 5.0, 5.0);

回答1:


No, you cannot move where the accessory view is. As an alternative you can add a subview like the following;

[cell.contentView addSubview:aView];

Also, by setting the accessoryView property equal to something, the accessoryType value is ignored.




回答2:


There is a way to move default accessoryView, but it's pretty hacky. So it might stop working one day when a new SDK arrives.

Use at your own risk (this code snippet moves any accessoryView 8 pixels to the left. Call [self positionAccessoryView]; from inside the -(void)layoutSubviews method of the desired UITableViewCell subclass):

- (void)layoutSubviews {
    [super layoutSubviews];
    [self positionAccessoryView];
}

- (void)positionAccessoryView {
    UIView *accessory = nil;
    if (self.accessoryView) {
        accessory = self.accessoryView;
    } else if (self.accessoryType != UITableViewCellAccessoryNone) {
        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 isKindOfClass:[UIButton class]]) {
                accessory = subview;
                break;
            }
        }
    }

    CGRect r = accessory.frame;
    r.origin.x -= 8;
    accessory.frame = r;
}



回答3:


I was able to change the accessory view's frame by simply doing this in my custom cell subclass.

CGRect adjustedFrame = self.accessoryView.frame;
adjustedFrame.origin.x += 10.0f;
self.accessoryView.frame = adjustedFrame;



回答4:


Another way to do this is to embed your custom accessory view in another view, that is set as the cell's accessory view and control the padding using the frame.

Here is an example with an image view as custom accessory view:

// Use insets to define the padding on each side within the wrapper view
UIEdgeInsets insets = UIEdgeInsetsMake(24, 0, 0, 0);

// Create custom accessory view, in this case an image view
UIImage *customImage = [UIImage imageNamed:@"customImage.png"];
UIImageView *accessoryView = [[UIImageView alloc] initWithImage:customImage];

// Create wrapper view with size that takes the insets into account 
UIView *accessoryWrapperView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, customImage.size.width+insets.left+insets.right, customImage.size.height+insets.top+insets.bottom)];

// Add custom accessory view into wrapper view
[accessoryWrapperView addSubview:accessoryView];

// Use inset's left and top values to position the custom accessory view inside the wrapper view
accessoryView.frame = CGRectMake(insets.left, insets.top, customImage.size.width, customImage.size.height);

// Set accessory view of cell (in this case this code is called from within the cell)
self.accessoryView = accessoryWrapperView;



回答5:


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



回答6:


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



回答7:


The simple way to set a custom position for the accessoryView that is persisted in any cell status is to layout the accessoryView in layoutSubViews:

- (void)layoutSubviews
{
    [super layoutSubviews];
    self.accessoryView.center = CGPointMake($yourX, $yourY);
}



回答8:


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.




回答9:


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.




回答10:


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


来源:https://stackoverflow.com/questions/2876041/can-a-standard-accessory-view-be-in-a-different-position-within-a-uitableviewcel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!