Por que o LayoutInflater ignora os parâmetros de layout layout_width e layout_height que eu especifiquei?

168

Tive muitos problemas para fazer com que o LayoutInflater funcionasse conforme o esperado e outras pessoas também: Como usar o layoutinflator para adicionar visualizações no tempo de execução? .

Por que o LayoutInflater ignora os parâmetros de layout que eu especifiquei? Por exemplo, por que o layout_widthe layout_heightvalores do meu XML recursos não honrado?

andig
fonte
É verdade - isso dói ou escolhi o lugar errado? Apenas pensei em compartilhar meus resultados. Devo admitir que os tutoriais não são mencionados especificamente na página de
perguntas
3
veja o último parágrafo da primeira pergunta no FAQ. publique-o como uma pergunta e, em seguida, publique o tutorial como uma resposta. é claro, você pode editar esta pergunta recortando e colando o tutorial na resposta. Vou votar se você corrigir isso.
bigstones

Respostas:

381

Investiguei esse problema, consultando os documentos LayoutInflater e configurando um pequeno projeto de demonstração de amostra. Os tutoriais a seguir mostram como preencher dinamicamente um layout usando LayoutInflater.

Antes de começarmos, veja como são os LayoutInflater.inflate()parâmetros:

  • resource : ID para carregar um recurso de layout XML (por exemplo, R.layout.main_page)
  • raiz : visualização opcional para ser o pai da hierarquia gerada (se attachToRootfor true) ou simplesmente um objeto que fornece um conjunto de LayoutParamsvalores para a raiz da hierarquia retornada (se attachToRootfor false).
  • attachToRoot : se a hierarquia inflada deve ser anexada ao parâmetro raiz? Se falso, root será usado apenas para criar a subclasse correta da LayoutParamsvisualização raiz no XML.

  • Retorna : a visão raiz da hierarquia inflada. Se a raiz foi fornecida e attachToRooté true, isso é raiz; caso contrário, é a raiz do arquivo XML inflado.

Agora, para o layout e o código de amostra.

Layout principal ( main.xml):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</LinearLayout>

Adicionado neste contêiner é um TextView separado, visível como um pequeno quadrado vermelho se os parâmetros de layout forem aplicados com êxito a partir de XML ( red.xml):

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="25dp"
    android:layout_height="25dp"
    android:background="#ff0000"
    android:text="red" />

Agora LayoutInflateré usado com várias variações de parâmetros de chamada

public class InflaterTest extends Activity {

    private View view;

    @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);

      setContentView(R.layout.main);
      ViewGroup parent = (ViewGroup) findViewById(R.id.container);

      // result: layout_height=wrap_content layout_width=match_parent
      view = LayoutInflater.from(this).inflate(R.layout.red, null);
      parent.addView(view);

      // result: layout_height=100 layout_width=100
      view = LayoutInflater.from(this).inflate(R.layout.red, null);
      parent.addView(view, 100, 100);

      // result: layout_height=25dp layout_width=25dp
      // view=textView due to attachRoot=false
      view = LayoutInflater.from(this).inflate(R.layout.red, parent, false);
      parent.addView(view);

      // result: layout_height=25dp layout_width=25dp 
      // parent.addView not necessary as this is already done by attachRoot=true
      // view=root due to parent supplied as hierarchy root and attachRoot=true
      view = LayoutInflater.from(this).inflate(R.layout.red, parent, true);
    }
}

Os resultados reais das variações de parâmetros estão documentados no código.

SINOPSE: Chamar LayoutInflatersem especificar leads raiz para aumentar a chamada, ignorando os parâmetros de layout do XML. A chamada inflar com raiz não é igual nulle attachRoot=truecarrega os parâmetros de layout, mas retorna o objeto raiz novamente, o que impede outras alterações de layout no objeto carregado (a menos que você possa encontrá-lo usando findViewById()). A convenção de chamada que você provavelmente gostaria de usar é, portanto, esta:

loadedView = LayoutInflater.from(context)
                .inflate(R.layout.layout_to_load, parent, false);

Para ajudar com problemas de layout, o Inspetor de layout é altamente recomendado.

andig
fonte
20
Excelente resposta. Trabalha no Android há 3 anos e conta e ainda tem algo a aprender com isso.
Reuben Scratton
Oi, existe alguma maneira de fazer a mesma coisa com o código java em vez de inflar com R.layout. porque eu não tenho layout. Eu criei a visualização com código java e quero adicionar a mesma visualização por 300 vezes.
Raj
1
@andig: Activityé uma subclasse de Contexte os exemplos da resposta estão no escopo de Activity, portanto, para simplificá-lo, substituí getBaseContext()-o thispor, para o bem desta resposta, é equivalente.
Marcin Orlowski
5
container possui layout_width e layout_height definidos como "match_parent"; o comentário diz "// resultado: layout_height = wrap_content layout_width = match_parent". Estou faltando sth?
Marian Paździoch
1
Obrigado por fazer a pesquisa e compartilhar os resultados! Além disso, eu segunda questão de Marian.
LarsH 21/09/15
5

andig está correto que um motivo comum para LayoutInflater ignorar seus layout_params seria porque uma raiz não foi especificada. Muitas pessoas pensam que você pode passar nulo para root. Isso é aceitável para alguns cenários, como uma caixa de diálogo, em que você não tem acesso à raiz no momento da criação. Uma boa regra a seguir, no entanto, é que, se você tiver root, forneça ao LayoutInflater.

Eu escrevi um post detalhado sobre isso que você pode conferir aqui:

https://www.bignerdranch.com/blog/understanding-androids-layoutinflater-inflate/

seanjfarrell
fonte
1
This is acceptable for a few scenarios such as a dialogque era tudo que eu precisava
rookieDeveloper
0

quero adicionar à resposta principal acima
Eu tentei segui-lo, mas meu recyclerView começou a esticar todos os itens para uma tela,
eu tive que adicionar a próxima linha depois de inflar para alcançar o objetivo

itemLayoutView.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT));

Eu já adicionei esses parâmetros por xml, mas não funcionou corretamente
e com esta linha está tudo ok

Kirguduck
fonte