ios - UIStackView "Não é possível satisfazer simultaneamente as restrições" nas visualizações ocultas "esmagadas"




autolayout uikit (10)

Quando minhas "linhas" do UIStackView são esmagadas, eles lançam avisos de AutoLayout . No entanto, eles exibem bem e nada mais está errado além desses tipos de registros:

Não é possível satisfazer simultaneamente as restrições. Provavelmente, pelo menos uma das restrições na lista a seguir é uma que você não deseja. Tente o seguinte: (1) observe cada restrição e tente descobrir o que você não espera; (2) encontre o código que adicionou as restrições ou restrições indesejadas e corrija-o. (Nota: se você estiver vendo NSAutoresizingMaskLayoutConstraints que você não entende, consulte a documentação da propriedade UIView translatesAutoresizingMaskIntoConstraints UIView ) (

Portanto, não tenho certeza de como consertar isso ainda, mas não parece quebrar nada além de ser irritante.

Alguém sabe como resolver isso? Curiosamente, as restrições de layout são frequentemente marcadas com 'UISV-hiding' , indicando que talvez deva ignorar as mínimas de altura para subvisões ou algo nesse caso?


Com base na resposta da @ Senseful, aqui está uma extensão do UIStackView para agrupar uma exibição de pilha em uma exibição e aplicar as restrições que ele recomenda:

/// wraps in a `UIView` to prevent autolayout warnings when a stack view with spacing is placed inside another stack view whose height might be zero (usually due to `hidden` being `true`).
/// See http://.com/questions/32428210
func wrapped() -> UIView {
    let wrapper = UIView()
    translatesAutoresizingMaskIntoConstraints = false
    wrapper.addSubview(self)

    for attribute in [NSLayoutAttribute.Top, .Left, .Right, .Bottom] {
        let constraint = NSLayoutConstraint(item: self,
                                            attribute: attribute,
                                            relatedBy: .Equal,
                                            toItem: wrapper,
                                            attribute: attribute,
                                            multiplier: 1,
                                            constant: 0)
        if attribute == .Bottom { constraint.priority = 999 }
        wrapper.addConstraint(constraint)
    }
    return wrapper
}

Em vez de adicionar seu stackView , use stackView.wrapped() .


Este erro não tem nada a ver com o UIStackView. Isso acontece quando você tem restrições de conflito com as mesmas prioridades. Por exemplo, se você tiver uma restrição afirma que a largura da sua visualização é 100 e outra ao mesmo tempo afirma que a largura da visualização é 25% de seu contêiner. Obviamente, existem duas restrições conflitantes. A solução é excluir um deles.


Eu experimentei os mesmos erros com o Stack Views incorporado, embora tudo funcionasse bem em tempo de execução.

Resolvi os erros de restrição ocultando todas as visualizações de isHidden = true primeiro (configuração isHidden = true ) antes de ocultar a exibição de pilha pai.

Fazer isso não tinha toda a complexidade de remover visualizações suborganizadas, mantendo um índice para quando precisar adicioná-las novamente.

Espero que isto ajude.


Eu queria ocultar todo o UIStackView de cada vez, mas estava recebendo os mesmos erros do OP, isso corrigiu para mim:

for(UIView *currentView in self.arrangedSubviews){
    for(NSLayoutConstraint *currentConstraint in currentView.constraints){
        [currentConstraint setPriority:999];
    }
}

NOP com [mySubView removeFromSuperview]. Espero que ajude alguém :)


Na maioria das vezes, esse erro pode ser resolvido diminuindo a prioridade das restrições para eliminar conflitos.


Quando você define uma exibição como oculta, o UIStackview tenta animá-la. Se você deseja esse efeito, precisará definir a prioridade certa para as restrições, para que não entrem em conflito (como muitos sugeriram acima).

No entanto, se você não se importa com a animação (talvez esteja ocultando-a no ViewDidLoad), é possível removeFromSuperview que terá o mesmo efeito, mas sem problemas com restrições, pois essas serão removidas junto com a exibição.


Recentemente, lutei com erros de layout automático ao ocultar um UIStackView . Em vez de fazer um monte de livros para guardar e UIViews em UIViews , optei por criar uma saída para o parentStackView e saídas para os filhos que quero ocultar / mostrar.

@IBOutlet weak var parentStackView: UIStackView!
@IBOutlet var stackViewNumber1: UIStackView!
@IBOutlet var stackViewNumber2: UIStackView!

No storyboard, eis a aparência do meu parentStack:

