Estou um pouco confuso sobre os papéis de forceLayout()
, requestLayout()
e invalidate()
métodos da View
classe.
Quando eles serão chamados?
android
android-layout
android-view
sdabet
fonte
fonte
TextView
. Pensei que talvez eles quisessem desenharView
pela última vez antes de alterar seus parâmetros relacionados ao layout, mas realmente não faz sentido se pensarmos sobre essas chamadas serem chamadas na ordem diferente (e elas ligaminvalidate()
logo depoisrequestLayout()
emTextView
também). Talvez mereça outra pergunta no StackOverflow :)?invalidate()
erequestLayout()
) corretamente. O objetivo desses métodos é dizerView
que tipo de invalidação (como você a chamou) aconteceu. Não é o caso deView
decidir qual caminho seguir depois de chamar um desses métodos. A lógica por trás da escolha doView
caminho do ciclo de vida é a escolha do método apropriado para se chamar. Se houver algo relacionado à alteração de tamanho -requestLayout()
deve ser chamado, se houver apenas uma alteração visual sem um tamanho alterado - você deve ligarinvalidate()
.View
de alguma forma, por exemplo, você atualizaLayoutParams
umView
e modifica-o, mas NÃO chama umrequestLayout
ousetLayoutParams
(que chamarequestLayout
internamente), pode ligar oinvalidate()
quanto quiser e oView
não passará pelo processo de layout da medida e, portanto, não mudará de tamanho. Se você não informarView
que seu tamanho foi alterado (com umarequestLayout
chamada de método), oView
assumirá que não, e oonMeasure
eonLayout
não será chamado.invalidate()
A chamada
invalidate()
é feita quando você deseja agendar um redesenho da exibição. Isso resultará emonDraw
uma chamada eventualmente (em breve, mas não imediatamente). Um exemplo de quando uma visualização personalizada seria chamada é quando uma propriedade de cor de texto ou plano de fundo é alterada.A vista será redesenhada, mas o tamanho não será alterado.
requestLayout()
Se algo na sua visualização mudar, afetando o tamanho, você deve ligar
requestLayout()
. Isso será acionadoonMeasure
eonLayout
não apenas para essa visualização, mas também para as visualizações pai.Não
requestLayout()
é garantido que aonDraw
chamada resulte em (ao contrário do que o diagrama na resposta aceita), por isso é geralmente combinada cominvalidate()
.Um exemplo disso é quando um rótulo personalizado tem sua propriedade de texto alterada. O rótulo mudaria de tamanho e, portanto, precisaria ser medido novamente e redesenhado.
forceLayout()
Quando há um
requestLayout()
chamado em um grupo de visualizações pai, não é necessário recalcular e retransmitir suas visualizações filho. No entanto, se uma criança deve ser incluída na medida e na retransmissão, você pode chamáforceLayout()
-la.forceLayout()
só funciona em um filho se ocorrer em conjunto com umrequestLayout()
pai direto. A chamadaforceLayout()
por si só não terá efeito, pois não aciona umarequestLayout()
árvore da visualização.Leia estas perguntas e respostas para obter uma descrição mais detalhada de
forceLayout()
.Um estudo mais aprofundado
View
Código fontefonte
requestLayout()
antes,invalidate()
se quiser. Ninguém faz um layout ou desenha imediatamente. Em vez disso, eles definem sinalizadores que acabarão resultando em retransmissão e redesenho.Aqui você pode encontrar algumas respostas: http://developer.android.com/guide/topics/ui/how-android-draws.html
Para mim, uma chamada
invalidate()
atualiza apenas a exibição e uma chamadarequestLayout()
atualiza a exibição e calcula o tamanho da exibição na tela.fonte
você usa invalidate () em uma exibição que deseja redesenhar, fará com que seu onDraw (Canvas c) seja invocado e requestLayout () fará com que todo o layout de renderização (fase de medição e fase de posicionamento) seja executado novamente. Você deve usá-lo se estiver alterando o tamanho da visualização filho em tempo de execução, mas apenas em casos específicos, como restrições da visualização pai (com isso quero dizer que a altura ou largura do pai são WRAP_CONTENT e, portanto, correspondam à medida dos filhos antes que eles possam envolvê-los novamente)
fonte
Esta resposta não está correta
forceLayout()
.Como você pode ver no código
forceLayout()
, apenas marca a exibição como "precisa de uma retransmissão", mas ela não agenda nem aciona essa retransmissão. A retransmissão não ocorrerá até que, em algum momento no futuro, o pai da exibição tenha sido apresentado por algum outro motivo.Há também um problema muito maior ao usar
forceLayout()
erequestLayout()
:Digamos que você tenha chamado
forceLayout()
uma visualização. Agora, ao chamarrequestLayout()
um descendente dessa visão, o Android recursivamente chamarárequestLayout()
os ancestrais desse descendente. O problema é que ele interromperá a recursão na exibição para a qual você ligouforceLayout()
. Portanto, arequestLayout()
chamada nunca alcançará a raiz da visualização e, portanto, nunca agendará um passe de layout. Uma subárvore inteira da hierarquia de exibição está aguardando um layout, e chamarrequestLayout()
qualquer visualização dessa subárvore não causará um layout. Apenas chamarrequestLayout()
qualquer visualização fora dessa subárvore interromperá o feitiço.Eu consideraria a implementação de
forceLayout()
(e como isso afetarequestLayout()
a ser quebrado e você nunca deve usar essa função em seu código.fonte
View
e executando o problema sozinho e depurando-o.forceLayout()
API: na verdade, não força uma passagem de layout, apenas altera uma sinalização que está sendo observadaonMeasure()
, masonMeasure()
não será chamada a menos querequestLayout()
um explícitoView#measure()
seja chamado. Isso significa queforceLayout()
deve ser emparelhadorequestLayout()
. Por outro lado, por que executarforceLayout()
se ainda preciso executarrequestLayout()
?requestLayout()
faz tudo o queforceLayout()
também faz.forceLayout
faz sentido. Então, no final, é muito mal nomeado e documentado.invalidate()
--->onDraw()
do thread da interface do usuáriopostInvalidate()
--->onDraw()
do segmento de segundo planorequestLayout()
--->onMeasure()
eonLayout()
E não necessariamenteonDraw()
forceLayout()
--->onMeasure()
eonLayout()
APENAS SE o pai direto chamourequestLayout()
.fonte