Tenho uma UITableView
execução no iOS 8 e estou usando alturas de células automáticas de restrições em um storyboard.
Uma das minhas células contém uma única UITextView
e eu preciso que ela se contraia e expanda com base na entrada do usuário - toque para diminuir / expandir o texto.
Estou fazendo isso adicionando uma restrição de tempo de execução à exibição de texto e alterando a constante na restrição em resposta a eventos do usuário:
-(void)collapse:(BOOL)collapse; {
_collapsed = collapse;
if(collapse)
[_collapsedtextHeightConstraint setConstant: kCollapsedHeight]; // 70.0
else
[_collapsedtextHeightConstraint setConstant: [self idealCellHeightToShowFullText]];
[self setNeedsUpdateConstraints];
}
Sempre que faço isso, envolvo-o em tableView
atualizações e chamo [tableView setNeedsUpdateConstraints]
:
[tableView beginUpdates];
[_briefCell collapse:!_showFullBriefText];
[tableView setNeedsUpdateConstraints];
// I have also tried
// [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop];
// with exactly the same results.
[tableView endUpdates];
Quando faço isso, meu celular se expande (e anima enquanto o faz), mas recebo um aviso de restrições:
2014-07-31 13:29:51.792 OneFlatEarth[5505:730175] 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:0x7f94dced2b60 V:[UITextView:0x7f94d9b2b200'Brief text: Lorem Ipsum i...'(388)]>",
"<NSLayoutConstraint:0x7f94dced2260 V:[UITextView:0x7f94d9b2b200'Brief text: Lorem Ipsum i...']-(15)-| (Names: '|':UITableViewCellContentView:0x7f94de5773a0 )>",
"<NSLayoutConstraint:0x7f94dced2350 V:|-(6)-[UITextView:0x7f94d9b2b200'Brief text: Lorem Ipsum i...'] (Names: '|':UITableViewCellContentView:0x7f94de5773a0 )>",
"<NSLayoutConstraint:0x7f94dced6480 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7f94de5773a0(91)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7f94dced2b60 V:[UITextView:0x7f94d9b2b200'Brief text: Lorem Ipsum i...'(388)]>
388 é minha altura calculada, as outras restrições UITextView
são as de Xcode / IB.
O último está me incomodando - acho que essa UIView-Encapsulated-Layout-Height
é a altura calculada da célula quando ela é renderizada pela primeira vez - (defino minha UITextView
altura como> = 70.0), mas não parece certo que essa restrição derivada substitua uma usuário atualizado cnstraint.
Pior, embora o código de layout diga que está tentando quebrar minha restrição de altura, isso não acontece - ele recalcula a altura da célula e tudo é desenhado como eu gostaria.
Então, o que é NSLayoutConstraint
UIView-Encapsulated-Layout-Height
(suponho que seja a altura calculada para o dimensionamento automático de células) e como devo forçá-lo a recalcular corretamente?
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
. Eu acho que a configuração inicial da máscara de redimensionamento automático impede que a última restrição seja adicionada. Eu encontrei esta solução aqui: github.com/wordpress-mobile/WordPress-iOS/commit/…<rect key="frame" x="0.0" y="0.0" width="600" height="110"/>
em sua definição, levando-me a acreditar que este é um bug do IB . Pelo menos o meu era assim mesmo.Respostas:
Tente diminuir a prioridade do seu
_collapsedtextHeightConstraint
para 999. Dessa forma, aUIView-Encapsulated-Layout-Height
restrição fornecida pelo sistema sempre tem precedência.É baseado no que você retorna
-tableView:heightForRowAtIndexPath:
. Certifique-se de retornar o valor certo, sua própria restrição e a gerada deve ser a mesma. A prioridade mais baixa para sua própria restrição é necessária apenas temporariamente para evitar conflitos enquanto as animações de recolhimento / expansão estão em andamento.fonte
UIView-Encapsulated-Layout-Height
restrição é adicionada pelo UITableView depois que as alturas são determinadas. Calculo a altura com base nosystemLayoutSizeFittingSize
contentView. Aqui,UIView-Encapsulated-Layout-Height
não importa. Em seguida, o tableView define o contentSize explicitamente para o valor retornado porheightForRowAtIndexPath:
. Nesse caso, é correto diminuir a prioridade de nossas restrições personalizadas, porque a restrição tableView deve ter precedência após o cálculo do rowHeights.UIView-Encapsulated-Layout-Height
se eu não abaixar a prioridade ...UIView-Encapsulated-Layout-Width
no meu caso está errado, mas parece ser preferível às minhas restrições explícitas em tempo de execução.Eu tenho um cenário semelhante: uma exibição de tabela com uma célula de linha, na qual existem algumas linhas de objetos UILabel. Estou usando o iOS 8 e o autolayout.
Quando eu girei, obtive a altura calculada da linha do sistema incorreta (43,5 é muito menor que a altura real). Parece que:
Não é apenas um aviso. O layout da minha célula de exibição de tabela é terrível - todo o texto se sobrepõe em uma linha de texto.
Surpreende-me que a seguinte linha "corrija" meu problema magicamente (o autolayout não reclama nada e recebo o que espero na tela):
com ou sem esta linha:
fonte
estimatedRowHeight
mais frequentementecellForRowAtIndexPath
será chamado inicialmente. altura da visualização da tabela dividida por vezes estimadoRowHeight, para ser exato. Em um iPad Pro de 12 polegadas, isso pode ser um número na casa dos milhares e martelará a fonte de dados e poderá resultar em um atraso significativo.Consegui que o aviso fosse embora especificando uma prioridade em um dos valores na restrição que as mensagens de aviso dizem que precisavam ser quebradas (abaixo
"Will attempt to recover by breaking constraint"
). Parece que, desde que eu defina a prioridade como algo maior que49
, o aviso desaparecerá.Para mim, isso significava mudar minha restrição, o aviso dizia que tentava quebrar:
@"V:|[contentLabel]-[quoteeLabel]|"
para:
@"V:|-0@500-[contentLabel]-[quoteeLabel]|"
De fato, posso adicionar uma prioridade a qualquer um dos elementos dessa restrição e ela funcionará. Não parece importar qual. Minhas células terminam na altura adequada e o aviso não é exibido. Roger, por exemplo, tente adicionar
@500
logo após a388
restrição do valor da altura (por exemplo388@500
).Não sei ao certo por que isso funciona, mas investiguei um pouco. Na enumeração NSLayoutPriority , parece que o
NSLayoutPriorityFittingSizeCompression
nível de prioridade é50
. A documentação para esse nível de prioridade diz:A documentação para a
fittingSize
mensagem referenciada lê:Eu não procurei além disso, mas parece fazer sentido que isso tenha algo a ver com o problema.
fonte
99,9% do tempo, ao usar células ou cabeçalhos personalizados, todos os conflitos
UITableViews
ocorrem quando a tabela é carregada pela primeira vez. Uma vez carregado, você normalmente não verá o conflito novamente.Isso acontece porque a maioria dos desenvolvedores geralmente usa uma altura fixa ou restrição de ancoragem de algum tipo para criar um layout no elemento / célula / cabeçalho. O conflito ocorre porque, quando as
UITableView
primeiras cargas / sendo dispostas, ele define a altura de suas células como 0. Isso obviamente entra em conflito com suas próprias restrições. Para resolver isso, basta definir qualquer restrição de altura fixa para uma prioridade mais baixa (.defaultHigh
). Leia atentamente a mensagem do console e veja qual restrição o sistema de layout decidiu quebrar. Geralmente é esse que precisa de sua prioridade alterada. Você pode alterar a prioridade assim:fonte
Eu era capaz de resolver esse erro removendo uma espúria
cell.layoutIfNeeded()
que eu tive na minhatableView
'scellForRowAt
método.fonte
Em vez de informar a exibição da tabela para atualizar suas restrições, tente recarregar a célula:
UIView-Encapsulated-Layout-Height
é provavelmente a altura que a visualização da tabela calculou para a célula durante o carregamento inicial, com base nas restrições da célula naquele momento.fonte
Outra possibilidade:
Se você estiver usando o layout automático para calcular a altura da célula (altura do contentView, na maioria das vezes como abaixo), e se tiver um separador de visualização uitabl, precisará adicionar a altura do separador para retornar a altura da célula. Depois de obter a altura correta, você não receberá o aviso de pagamento automático.
fonte
UITableViewAutomaticDimension
emheightForRowAtIndexPath
I voltar[sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize] + 0.1
[sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height + 0.1
Como mencionado por Jesse no comentário da pergunta, isso funciona para mim:
Para sua informação, esse problema não ocorre no iOS 10.
fonte
Eu tive esse erro ao usar UITableViewAutomaticDimension e alterar uma restrição de altura em uma exibição dentro da célula.
Finalmente descobri que era devido ao valor constante da restrição não ser arredondado para o número inteiro mais próximo.
fonte
O dimensionamento da exibição de texto para ajustar seu conteúdo e a atualização da constante de restrição de altura para a altura resultante corrigiram o
UIView-Encapsulated-Layout-Height
conflito de restrições para mim, por exemplo:fonte
Depois de passar algumas horas coçando a cabeça com esse bug, finalmente encontrei uma solução que funcionou para mim. meu principal problema era que eu tinha várias pontas registradas para diferentes tipos de célula, mas um tipo de célula especificamente tinha tamanhos diferentes (nem todas as instâncias dessa célula terão o mesmo tamanho). então o problema surgiu quando a tableview estava tentando desenfileirar uma célula desse tipo e passou a ter uma altura diferente. Eu o resolvi definindo
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight; self.frame = CGRectMake(0, 0, self.frame.size.width, {correct height});
sempre que a célula tiver seus dados para calcular seu tamanho. Eu acho que pode estar em
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
algo como
cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight; cell.frame = CGRectMake(0, 0, self.frame.size.width, {correct height});
Espero que isto ajude!
fonte
O TableView obtém a altura da célula no indexPath do delegado. em seguida, obtenha o celular de
cellForRowAtIndexPath
:if cell.contentView.height: 0 // <-> (UIView-Encapsulated-Layout-Height: 0 @ 1000) top (10 @ 1000) em conflito com (UIView-Encapsulated-Layout-Height: 0 @ 1000),
por causa de suas prioridades, é igual a 1000. Precisamos definir a prioridade máxima sob
UIView-Encapsulated-Layout-Height
a prioridade.fonte
Eu estava recebendo uma mensagem como esta:
Estou usando um costume
UITableViewCell
comUITableViewAutomaticDimension
para a altura. E eu também implementei oestimatedHeightForRowAtIndex:
método.A restrição que estava me dando problemas era algo como isto
Alterar a restrição para isso resolverá o problema, mas, como outra resposta, achei que isso não estava correto, pois diminui a prioridade de uma restrição que eu quero que seja exigida:
No entanto, o que notei é que, se eu realmente remover a prioridade, isso também funcionará e não recebo os logs de restrição de quebra:
Isso é um pouco misterioso quanto à diferença entre
|-6-[title]-6-|
e|-[title-|
. Mas especificar o tamanho não é um problema para mim e ele se livra dos logs, e não preciso diminuir a prioridade das minhas restrições necessárias.fonte
Defina isso
view.translatesAutoresizingMaskIntoConstraints = NO;
deve resolver esse problema.fonte
Eu tive um problema semelhante com uma célula de exibição de coleção.
Eu o resolvi abaixando a prioridade da restrição final que estava vinculada à parte inferior da célula (a última da cadeia de cima para baixo da vista - é isso que determina sua altura) para 999.
A altura da cela estava correta e os avisos desapareceram.
fonte