Классы размеров UIStackView и subview

У меня есть UIStackView, где средняя кнопка видна только в раскадровке другого класса размера.

После поворота устройства кнопка будет видна из-за своего класса размера и также находится в правой иерархии представления (изображение), но не имеет достаточных ограничений, заданных UIstackview для правильного позиционирования, она располагается в верхнем левом углу (метка середина).

недостаточно ограничений

Рабочие кнопки (на которые не влияют изменения класса размера) имеют гораздо больше ограничений.

Это ошибка или я что-то упустил? Кто-нибудь знает обходной путь?


person Uwe Wittig    schedule 04.11.2015    source источник


Ответы (4)


Это определенно ошибка в iOS. Когда средняя кнопка установлена, она добавляется как подпредставление представления стека, но не как упорядоченное подпредставление.

Вот обходной путь. Установите пользовательский класс средней кнопки на StackViewBugFixButton. Затем подключите (новый) выход priorView средней кнопки к следующей кнопке слева. Вот определение StackViewBugFixButton:

StackViewBugFixButton.h

#import <UIKit/UIKit.h>

@interface StackViewBugFixButton : UIButton

@property (nonatomic, weak) IBOutlet UIView *priorSibling;

@end

StackViewBugFixButton.m

#import "StackViewBugFixButton.h"

@implementation StackViewBugFixButton

- (void)didMoveToSuperview {
    [super didMoveToSuperview];
    [self putIntoArrangedSubviewsIfNeeded];
}

- (void)putIntoArrangedSubviewsIfNeeded {
    if (![self.superview isKindOfClass:[UIStackView class]]) {
        return;
    }

    if (self.priorSibling == nil) {
        NSLog(@"%@ %s You forgot to hook up my priorSibling outlet.", self, __func__);
        return;
    }

    UIStackView *stackView = (UIStackView *)self.superview;
    if ([stackView.arrangedSubviews indexOfObject:self] != NSNotFound) {
        return;
    }

    NSUInteger priorSiblingIndex = [stackView.arrangedSubviews indexOfObject:self.priorSibling];
    if (priorSiblingIndex == NSNotFound) {
        NSLog(@"%@ %s My priorSibling isn't in my superview's arrangedSubviews.", self, __func__);
        return;
    }

    [stackView insertArrangedSubview:self atIndex:priorSiblingIndex + 1];
}

@end

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

person rob mayoff    schedule 04.11.2015
comment
отлично, это сработало отлично, я немного изменил его, потому что мне не нравится выход и перетаскивание, но, по сути, это ваше решение, я отправлю его как ответ на свой вопрос - person Uwe Wittig; 05.11.2015

Решения, предлагаемые Робом и Уве, определенно работают и решают проблему условно установленных представлений, которые не добавляются в arrangedSubviews при изменении коллекции признаков.

Я предпочел решить эту проблему, не создавая подклассы для каждого представления, которое я хотел поместить в UIStackView, поэтому я создал подкласс самого UIStackView, чтобы переопределить layoutSubviews() и добавить потерянные подпредставления в arrangedSubviews:

class ManagedStackView: UIStackView {

    override func layoutSubviews() {
        super.layoutSubviews()
        let unarrangedSubviews = subviews.filter({ !arrangedSubviews.contains($0) })
        unarrangedSubviews.forEach({ insertArrangedSubview($0, atIndex: $0._arrangedSubviewIndex) })
    }

}


extension UIView {

    private var _arrangedSubviewIndex: Int {
        get {
            return tag
        }
        set {
            tag = newValue
        }
    }

}
person khaullen    schedule 17.02.2016

Благодаря Робу я создал следующее решение с помощью swift, вы должны установить controlIndex в определяемых пользователем значениях времени выполнения, но на правильный индекс (см. изображение)

import UIKit

class UIButtonFixForStackView: UIButton {

    var controlIndex:Int = 0

    internal override func didMoveToSuperview() {


    if (superview?.isKindOfClass(UIStackView) == false)
    {
        return
    }

    if let stackView = self.superview as? UIStackView
    {
        if stackView.arrangedSubviews.indexOf(self) != nil
        {
            return
        }

        stackView.insertArrangedSubview(self, atIndex: controlIndex)
        }
    }
}
person Uwe Wittig    schedule 04.11.2015

Хотя принятые ответы должны работать как программный подход, стоит отметить, что вы можете избежать этой проблемы в Interface Builder, добавив свои варианты класса размера для свойства Hidden вместо Installed собственность. iOS правильно обрабатывает этот сценарий, потому что arrangedSubviews на самом деле никогда не меняется, а UIStackView создан для адаптации его макета когда (упорядоченные) подвиды скрыты.

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

изменение скрытого свойства

person Ronald Martin    schedule 09.10.2019