Eu tenho um UITableView
com um personalizado UITableViewCell
definido em um storyboard usando layout automático. A célula possui várias linhas UILabels
.
O UITableView
parece calcular corretamente as alturas das células, mas para as primeiras células essa altura não é dividida corretamente entre os rótulos. Depois de rolar um pouco, tudo funciona conforme o esperado (mesmo as células que estavam inicialmente incorretas).
- (void)viewDidLoad {
[super viewDidLoad]
// ...
self.tableView.rowHeight = UITableViewAutomaticDimension;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"TestCell"];
// ...
// Set label.text for variable length string.
return cell;
}
Existe alguma coisa que eu possa estar perdendo, que está fazendo com que o layout automático não consiga fazer seu trabalho nas primeiras vezes?
Criei um projeto de amostra que demonstra esse comportamento.
ios
uitableview
ios8
autolayout
ios-autolayout
blackp
fonte
fonte
Respostas:
Não sei se isso está claramente documentado ou não, mas adicionar
[cell layoutIfNeeded]
antes de devolver o celular resolve seu problema.fonte
-layoutIfNeeded
no do celular-awakeFromNib
. Prefiro ligar apenas paralayoutIfNeeded
onde sei por que é necessário.Isso funcionou para mim quando outras soluções semelhantes não:
Este parece ser um bug real, já que estou muito familiarizado com o AutoLayout e como usar UITableViewAutomaticDimension, no entanto, ainda ocasionalmente me deparo com esse problema. Estou feliz por finalmente encontrar algo que funciona como uma solução alternativa.
fonte
super.didMoveToSuperview()
didMoveToSuperview
: "A implementação padrão deste método não faz nada."Adicionando
[cell layoutIfNeeded]
emcellForRowAtIndexPath
não funciona para células que são inicialmente enrolado out-of-view.Nem prefaciar com
[cell setNeedsLayout]
.Você ainda tem que rolar certas células para fora e de volta à vista para que sejam redimensionadas corretamente.
Isso é muito frustrante, já que a maioria dos desenvolvedores possui Dynamic Type, AutoLayout e Self-Sizing Cells funcionando corretamente - exceto neste caso irritante. Este bug afeta todos os meus controladores de visualização de tabela "mais altos".
fonte
[cell layoutSubviews]
vez de layoutIfNeeded pode ser uma solução possível. Consulte stackoverflow.com/a/33515872/1474113Tive a mesma experiência em um de meus projetos.
Por que isso acontece?
Célula projetada no Storyboard com alguma largura para algum dispositivo. Por exemplo, 400px. Por exemplo, sua etiqueta tem a mesma largura. Quando carrega do storyboard, tem largura de 400 px.
Aqui está um problema:
tableView:heightForRowAtIndexPath:
chamado antes do layout da célula é subvisualizações.Portanto, ele calculou a altura do rótulo e da célula com largura de 400 px. Mas você roda em aparelho com tela, por exemplo, 320px. E esta altura calculada automaticamente está incorreta. Só porque o celular
layoutSubviews
só acontece depois.tableView:heightForRowAtIndexPath:
Mesmo que você configurepreferredMaxLayoutWidth
seu rótulo manualmente,layoutSubviews
isso não ajuda.Minha solução:
1) Subclasse
UITableView
e substituiçãodequeueReusableCellWithIdentifier:forIndexPath:
. Defina a largura da célula igual à largura da tabela e o layout da célula de força.2) Subclasse
UITableViewCell
. DefinapreferredMaxLayoutWidth
manualmente para seus rótulos emlayoutSubviews
. Além disso, você precisa do layout manualmentecontentView
, porque ele não faz o layout automaticamente após a mudança do quadro da célula (não sei por que, mas é)fonte
cell.frame.size.width = tableview.frame.width
seguidacell.layoutIfNeeded()
, acellForRowAt
função funcionou para mimEu tenho um problema semelhante, no primeiro carregamento, a altura da linha não foi calculada, mas depois de alguma rolagem ou vá para outra tela e volto a esta tela as linhas são calculadas. No primeiro carregamento, meus itens são carregados da internet e no segundo carregamento meus itens são carregados primeiro do Core Data e recarregados da internet e eu percebi que a altura das linhas são calculadas no recarregamento da internet. Portanto, percebi que quando tableView.reloadData () é chamado durante a animação segue (mesmo problema com push e segue segue), a altura da linha não foi calculada. Então, escondi o tableview na inicialização do modo de exibição e coloquei um carregador de atividade para evitar um efeito desagradável para o usuário e chamei tableView.reloadData após 300 ms e agora o problema está resolvido. Acho que é um bug do UIKit, mas essa solução alternativa resolve o problema.
Eu coloquei essas linhas (Swift 3.0) no meu gerenciador de conclusão de carga de item
Isso explica por que, para algumas pessoas, colocar reloadData em layoutSubviews resolve o problema
fonte
nenhuma das soluções acima funcionou para mim, o que funcionou é esta receita de mágica: chame-os nesta ordem:
tableView.reloadData()
tableView.layoutIfNeeded() tableView.beginUpdates() tableView.endUpdates()
meus dados do tableView são preenchidos a partir de um serviço da web, no retorno de chamada da conexão, escrevo as linhas acima.
fonte
No meu caso, a última linha do UILabel foi truncada quando a célula foi exibida pela primeira vez. Aconteceu de forma bastante aleatória e a única maneira de dimensionar corretamente era rolar a célula para fora da visualização e trazê-la de volta. Tentei todas as soluções possíveis exibidas até agora (layoutIfNeeded..reloadData), mas nada funcionou para mim. O truque era definir "Autoshrink" para Minimuum Font Scale (0,5 para mim). De uma chance
fonte
Adicione uma restrição para todo o conteúdo dentro de uma célula personalizada de visualização de tabela, em seguida, estime a altura da linha de visualização de tabela e defina a altura da linha para dimensão automática com uma carga viewdid:
Para corrigir esse problema de carregamento inicial, aplique o método layoutIfNeeded em uma célula de visualização de tabela personalizada:
fonte
estimatedRowHeight
um valor> 0 e nãoUITableViewAutomaticDimension
(que é -1), caso contrário, a altura da linha automática não funcionará.Tentei a maioria das respostas a esta pergunta e não consegui fazer nenhuma delas funcionar. A única solução funcional que encontrei foi adicionar o seguinte à minha
UITableViewController
subclasse:A
UIView.performWithoutAnimation
chamada é necessária, caso contrário, você verá a animação normal da visualização da tabela conforme o controlador da visualização carrega.fonte
viewWillAppear
não funcionou para mim, mas fazê-lo emviewDidAppear
sim.A configuração
preferredMaxLayoutWidth
ajuda no meu caso. Eu adicioneino meu código.
Consulte também o texto de linha única ocupa duas linhas em UILabel e http://openradar.appspot.com/17799811 .
fonte
ligar para
cell.layoutIfNeeded()
dentrocellForRowAt
funcionou para mim no iOS 10 e no iOS 11, mas não no iOS 9.para conseguir esse trabalho no ios 9 também, ligo
cell.layoutSubviews()
e funcionou.fonte
Para mim, nenhuma dessas abordagens funcionou, mas descobri que o rótulo tinha um
Preferred Width
conjunto explícito no Interface Builder. Removendo isso (desmarcando "Explícito") e usandoUITableViewAutomaticDimension
funcionou como esperado.fonte
Tentei todas as soluções nesta página, mas desmarcar usar classes de tamanho e, em seguida, verificar novamente resolveu meu problema.
Edit: Desmarcar as classes de tamanho causa muitos problemas no storyboard, então tentei outra solução. Preenchi minha table view em meu view controller
viewDidLoad
eviewWillAppear
métodos. Isso resolveu meu problema.fonte
Tenho o problema de redimensionar o rótulo, então preciso apenas fazer
chatTextLabel.text = chatMessage.message chatTextLabel? .UpdateConstraints () após configurar o texto
// código completo
fonte
No meu caso, fui atualizando em outro ciclo. Portanto, a altura de tableViewCell foi atualizada após a configuração de labelText. Excluí o bloco assíncrono.
fonte
Apenas certifique-se de não definir o texto do rótulo no método delegado 'willdisplaycell' de visualização de tabela. Defina o texto do rótulo no método delegado 'cellForRowAtindexPath' para cálculo de altura dinâmica.
De nada :)
fonte
No meu caso, uma exibição de pilha na célula estava causando o problema. Aparentemente, é um bug. Depois de removê-lo, o problema foi resolvido.
fonte
O problema é que as células iniciais são carregadas antes de termos uma altura de linha válida. A solução alternativa é forçar o recarregamento da tabela quando a exibição for exibida.
fonte
Apenas para iOS 12+, 2019 em diante ...
Um exemplo contínuo da incompetência bizarra ocasional da Apple, onde os problemas duram literalmente anos.
Parece ser o caso de
vai consertar isso. (Você está perdendo algum desempenho, é claro.)
Assim é a vida com a Apple.
fonte
No meu caso, o problema com a altura da célula ocorre depois que a visualização da tabela inicial é carregada e ocorre uma ação do usuário (tocar em um botão em uma célula que tem o efeito de alterar a altura da célula). Não consegui fazer a célula mudar sua altura, a menos que eu:
Eu tentei
mas isso não funcionou.
fonte
No Swift 3. Tive que chamar self.layoutIfNeeded () cada vez que atualizo o texto da célula reutilizável.
fonte
Nenhuma das soluções acima funcionou, mas a seguinte combinação de sugestões funcionou.
Tive que adicionar o seguinte em viewDidLoad ().
A combinação acima de reloadData, setNeedsLayout e layoutIfNeeded funcionou, mas nenhuma outra. No entanto, pode ser específico para as células do projeto. E sim, tive que invocar reloadData duas vezes para fazê-lo funcionar.
Defina também o seguinte em viewDidLoad
Em tableView (_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
fonte
reloadData/beginUpdates/endUpdates/reloadData
também está funcionando;reloadData
deve ser chamado uma segunda vez. Não precisa embrulharasync
.Corri para esse problema e corrigi-lo movendo meu código de inicialização view / label DE
tableView(willDisplay cell:)
PARAtableView(cellForRowAt:)
.fonte
willDisplay
terá um desempenho melhor do quecellForRowAt
. Use o último apenas para instanciar a célula certa.willDisplay
tenha melhor desempenho, é recomendável inicializar sua UI de célulacellForRowAt
quando o layout for automático. Na verdade, o layout é calculado por UIKit após cellForRowAt et antes de willDisplay. Portanto, se a altura de sua célula depende de seu conteúdo, inicialize o conteúdo do rótulo (ou qualquer outro) emcellForRowAt
.use o método acima que retorna a altura da linha dinamicamente. E atribua a mesma altura dinâmica à etiqueta que você está usando.
Este código ajuda a encontrar a altura dinâmica do texto exibido no rótulo.
fonte