Tem 4 filhos e cada um deles tem várias visualizações de pilha dentro deles. Quando você oculta uma exibição de pilha, se houver elementos de interface do usuário que também sejam exibições de pilha, você verá um fluxo de erros de layout automático. Em vez de me esconder, optei por removê-los.

No meu exemplo, parentStackViews contém uma matriz dos 4 elementos: Top Stack View, StackViewNumber1, Stack View Number 2 e Stop Button. Seus índices nas visualizações arrangedSubviews são 0, 1, 2 e 3, respectivamente. Quando quero ocultar um, basta removê-lo da matriz arrangedSubviews parentStackView's . Como não é fraco, permanece na memória e você pode colocá-lo novamente no índice desejado mais tarde. Não estou reinicializando, de modo que ele permanece até que seja necessário, mas não incha a memória.

Então, basicamente, você pode ...

1) Arraste os IBOutlets para sua pilha pai e os filhos que você deseja ocultar / exibir no storyboard.

2) Quando você deseja ocultá-los, remova a pilha que deseja ocultar da matriz arrangedSubviews parentStackView's .

3) Chame self.view.layoutIfNeeded() com UIView.animateWithDuration .

Observe que os dois últimos stackViews não são weak . Você precisa mantê-los por perto para quando os mostrar.

Digamos que eu quero ocultar stackViewNumber2:

parentStackView.removeArrangedSubview(stackViewNumber2)
stackViewNumber2.removeFromSuperview()

Então animá-lo:

UIView.animate(withDuration: 0.25,
               delay: 0,
               usingSpringWithDamping: 2.0,
               initialSpringVelocity: 10.0,
               options: [.curveEaseOut],
               animations: {
                self.view.layoutIfNeeded()
},
               completion: nil)

Se você deseja "mostrar" um stackViewNumber2 posteriormente, basta inseri-lo no índice parentStackView arrangedSubViews desejado e animar a atualização.

parentStackView.removeArrangedSubview(stackViewNumber1)
stackViewNumber1.removeFromSuperview()
parentStackView.insertArrangedSubview(stackViewNumber2, at: 1)

// Then animate it
UIView.animate(withDuration: 0.25,
               delay: 0,
               usingSpringWithDamping: 2.0,
               initialSpringVelocity: 10.0,
               options: [.curveEaseOut],
               animations: {
                self.view.layoutIfNeeded()
},
               completion: nil)

Achei isso muito mais fácil do que fazer contabilidade sobre restrições, mexer com prioridades, etc.

Se você tem algo que deseja ocultar por padrão, basta colocá-lo no storyboard e removê-lo em viewDidLoad e atualizar sem a animação usando view.layoutIfNeeded() .


Você pode ter criado uma restrição ao trabalhar com uma determinada classe de tamanho (por exemplo: wCompact hRegular) e, em seguida, criou uma duplicata quando mudou para outra classe de tamanho (por exemplo: wAny hAny). verifique as restrições dos objetos da interface do usuário em diferentes classes de tamanho e veja se há anomalias com as restrições. você deve ver as linhas vermelhas indicando restrições em colisão. Não posso colocar uma foto até receber 10 pontos de reputação, desculpe: /


Você tem esse problema porque, ao definir uma UIStackView do UIStackView como oculta, ela primeiro restringe sua altura a zero para animá-la.

Eu estava recebendo o seguinte erro:

2015-10-01 11:45:13.732 <redacted>[64455:6368084] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x7f7f5be18c80 V:[UISegmentedControl:0x7f7f5bec4180]-(8)-|   (Names: '|':UIView:0x7f7f5be69d30 )>",
    "<NSLayoutConstraint:0x7f7f5be508d0 V:|-(8)-[UISegmentedControl:0x7f7f5bec4180]   (Names: '|':UIView:0x7f7f5be69d30 )>",
    "<NSLayoutConstraint:0x7f7f5bdfbda0 'UISV-hiding' V:[UIView:0x7f7f5be69d30(0)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7f7f5be18c80 V:[UISegmentedControl:0x7f7f5bec4180]-(8)-|   (Names: '|':UIView:0x7f7f5be69d30 )>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

O que eu estava tentando fazer era colocar um UIView dentro do meu UIStackView que contivesse uma inserção UISegmentedControl por 8pts em cada borda.

Quando o defino como oculto, ele tenta restringir a exibição do contêiner a uma altura zero, mas como tenho um conjunto de restrições de cima para baixo, houve um conflito.

Para resolver o problema, alterei a prioridade das restrições superior e inferior de 8pt de 1000 para 999 para que a UISV-hiding possa ter prioridade, se necessário.