Como você usa o Layout automático dentro de UITableViewCell
s em uma exibição de tabela para permitir que o conteúdo e as subvisões de cada célula determinem a altura da linha (ela própria / automaticamente), mantendo o desempenho de rolagem suave?
ios
uitableview
autolayout
nsautolayout
row-height
smileyborg
fonte
fonte
contentSize
epreferredMaxLayoutWidth
trabalhar. Veja aqui . Dito isto, se você configurar suas restrições corretamente, não será necessáriopreferredMaxLayoutWidth
e poderá criar resultados inesperados.Respostas:
TL; DR: Não gosta de ler? Vá direto para os projetos de amostra no GitHub:
Descrição conceitual
As duas primeiras etapas abaixo são aplicáveis, independentemente de quais versões do iOS você está desenvolvendo.
1. Configurar e adicionar restrições
Na sua
UITableViewCell
subclasse, adicione restrições para que as subvisões da célula tenham suas bordas fixadas nas bordas do contentView da célula (o mais importante nas bordas superior E inferior). NOTA: não fixe subvisões à própria célula; apenas para o celularcontentView
! Permita que o tamanho do conteúdo intrínseco dessas subvisões conduza a altura da visualização do conteúdo da célula, garantindo que a resistência à compactação e as restrições de restrição de conteúdo na dimensão vertical de cada subvisão não sejam substituídas pelas restrições de prioridade mais alta que você adicionou. ( Hein? Clique aqui. )Lembre-se de que a ideia é ter as subvisões da célula conectadas verticalmente à visualização de conteúdo da célula, para que possam "exercer pressão" e fazer com que a visualização de conteúdo se expanda para ajustá-las. Usando uma célula de exemplo com algumas subvisões, aqui está uma ilustração visual de como algumas (não todas!) De suas restrições teriam a aparência:
Você pode imaginar que, à medida que mais texto for adicionado ao rótulo do corpo com várias linhas na célula de exemplo acima, ele precisará crescer verticalmente para caber no texto, o que forçará efetivamente a célula a crescer em altura. (Obviamente, você precisa acertar as restrições para que funcione corretamente!)
Ajustar corretamente suas restrições é definitivamente a parte mais difícil e importante de obter alturas dinâmicas de células trabalhando com o Layout Automático. Se você cometer um erro aqui, isso poderá impedir que tudo funcione - por isso não se apresse! Eu recomendo configurar suas restrições no código porque você sabe exatamente quais restrições estão sendo adicionadas e onde é muito mais fácil depurar quando as coisas dão errado. Adicionar restrições no código pode ser tão fácil quanto e significativamente mais poderoso que o Interface Builder usando âncoras de layout ou uma das fantásticas APIs de código aberto disponíveis no GitHub.
updateConstraints
método da sua subclasse UITableViewCell. Observe queupdateConstraints
pode ser chamado mais de uma vez; portanto, para evitar adicionar as mesmas restrições mais de uma vez, envolva seu código de adição de restriçãoupdateConstraints
em uma verificação de uma propriedade booleana comodidSetupConstraints
(que você definiu como YES depois de executar sua restrição código de adição uma vez). Por outro lado, se você tiver um código que atualize as restrições existentes (como ajustar aconstant
propriedade em algumas restrições), coloque-o dentro,updateConstraints
mas fora da verificação, paradidSetupConstraints
que ele possa ser executado sempre que o método for chamado.2. Determinar identificadores exclusivos de reutilização de célula no modo de exibição de tabela
Para cada conjunto exclusivo de restrições na célula, use um identificador de reutilização de célula exclusivo. Em outras palavras, se suas células tiverem mais de um layout exclusivo, cada layout exclusivo receberá seu próprio identificador de reutilização. (Uma boa dica de que você precisa usar um novo identificador de reutilização é quando a variante de célula tem um número diferente de sub-visualizações ou as sub-visualizações são organizadas de maneira distinta.)
Por exemplo, se você estivesse exibindo uma mensagem de email em cada célula, poderá ter quatro layouts exclusivos: mensagens com apenas um assunto, mensagens com um assunto e um corpo, mensagens com um assunto e um anexo de foto e mensagens com um assunto, corpo e anexo de foto. Cada layout possui restrições completamente diferentes necessárias para alcançá-la. Assim, quando a célula é inicializada e as restrições são adicionadas a um desses tipos de células, a célula deve obter um identificador de reutilização exclusivo específico para esse tipo de célula. Isso significa que, quando você desenfileirar uma célula para reutilização, as restrições já foram adicionadas e estão prontas para esse tipo de célula.
Observe que, devido a diferenças no tamanho do conteúdo intrínseco, as células com as mesmas restrições (tipo) ainda podem ter alturas variadas! Não confunda layouts fundamentalmente diferentes (restrições diferentes) com diferentes frames de vista calculados (resolvidos com restrições idênticas) devido a tamanhos diferentes de conteúdo.
Para iOS 8 - Células de auto-dimensionamento
3. Ative a estimativa de altura da linha
Com o iOS 8, a Apple internalizou grande parte do trabalho que anteriormente deveria ser implementado por você antes do iOS 8. Para permitir que o mecanismo de célula de auto-dimensionamento funcione, você deve primeiro definir a
rowHeight
propriedade na exibição de tabela como constanteUITableViewAutomaticDimension
. Em seguida, basta ativar a estimativa da altura da linha configurando aestimatedRowHeight
propriedade da visualização da tabela para um valor diferente de zero, por exemplo:O que isso faz é fornecer à visualização da tabela uma estimativa / espaço reservado temporário para as alturas de linha das células que ainda não estão na tela. Então, quando essas células estiverem prestes a rolar na tela, a altura real da linha será calculada. Para determinar a altura real de cada linha, a visualização da tabela pergunta automaticamente a cada célula qual a altura
contentView
necessária para se basear na largura fixa conhecida da visualização de conteúdo (que é baseada na largura da visualização da tabela, menos itens adicionais, como um índice de seção ou visualização acessória) e as restrições de layout automáticas adicionadas à visualização e subvisões de conteúdo da célula. Depois que essa altura real da célula é determinada, a altura estimada antiga da linha é atualizada com a nova altura real (e todos os ajustes no contentSize / contentOffset da visualização da tabela são feitos conforme necessário).De um modo geral, a estimativa que você fornece não precisa ser muito precisa - é usada apenas para dimensionar corretamente o indicador de rolagem na exibição de tabela, e a exibição de tabela faz um bom trabalho ao ajustar o indicador de rolagem para estimativas incorretas, conforme você rolar as células na tela. Você deve definir a
estimatedRowHeight
propriedade na visualização da tabela (emviewDidLoad
ou similar) para um valor constante que seja a altura da linha "média". Somente se a altura da sua linha tiver extrema variabilidade (por exemplo, diferir por uma ordem de magnitude) e você notar o indicador de rolagem "pulando" à medida que você rola, você deve se preocupar em implementartableView:estimatedHeightForRowAtIndexPath:
o cálculo mínimo necessário para retornar uma estimativa mais precisa para cada linha.Para suporte ao iOS 7 (implementando o dimensionamento automático de células)
3. Faça um passe de layout e obtenha a altura da célula
Primeiro, instancie uma instância fora da tela de uma célula de exibição de tabela, uma instância para cada identificador de reutilização , usada estritamente para cálculos de altura. (Fora da
tableView:cellForRowAtIndexPath:
tela, o que significa que a referência da célula é armazenada em uma propriedade / ivar no controlador de exibição e nunca retornada da exibição de tabela para renderizar na tela.) Em seguida, a célula deve ser configurada com o conteúdo exato (por exemplo, texto, imagens etc.) que seria válido se fosse exibido na visualização da tabela.Então, forçar a célula para de imediato o layout de seus subviews, e depois usar o
systemLayoutSizeFittingSize:
método noUITableViewCell
'scontentView
para descobrir o que a altura necessária da célula é. UseUILayoutFittingCompressedSize
para obter o menor tamanho necessário para caber em todo o conteúdo da célula. A altura pode então ser retornada dotableView:heightForRowAtIndexPath:
método delegado.4. Use as alturas estimadas das linhas
Se a visualização da tabela contiver mais de duas dúzias de linhas, você descobrirá que a solução de restrições de Layout Automático pode atolar rapidamente o encadeamento principal ao carregar a visualização da tabela pela primeira vez, como
tableView:heightForRowAtIndexPath:
é chamado em todas as linhas após o primeiro carregamento ( para calcular o tamanho do indicador de rolagem).No iOS 7, você pode (e absolutamente deveria) usar a
estimatedRowHeight
propriedade na exibição de tabela. O que isso faz é fornecer à visualização da tabela uma estimativa / espaço reservado temporário para as alturas de linha das células que ainda não estão na tela. Então, quando essas células estiverem prestes a rolar na tela, a altura real da linha será calculada (chamandotableView:heightForRowAtIndexPath:
) e a altura estimada atualizada com a atual.De um modo geral, a estimativa que você fornece não precisa ser muito precisa - é usada apenas para dimensionar corretamente o indicador de rolagem na exibição de tabela, e a exibição de tabela faz um bom trabalho ao ajustar o indicador de rolagem para estimativas incorretas, conforme você rolar as células na tela. Você deve definir a
estimatedRowHeight
propriedade na visualização da tabela (emviewDidLoad
ou similar) para um valor constante que seja a altura da linha "média". Somente se a altura da sua linha tiver extrema variabilidade (por exemplo, diferir por uma ordem de magnitude) e você notar o indicador de rolagem "pulando" à medida que você rola, você deve se preocupar em implementartableView:estimatedHeightForRowAtIndexPath:
o cálculo mínimo necessário para retornar uma estimativa mais precisa para cada linha.5. (Se necessário) Adicionar cache de altura da linha
Se você fez tudo o que foi dito acima e ainda está percebendo que o desempenho é inaceitavelmente lento ao resolver as restrições
tableView:heightForRowAtIndexPath:
, infelizmente você precisará implementar algum cache para a altura das células. (Essa é a abordagem sugerida pelos engenheiros da Apple.) A idéia geral é permitir que o mecanismo de Autolayout resolva as restrições pela primeira vez, depois armazene em cache a altura calculada para essa célula e use o valor em cache para todas as solicitações futuras da altura dessa célula. O truque, é claro, é garantir que você limpe a altura em cache de uma célula quando acontecer algo que possa causar a alteração da altura da célula - principalmente, quando o conteúdo dessa célula for alterado ou quando ocorrerem outros eventos importantes (como o ajuste do usuário o controle deslizante de tamanho de texto Tipo dinâmico).Código de exemplo genérico do iOS 7 (com muitos comentários interessantes)
Projetos de amostra
Esses projetos são exemplos completos de visualizações de tabela com alturas de linha variáveis devido às células de visualização de tabela que contêm conteúdo dinâmico nos UILabels.
Xamarin (C # /. NET)
Se você estiver usando o Xamarin, confira este projeto de amostra elaborado por @KentBoogaart .
fonte
heightForRowAtIndexPath
, mantendo a célula e retornando-a na próxima vez quecellForRowAtIndexPath
for chamado.iOS8
implementação ainda é recomendadaiOS9
eiOS10
, ou existem novas abordagens desde que esta resposta foi publicada?Para o iOS 8 acima, é realmente simples:
ou
Mas para o iOS 7, a chave é calcular a altura após o pagamento automático:
Importante
Se várias etiquetas de linhas, não se esqueça de definir
numberOfLines
como0
.Não esqueça
label.preferredMaxLayoutWidth = CGRectGetWidth(tableView.bounds)
O código de exemplo completo está aqui .
fonte
Exemplo rápido de uma altura variável UITableViewCell
Atualizado para o Swift 3
A resposta rápida de William Hu é boa, mas me ajuda a seguir alguns passos simples, porém detalhados, ao aprender a fazer algo pela primeira vez. O exemplo abaixo é o meu projeto de teste enquanto aprendo a fazer
UITableView
alturas de células variáveis. Baseei-lo em este exemplo UITableView básica para Swift .O projeto final deve ficar assim:
Crie um novo projeto
Pode ser apenas um aplicativo de exibição única.
Adicione o código
Adicione um novo arquivo Swift ao seu projeto. Nomeie-o MyCustomCell. Esta classe manterá as saídas para as visualizações adicionadas ao seu celular no storyboard. Neste exemplo básico, teremos apenas um rótulo em cada célula.
Mais tarde conectaremos esta tomada.
Abra ViewController.swift e verifique se você tem o seguinte conteúdo:
Nota importante:
São as duas linhas de código a seguir (junto com o layout automático) que tornam possível a altura variável da célula:
Configurar o storyboard
Adicione uma visualização de tabela ao seu controlador de visualização e use o layout automático para fixá-la nos quatro lados. Em seguida, arraste uma célula de exibição de tabela para a exibição de tabela. E na célula Prototype, arraste um Label. Use o layout automático para fixar o rótulo nas quatro arestas da exibição de conteúdo da célula de exibição de tabela.
Nota importante:
Outras configurações de IB
Nome da classe personalizada e Identificador
Selecione a célula de exibição de tabela e defina a classe personalizada como
MyCustomCell
(o nome da classe no arquivo Swift que adicionamos). Defina também o identificador comocell
(a mesma string que usamoscellReuseIdentifier
no código acima.Zero linhas para etiqueta
Defina o número de linhas
0
na sua etiqueta. Isso significa várias linhas e permite que o rótulo se redimensione com base em seu conteúdo.Ligar as tomadas
tableView
variável noViewController
código.myCellLabel
variável naMyCustomCell
classe.Acabado
Agora você deve poder executar seu projeto e obter células com alturas variáveis.
Notas
Se você não estiver fixando as arestas à esquerda e à direita (esquerda e direita), também poderá ser necessário definir as etiquetas
preferredMaxLayoutWidth
para que ele saiba quando alinhar a linha. Por exemplo, se você tivesse adicionado uma restrição de Horizontalmente ao Centro no rótulo do projeto acima, em vez de fixar as arestas à esquerda e à direita, seria necessário adicionar esta linha aotableView:cellForRowAtIndexPath
método:Veja também
fonte
preferredMaxLayoutWidth
o celular contra o celularcontentSize
? Dessa forma, se você tiver um acessórioView ou ele foi deslocado para edição, ele ainda será levado em consideração?Eu envolvi a solução iOS7 da smileyborg em uma categoria
Decidi agrupar essa solução inteligente por @smileyborg em uma
UICollectionViewCell+AutoLayoutDynamicHeightCalculation
categoria.A categoria também corrige os problemas descritos na resposta do @ wildmonkey (carregar uma célula de uma ponta e
systemLayoutSizeFittingSize:
retornarCGRectZero
)Ele não leva em consideração nenhum cache, mas atende às minhas necessidades no momento. Sinta-se livre para copiar, colar e invadir.
UICollectionViewCell + AutoLayoutDynamicHeightCalculation.h
UICollectionViewCell + AutoLayoutDynamicHeightCalculation.m
Exemplo de uso:
Felizmente, não teremos que fazer esse jazz no iOS8, mas já está por enquanto!
fonte
[YourCell new]
e usar isso como manequim. Contanto que o código de construção do código de restrição seja acionado em sua instância, e você acione um passe de layout de forma programática, você deve estar pronto.UICollectionViews
.Aqui está a minha solução:
Você precisa informar
TableView
oestimatedHeight
antes de carregar a exibição. Caso contrário, não será capaz de se comportar como o esperado.Objetivo-C
Atualização para o Swift 4.2
fonte
estimatedRowHeight
houver variação linha por linha? devo acima ou abaixo da estimativa? usar mínimo ou máximo da altura em que usotableView
?estimatedRowHeight
, isso afeta principalmente o tamanho da barra de rolagem, nunca a altura das células reais. Seja ousado na altura que você escolher: isso afetará a animação de inserção / exclusão.A solução proposta por @smileyborg é quase perfeita. Se você tem um celular personalizado e você quer uma ou mais
UILabel
com alturas dinâmicas então o systemLayoutSizeFittingSize método combinado com AutoLayout habilitado retorna aCGSizeZero
menos que você mover todas as restrições a sua celulares da célula à sua contentView (como sugerido por @TomSwift aqui Como redimensionar superview para encaixar todas as subvisões com a execução automática? ).Para fazer isso, você precisa inserir o seguinte código na sua implementação personalizada do UITableViewCell (graças a @Adrian).
Misturar a resposta @smileyborg com isso deve funcionar.
fonte
systemLayoutSizeFittingSize
precisa ser chamado em contentView, não celularUma pegadinha importante o suficiente que eu acabei de encontrar para postar como resposta.
A resposta de @ smileyborg está correta. No entanto, se você tiver algum código no
layoutSubviews
método da sua classe de célula personalizada, por exemplo, definindo opreferredMaxLayoutWidth
, ele não será executado com este código:Isso me confundiu por um tempo. Então eu percebi que é porque eles estão apenas acionando layoutSubviews no
contentView
, não na própria célula.Meu código de trabalho é assim:
Observe que, se você estiver criando uma nova célula, tenho certeza de que não precisa ligar,
setNeedsLayout
pois ela já deve estar definida. Nos casos em que você salva uma referência em uma célula, provavelmente deve chamá-la. De qualquer maneira, não deve doer nada.Outra dica se você estiver usando subclasses de células em que está definindo coisas como
preferredMaxLayoutWidth
. Como menciona @smileyborg, "a célula da visualização da tabela ainda não teve sua largura fixa na largura da visualização da tabela". Isso é verdade, e problemas se você estiver fazendo seu trabalho em sua subclasse e não no controlador de exibição. No entanto, você pode simplesmente definir o quadro da célula neste momento usando a largura da tabela:Por exemplo, no cálculo da altura:
(Por acaso, armazene em cache essa célula específica para reutilização, mas isso é irrelevante).
fonte
Caso as pessoas ainda estejam tendo problemas com isso. Eu escrevi uma rápida postagem no blog sobre o uso do Autolayout com o UITableViews, aproveitando o Autolayout For Dynamic Cell Heights , bem como um componente de código aberto para ajudar a tornar isso mais abstrato e fácil de implementar. https://github.com/Raizlabs/RZCellSizeManager
fonte
Contanto que seu layout no seu celular seja bom.
Atualização: você deve usar o redimensionamento dinâmico introduzido no iOS 8.
fonte
tableView:cellForRowAtIndexPath:
detableView:heightForRowAtIndexPath:
agora?systemLayoutSizeFittingSize:
emtableView:cellForRowAtIndexPath:
cache o resultado, em seguida, usá-tableView:heightForRowAtIndexPath:
lo funciona bem, desde que as restrições estejam configuradas corretamente, é claro!(para o Xcode 8.x / Xcode 9.x lido na parte inferior)
Cuidado com o seguinte problema no Xcode 7.x, que pode ser uma fonte de confusão:
O Interface Builder não lida corretamente com a configuração de célula de dimensionamento automático. Mesmo que suas restrições sejam absolutamente válidas, o IB ainda reclamará e fornecerá sugestões e erros confusos. O motivo é que o IB não está disposto a alterar a altura da linha conforme suas restrições determinam (para que a célula se ajuste ao seu conteúdo). Em vez disso, mantém a altura da linha fixa e começa a sugerir que você altere suas restrições, as quais você deve ignorar .
Por exemplo, imagine que você configurou tudo bem, sem avisos, sem erros, tudo funciona.
Agora, se você alterar o tamanho da fonte (neste exemplo, estou alterando o tamanho da fonte do rótulo da descrição de 17.0 para 18.0).
Como o tamanho da fonte aumentou, o rótulo agora quer ocupar 3 linhas (antes disso estava ocupando 2 linhas).
Se o Interface Builder funcionasse conforme o esperado, ele redimensionaria a altura da célula para acomodar a nova altura da etiqueta. No entanto, o que realmente acontece é que o IB exibe o ícone vermelho de erro de layout automático e sugere que você modifique as prioridades de abraço / compactação.
Você deve ignorar esses avisos. O que você pode fazer * é alterar manualmente a altura da linha (selecione Célula> Inspetor de tamanho> Altura da linha).
Eu estava mudando essa altura, um clique de cada vez (usando o deslizante para cima / para baixo) até que os erros de seta vermelha desaparecessem! (você realmente receberá avisos amarelos; nesse ponto, vá em frente e faça 'atualizar quadros', tudo deverá funcionar).
* Observe que você não precisa realmente resolver esses erros vermelhos ou avisos amarelos no Interface Builder - em tempo de execução, tudo funcionará corretamente (mesmo que o IB mostre erros / avisos). Apenas verifique se, em tempo de execução no log do console, você não está recebendo nenhum erro de AutoLayout.
De fato, tentar sempre atualizar a altura da linha no IB é super irritante e às vezes quase impossível (devido a valores fracionários).
Para evitar os irritantes avisos IB / erros, você pode selecionar os pontos de vista envolvidos e
Size Inspector
para a propriedadeAmbiguity
escolherVerify Position Only
O Xcode 8.x / Xcode 9.x parece (às vezes) fazer coisas de maneira diferente do Xcode 7.x, mas ainda incorretamente. Por exemplo, mesmo quando
compression resistance priority
/hugging priority
está definido como necessário (1000), o Interface Builder pode esticar ou recortar um rótulo para caber na célula (em vez de redimensionar a altura da célula para caber no rótulo). E, nesse caso, ele pode nem mostrar avisos ou erros de AutoLayout. Ou, às vezes, faz exatamente o que o Xcode 7.x fez, descrito acima.fonte
Para definir a dimensão automática para a altura da linha e a altura estimada da linha, verifique as etapas a seguir, efetue a cota automática para o layout da altura da célula / linha.
UITableViewAutomaticDimension
a rowHeight e estimadoRowHeightheightForRowAt
e retornar um valorUITableViewAutomaticDimension
para ele)-
Objetivo C:
Rápido:
Para instância de rótulo em UITableviewCell
Nota : Se você tiver mais de um rótulo (UIElements) com comprimento dinâmico, o qual deverá ser ajustado de acordo com o tamanho do conteúdo: Ajuste 'Prioridade de resistência a compressão e compressão de conteúdo' para rótulos que você deseja expandir / compactar com prioridade mais alta.
fonte
tableView: heightForRow
fonte de dados.tableView: heightForRow
. (para iOS 10tableView: heightForRow
é necessário)tableView: heightForRow
..if (indexPath.row == 0) { return 100} else { return UITableView.automaticDimension }
Como @ Bob-Spryn, me deparei com uma pegadinha importante o suficiente para postar isso como resposta.
Eu lutei com a resposta de @ smileyborg por um tempo. O problema que eu encontrei é se você definiu sua célula protótipo no IB com elementos adicionais (
UILabels
,UIButtons
etc.) no IB quando você instancia a célula com [[YourTableViewCellClass alloc] init]
ela não instancia todos os outros elementos nessa célula, a menos que você código escrito para fazer isso. (Eu tive uma experiência semelhante cominitWithStyle
.)Para que o storyboard instancie todos os elementos adicionais, obtenha sua célula
[tableView dequeueReusableCellWithIdentifier:@"DoseNeeded"]
(Não,[tableView dequeueReusableCellWithIdentifier:forIndexPath:]
pois isso causará problemas interessantes.) Quando você fizer isso, todos os elementos que você definiu no IB serão instanciados.fonte
Altura da célula da exibição dinâmica da tabela e layout automático
Uma boa maneira de resolver o problema com o Layout automático do storyboard:
fonte
fonte
Outra "solução": pule toda essa frustração e use um UIScrollView para obter um resultado que pareça idêntico ao UITableView.
Essa foi a "solução" dolorosa para mim, depois de ter gasto literalmente mais de 20 horas muito frustrantes tentando criar algo parecido com o que o smileyborg sugeriu e falhou ao longo de muitos meses e três versões dos lançamentos da App Store.
Meu ponto de vista é que, se você realmente precisa do suporte ao iOS 7 (para nós, é essencial), a tecnologia é muito quebradiça e você arranca os cabelos. E que o UITableView é um exagero completo, a menos que você esteja usando alguns dos recursos avançados de edição de linha e / ou precise realmente suportar mais de 1000 "linhas" (em nosso aplicativo, na realidade, nunca é mais do que 20 linhas).
O bônus adicional é que o código fica incrivelmente simples em comparação com toda a porcaria de delegado e para trás e para a frente que acompanha o UITableView. É apenas um único loop de código no viewOnLoad que parece elegante e fácil de gerenciar.
Aqui estão algumas dicas sobre como fazê-lo:
Usando o Storyboard ou um arquivo de ponta, crie um ViewController e uma visualização raiz associada.
Arraste sobre um UIScrollView para a visualização raiz.
Adicione restrições superiores, inferiores, esquerda e direita à exibição de nível superior, para que o UIScrollView preencha toda a exibição raiz.
Adicione um UIView dentro do UIScrollView e chame-o de "contêiner". Adicione restrições superior, inferior, esquerda e direita ao UIScrollView (seu pai). TRUQUE DE CHAVE: Adicione também restrições de "Larguras iguais" para vincular o UIScrollView e o UIView.
NOTA: Você receberá um erro "a exibição de rolagem possui altura de conteúdo rolável ambígua" e que o UIView do contêiner deve ter uma altura de 0 pixels. Nenhum dos erros parece importar quando o aplicativo está sendo executado.
Crie arquivos e controladores de ponta para cada uma das suas "células". Use UIView não UITableViewCell.
No seu ViewController raiz, você basicamente adiciona todas as "linhas" ao UIView do contêiner e adiciona programaticamente restrições que vinculam suas bordas esquerda e direita à exibição do contêiner, suas bordas superiores à parte superior da exibição do contêiner (para o primeiro item) ou à anterior célula. Em seguida, vincule a célula final ao fundo do contêiner.
Para nós, cada "linha" está em um arquivo de ponta. Portanto, o código se parece com isso:
E aqui está o código para UITools.addViewToTop:
A única "pegadinha" que encontrei com essa abordagem até agora é que o UITableView possui um bom recurso de cabeçalhos de seção "flutuantes" na parte superior da exibição enquanto você rola. A solução acima não fará isso, a menos que você adicione mais programação, mas, no nosso caso particular, esse recurso não era 100% essencial e ninguém notou quando foi embora.
Se você deseja divisórias entre as células, basta adicionar uma visualização UIV de 1 pixel na parte inferior da "célula" personalizada que se parece com um divisor.
Certifique-se de ativar "devoluções" e "devolver verticalmente" para que o controle de atualização funcione e, portanto, pareça mais uma exibição de tabela.
O TableView mostra algumas linhas e divisórias vazias no seu conteúdo, se ele não preencher a tela inteira, onde esta solução não. Mas, pessoalmente, prefiro que essas linhas vazias não estivessem lá de qualquer maneira - com altura variável da célula, sempre parecia "buggy" para mim ter as linhas vazias lá.
Esperamos que algum outro programador leia meu post ANTES de perder mais de 20 horas tentando descobrir isso com o Table View em seu próprio aplicativo. :)
fonte
Eu tive que usar visualizações dinâmicas (visualizações de configuração e restrições por código) e quando desejei definir a largura do rótulo preferencialMaxLayoutWidth era 0. Portanto, eu tenho uma altura de célula errada.
Então eu adicionei
antes de executar
Depois que a largura da etiqueta estava como o esperado e a altura dinâmica foi calculada corretamente.
fonte
Digamos que você tenha uma célula com uma subvisão e deseje que a altura da célula seja alta o suficiente para abranger a subvisão + preenchimento.
1) Defina a restrição inferior da subvisão igual à cell.contentView menos o preenchimento desejado. Não defina restrições na célula ou cell.contentView em si.
2) Defina a
rowHeight
propriedade do tableView outableView:heightForRowAtIndexPath:
comoUITableViewAutomaticDimension
.3) Defina a
estimatedRowHeight
propriedade tableView ou otableView:estimatedHeightForRowAtIndexPath:
melhor palpite da altura.É isso aí.
fonte
Se você faz o layout programaticamente, eis o que considerar no iOS 10 usando âncoras no Swift.
Existem três regras / etapas
NÚMERO 1: defina essas duas propriedades da visualização da tabela em viewDidLoad, a primeira informa à visualização da tabela que deve esperar tamanhos dinâmicos em suas células; a segunda é apenas para permitir que o aplicativo calcule o tamanho do indicador da barra de rolagem, ajudando a desempenho.
NÚMERO 2: É importante que você inclua as subvisões no contentView da célula, e não na visualização, e também use seu layoutsmarginguide para ancorar as subviews nas partes superior e inferior; este é um exemplo prático de como fazê-lo.
Crie um método que adicione as subvisões e execute o layout, chame-o no método init.
NÚMERO 3: NÃO CHAMA O MÉTODO:
Se você fizer isso, substituirá sua implementação.
Siga estas 3 regras para células dinâmicas nas visualizações de tablaturas.
aqui está uma implementação funcional https://github.com/jamesrochabrun/MinimalViewController
fonte
Se você tem uma corda longa . por exemplo, um que não tem uma quebra de linha. Então você pode ter alguns problemas.
A correção "alegada" é mencionada pela resposta aceita e poucas outras respostas. Você só precisa adicionar
Acho a resposta de Suragh a mais completa e concisa , portanto não confusa.
Embora não explique por que essas mudanças são necessárias. Vamos fazer isso.
Solte o seguinte código em um projeto.
Observe que eu não adicionei nenhuma restrição de tamanho . Eu apenas adicionei restrições centerX, centerY. Mas ainda assim a etiqueta será dimensionada corretamente Por quê?
Por causa de
contentSize
.Para melhor processar isso, primeiro mantenha a etapa 0 e depois comente as etapas 1 a 6. Vamos
setupLayout()
ficar. Observe o comportamento.Descomente a etapa 1 e observe.
Em seguida, remova o comentário do passo 2 e observe.
Faça isso até que você descomente todas as 6 etapas e observe o comportamento delas.
O que pode concluir disso tudo? Quais fatores podem mudar o
contenSize
?\n
, a largura do intrinsicContentSize será a largura máxima de todas as linhas. Se uma linha possui 25 caracteres, outra possui 2 caracteres e outra possui 21 caracteres, sua largura será calculada com base nos 25 caracteresnumberOfLines
como0
diferente, caso contrário não terá várias linhas. VocênumberOfLines
ajustará a altura do seu conteúdo intrínsecoFazendo ajustes: imagine que, com base no seu texto, a largura
200
e a altura do seu intrinsicContentSize eram100
, mas você queria limitar a largura ao contêiner do rótulo, o que você fará? A solução é configurá-lo para a largura desejada. Você faz isso configurandopreferredMaxLayoutWidth
para130
que seu novo intrinsicContentSize tenha uma largura aproximada130
. Obviamente, a altura seria maior do que100
porque você precisaria de mais linhas. Dito isto, se suas restrições estiverem definidas corretamente, você não precisará usá-las! Para mais informações, consulte esta resposta e seus comentários. Você só precisa usarpreferredMaxLayoutWidth
se não houver restrições que restrinjam a largura / altura, como pode ser dito "não envolva o texto a menos que exceda apreferredMaxLayoutWidth
". Mas, com 100% de certeza se você definir o líder / fuga enumberOfLines
para0
, em seguida, você é bom! Longa história curta maioria respostas aqui que recomendo usá-lo está errado! Você não precisa dele. Precisando é um sinal de que suas limitações não estão definidos corretamente ou você simplesmente não tem restriçõesTamanho da fonte: Observe também que, se você aumentar o fontSize, a altura do intrinsicContentSize aumentará. Eu não mostrei isso no meu código. Você pode tentar isso sozinho.
Então, de volta ao seu exemplo tableViewCell:
Tudo que você precisa fazer é:
numberOfLines
como0
preferredMaxLayoutWidth
.fonte
No meu caso, eu tenho que criar uma célula personalizada com uma imagem que vem do servidor e pode ter qualquer largura e altura. E dois UILabels com tamanho dinâmico (largura e altura)
Eu consegui o mesmo aqui na minha resposta com autolayout e programaticamente:
Basicamente acima, a resposta @smileyBorg ajudou, mas o systemLayoutSizeFittingSize nunca funcionou para mim. Na minha abordagem:
1. Não há uso da propriedade de cálculo automático de altura da linha. 2. Sem uso de altura estimada 3. Não há necessidade de atualizações desnecessárias. Uso 4.No da largura máxima preferida automática do layout. 5. Nenhum uso de systemLayoutSizeFittingSize (deve ter uso, mas não está funcionando para mim, não sei o que está fazendo internamente), mas o meu método - (float) getViewHeight está funcionando e sei o que está fazendo internamente.
É possível ter alturas diferentes em uma célula UITableView quando eu uso várias maneiras diferentes de exibir a célula?
fonte
No meu caso, o preenchimento foi por causa das alturas sectionHeader e sectionFooter, em que o storyboard me permitiu alterá-lo para o mínimo 1. Portanto, no método viewDidLoad:
fonte
Eu apenas fiz algumas tentativas e erros estúpidos com os 2 valores de
rowHeight
eestimatedRowHeight
pensei que poderia fornecer algumas dicas de depuração:Se você definir os dois OU apenas definir
estimatedRowHeight
, obterá o comportamento desejado:É recomendável que você faça o melhor para obter a estimativa correta, mas o resultado final não é diferente. Isso afetará apenas o seu desempenho.
Se você definir apenas o rowHeight, ou seja, faça apenas:
seu resultado final não seria o desejado:
Se você definir
estimatedRowHeight
como 1 ou menor, ocorrerá falha independentemente dorowHeight
.Fui com a seguinte mensagem de erro:
fonte
Em relação à resposta aceita por @smileyborg, eu encontrei
não ser confiável em alguns casos em que as restrições são ambíguas. Melhor forçar o mecanismo de layout a calcular a altura em uma direção, usando a categoria auxiliar no UIView abaixo:
Onde w: é a largura da tableview
fonte
Basta adicionar essas duas funções no seu controlador de exibição, pois isso resolverá o seu problema. Aqui, list é uma matriz de strings que contém sua string de cada linha.
fonte
fonte
Se a altura da célula for dinâmica pelo conteúdo, você deve contá-la com precisão e retornar o valor da altura antes que a célula seja renderizada. Uma maneira fácil é definir o método de contagem no código de célula da visualização de tabela para o controlador chamar no método delegado de altura da célula da tabela. Não se esqueça de contar a largura real do quadro da célula (o padrão é 320) se a altura depender da largura da tabela ou tela. Ou seja, no método delegado de altura da célula da tabela, use cell.frame para corrigir primeiro a largura da célula e, em seguida, chame o método de altura de contagem definido na célula para obter o valor adequado e retorná-lo .
PS. O código para gerar o objeto da célula pode ser definido em outro método para chamar o método delegado da célula da visualização de tabela diferente.
fonte
UITableView.automaticDimension
pode ser definido através do Interface Builder:Xcode> Storyboard> Inspetor de tamanho
Célula de exibição de tabela> Altura da linha> Automático
fonte
mais uma solução iOs7 + iOs8 no Swift
fonte
cellForRowAtIndexPath
, a célula ainda não está definida neste momento.