问题
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