Android Dev Summit, October 23-24: two days of technical content, directly from the Android team. Sign-up for livestream updates.

Criar uma IU flexível

Ao projetar o aplicativo para ser compatível com uma grande variedade de tamanhos de tela, você poderá reutilizar os Fragments em diferentes configurações de layout para otimizar a experiência do usuário com base no espaço de tela disponível.

Por exemplo, em um celular, pode ser apropriado exibir somente um Fragment por vez para uma interface do usuário de painel simples. Por outro lado, em tablets que têm uma tela maior para exibir mais informações ao usuário, é melhor arranjar Fragments lado a lado.

Figura 1. Dois Fragments, exibidos em diferentes configurações para a mesma atividade em diferentes tamanhos de tela. Em uma tela grande, ambos os Fragments se encaixam lado a lado. No entanto, em um celular, somente um Fragment se encaixa por vez. Assim, os Fragments devem substituir-se mutuamente à medida que o usuário navega.

A classe FragmentManager oferece métodos que permitem a adição, a remoção e a substituição de Fragments em uma atividade em tempo de execução para criar uma experiência dinâmica.

Para mais informações sobre como implementar Fragments, consulte os recursos a seguir.

Adicionar um Fragment a uma atividade em tempo de execução

Em vez de definir os Fragments para uma atividade no arquivo de layout, como mostrado na lição anterior com o elemento <fragment>, você pode adicionar um Fragment à atividade durante o tempo de execução dela. Isso é necessário se você planeja alterar Fragments durante a vida de uma atividade.

Para realizar uma transação como adicionar ou remover um Fragment, você precisa usar a FragmentManager para criar uma FragmentTransaction, que oferece APIs para adicionar, remover, substituir e realizar outras transações de Fragments.

Caso sua atividade permita que os Fragments sejam removidos e substituídos, adicione os Fragments iniciais à atividade durante o método onCreate().

Uma regra importante ao lidar com Fragments, especialmente ao adicioná-los em tempo de execução, é que o layout da atividade precisa incluir uma View de contêiner na qual você pode inserir o Fragment.

O layout a seguir é uma alternativa ao layout que exibe somente um Fragment por vez, mostrado na lição anterior. Para substituir um Fragment por outro, o layout da atividade inclui um FrameLayout vazio, que age como o contêiner do Fragment.

Observe que o nome do arquivo é o mesmo que o do arquivo de layout da lição anterior, mas o diretório de layout não tem o qualificador large, e esse layout é usado quando a tela do dispositivo é menor que grande porque a tela não exibe dois Fragments ao mesmo tempo.

res/layout/news_articles.xml:

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    

Dentro da atividade, chame getSupportFragmentManager() para conseguir um FragmentManager usando as APIs da Biblioteca de Suporte. Em seguida, chame beginTransaction() para criar uma FragmentTransaction e add() para adicionar um Fragment.

Você pode realizar várias transações de Fragments para a atividade usando a mesma FragmentTransaction. Quando estiver pronto para fazer as mudanças, você precisará chamar commit().

Por exemplo, veja como adicionar um Fragment ao layout anterior:

Kotlin

    import android.os.Bundle
    import android.support.v4.app.FragmentActivity

    class MainActivity : FragmentActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.news_articles)

            // Check that the activity is using the layout version with
            // the fragment_container FrameLayout
            if (findViewById(R.id.fragment_container) != null) {

                // However, if we're being restored from a previous state,
                // then we don't need to do anything and should return or else
                // we could end up with overlapping fragments.
                if (savedInstanceState != null) {
                    return;
                }

                // Create a new Fragment to be placed in the activity layout
                val firstFragment = HeadlinesFragment()

                // In case this activity was started with special instructions from an
                // Intent, pass the Intent's extras to the fragment as arguments
                firstFragment.arguments = intent.extras

                // Add the fragment to the 'fragment_container' FrameLayout
                supportFragmentManager.beginTransaction()
                        .add(R.id.fragment_container, firstFragment).commit()
            }
        }
    }
    

Java

    import android.os.Bundle;
    import android.support.v4.app.FragmentActivity;

    public class MainActivity extends FragmentActivity {
        @Override
        public void onCreate(Bundle savedInstanceState?) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.news_articles);

            // Check that the activity is using the layout version with
            // the fragment_container FrameLayout
            if (findViewById(R.id.fragment_container) != null) {

                // However, if we're being restored from a previous state,
                // then we don't need to do anything and should return or else
                // we could end up with overlapping fragments.
                if (savedInstanceState != null) {
                    return;
                }

                // Create a new Fragment to be placed in the activity layout
                HeadlinesFragment firstFragment = new HeadlinesFragment();

                // In case this activity was started with special instructions from an
                // Intent, pass the Intent's extras to the fragment as arguments
                firstFragment.setArguments(getIntent().getExtras());

                // Add the fragment to the 'fragment_container' FrameLayout
                getSupportFragmentManager().beginTransaction()
                        .add(R.id.fragment_container, firstFragment).commit();
            }
        }
    }
    

Como o Fragment foi adicionado ao contêiner FrameLayout em tempo de execução, em vez de definido no layout da atividade com um elemento <fragment>, a atividade pode remover o Fragment e substituí-lo por um diferente.

Substituir um Fragment por outro

O procedimento para substituir um Fragment é semelhante ao de adicionar, mas requer o método replace(), em vez de add().

Lembre-se de que, ao realizar transações de Fragment, como substituição ou remoção, é apropriado permitir que o usuário retorne e "desfaça" a alteração. Para permitir que o usuário retorne em transações de Fragment, você precisa chamar addToBackStack() antes de acionar a FragmentTransaction.

Observação: ao remover ou substituir um Fragment e adicionar a transação à pilha de retorno, o Fragment removido será pausado (não destruído). Se o usuário navegar de volta para restaurar o Fragment, ele será reiniciado. Se você não adicionar a transação à pilha de retorno, o Fragment será destruído quando for removido ou substituído.

Exemplo de substituição de um Fragment por outro:

Kotlin

    // Create fragment and give it an argument specifying the article it should show
    val newFragment = ArticleFragment()
    Bundle args = Bundle()
    args.putInt(ArticleFragment.ARG_POSITION, position)
    newFragment.arguments = args

    val transaction = supportFragmentManager.beginTransaction().apply {
      // Replace whatever is in the fragment_container view with this fragment,
      // and add the transaction to the back stack so the user can navigate back
      replace(R.id.fragment_container, newFragment)
      addToBackStack(null)
    }

    // Commit the transaction
    transaction.commit();
    

Java

    // Create fragment and give it an argument specifying the article it should show
    ArticleFragment newFragment = new ArticleFragment();
    Bundle args = new Bundle();
    args.putInt(ArticleFragment.ARG_POSITION, position);
    newFragment.setArguments(args);

    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

    // Replace whatever is in the fragment_container view with this fragment,
    // and add the transaction to the back stack so the user can navigate back
    transaction.replace(R.id.fragment_container, newFragment);
    transaction.addToBackStack(null);

    // Commit the transaction
    transaction.commit();
    

O método addToBackStack() tem um parâmetro de string opcional que especifica um nome único para a transação. O nome não é necessário a menos que você planeje realizar operações de Fragment avançadas usando as APIs FragmentManager.BackStackEntry.