Может ли стандартный вид аксессуаров находиться в другом месте в UITableViewCell?

Я хочу, чтобы мой аксессуар находился в немного другом месте, чем обычно. Является ли это возможным? Этот код не действует:

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

Ответ 1

Нет, вы не можете перемещаться, где находится аксессуар. В качестве альтернативы вы можете добавить подзаголовок следующим образом:

[cell.contentView addSubview:aView];

Кроме того, устанавливая свойство accessoryView равным чему-то, значение accessoryType игнорируется.

Ответ 2

Есть способ переместить defaultксессуар, но он довольно взломан. Таким образом, он может перестать работать в один прекрасный день, когда придет новый SDK.

Используйте на свой страх и риск (этот фрагмент кода перемещает любой accessoryView 8 пикселей влево. Вставьте его внутри метода -(void)layoutSubviews желаемого подкласса UITableViewCell):

if (self.accessoryView) {
    r = self.accessoryView.frame;
    r.origin.x -= 8;
    self.accessoryView.frame = r;
} else {
    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) {
            defaultAccessoryView = subview;
            break;
        }
    }

    r = defaultAccessoryView.frame;
    r.origin.x -= 8;
    defaultAccessoryView.frame = r;
}

Ответ 3

Мне удалось изменить внешний вид аксессуаров, просто сделав это в моем пользовательском подклассе ячейки.

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

Ответ 4

Другой способ сделать это - встраивать свой пользовательский вид аксессуаров в другое представление, которое устанавливается как вид аксессуара ячейки и управляет дополнением с использованием фрейма.

Вот пример с представлением изображения в виде пользовательского аксессуара:

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

Следуя решению, предоставленному Ana, я попытался лучше определить аксессуар, я посмотрю на правую часть ячейки.

Создайте собственный класс, который расширяет UITableViewCell и добавляет этот метод:

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

Вышеуказанные ответы не помогли мне в соответствии с ios 6.1. Поэтому я попытался использовать UIEdgeInsets, потому что DetailDisclosure - это UIButton. И теперь он отлично работает. Здесь источник:

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

Я работал с ios5, и решение, данное Алексеем, не работало полностью. Я обнаружил, что, когда в таблице установлен атрибут accessoriesType, accessView имеет значение null, поэтому первое "если" не работает. Я немного изменил код:

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;

}

и это решение работает для меня. Как сказал Алексей, я не знаю, что произойдет с будущими версиями, но, по крайней мере, в ios 4 работает.

Ответ 8

Возможно, этого вам будет достаточно:

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;

Таким образом, я добавил прописку справа, так что кнопка аксессуаров смещается влево. Он имеет более широкую область, которая реагирует на касания, это единственный побочный эффект.

Ответ 9

Простым способом установки настраиваемой позиции для аксессуара, который сохраняется в любом состоянии ячейки, является расположение аксессуара в layoutSubViews:

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

Ответ 10

улучшения в других ответах

Для Джеймса Куанга, Kappe, accessoryView нет нулевого значения для аксессуаров по умолчанию.

Для Matjan, subviews.lastObject легко выглядит неправильно, например, UITableViewCellSeparatorView.

Для Алексея, Ана, Томаша, перечисляющего подпункты, пока мы не найдем неизвестного, сейчас работает. Но это кропотливо и может быть легко сломано в будущих версиях, если, скажем, Apple добавит backgroundAccessoryView.

Для larshaeuser, перечисляя подпункты, пока мы не найдем UIButton, хорошая идея, но contentEdgeInsets не заметно заметно меняет вид аксессуаров.

мое решение

Мы будем перечислять и искать последний 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
        }
    }
}