Fragment é um elemento especial dos layouts para Android que pode ser incluído dentro de uma Activity. Onde isso é usado? Dê uma olhada em vários aplicativos, como o YouTube ou o VLC: todos usam Fragments em alguma parte.
ESTE É UM POST ANTIGO
Este post foi importado do antigo blog e o seu conteúdo não foi revisado. O conteúdo deve estar desatualizado e a formatação pode apresentar problemas.
Os Fragments são bastante utilizados para criar uma navegação por abas (como nós também vamos fazer nesse exemplo), que é muito útil para exibir informações diferentes mas relacionadas ao mesmo assunto. O aplicativo do Google Play, por exemplo, utiliza um Fragment para exibir os aplicativos em destaque, outro para exibir os principais apps gratuitos, mais um Fragment para mostrar os apps pagos, outro para os novos, para as tendências, etc.
Mas vamos ao que interessa. Vamos alterar o exemplo do post anterior para incluir Fragments.
Vamos criar dois Fragments: FieldsFragment e ViewFragment, as duas estendendo de com.actionbarsherlock.app.SherlockFragment. Por enquanto vamos deixá-las vazias e criar o layout delas.
Um Fragment pode incluir um layout de qualquer formato com qualquer quantidade de widgets. O único limite é a imaginação (e talvez a falta de criatividade). Eu vou fazer um exemplo simples aqui apenas para demonstrar. Vou criar dois arquivos de layout na pasta res/layout (o tipo Android XML Layout File na janela do assistente). Os layouts que eu criei ficaram assim (clique para ampliar a imagem e para expandir os códigos XML):
<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <EditText android:id="@+id/editName" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="8dip" android:layout_weight="1" android:ems="10" android:hint="Nome" android:inputType="textPersonName" > <requestFocus /> </EditText> <EditText android:id="@+id/editEmail" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="8dp" android:layout_weight="1" android:ems="10" android:hint="E-mail" android:inputType="textEmailAddress" /> </LinearLayout> </ScrollView>
<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="8dp" android:text="[falta_de_criatividade mode ON] Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas vitae mollis mauris. Nulla quis magna ac diam fermentum sollicitudin eu ac leo. Nunc cursus tempus viverra. Nam ut nisl tellus. Cras aliquet mi a mauris venenatis in gravida turpis egestas. Duis et blandit magna. Proin urna lorem, cursus eget laoreet non, ullamcorper ut dui. Duis ligula nisi, adipiscing non porta a, dignissim nec risus." /> </FrameLayout> </ScrollView>
Agora vamos carregar nosso layout nos Fragments. Para isso, sobrescrevemos o método onCreateView:
package seu.dominio.sherlocktest; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.actionbarsherlock.app.SherlockFragment; public class FieldsFragment extends SherlockFragment { /** Método executado para inflar o layout do nosso Fragment */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup group, Bundle saved) { // carrega o layout a partir do arquivo fields.xml return inflater.inflate(R.layout.fields, group, false); } }
A mesma coisa para o ViewFragment, mas carregando o segundo layout (view). Depois de criar os Fragments, falta apenas incluí-los na Activity. Mãos à obra.
Abra o MainActivity.java. Para utilizar os Fragments precisamos estender de outra classe diferente de SherlockActivity, precisamos usar a SherlockFragmentActivity, então altere o import e a definição da classe MainActivity para referenciá-la.
Vamos alterar o método onCreate:
// imports necessários no início do arquivo: import android.support.v4.app.FragmentTransaction; import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.ActionBar.Tab; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActionBar bar = getSupportActionBar(); bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); // Tab listener para executar a troca de abas ActionBar.TabListener tabListener = new ActionBar.TabListener() { // evento de seleção de uma aba @Override public void onTabSelected(Tab tab, FragmentTransaction ft) { // primeira aba if (tab.getPosition() == 0) { ft.replace(android.R.id.content, new FieldsFragment()); } // segunda aba else { ft.replace(android.R.id.content, new ViewFragment()); } } @Override public void onTabUnselected(Tab tab, FragmentTransaction ft) {} @Override public void onTabReselected(Tab tab, FragmentTransaction ft) {} }; bar.addTab(bar.newTab().setText("FieldsFragment").setTabListener(tabListener)); bar.addTab(bar.newTab().setText("ViewFragment").setTabListener(tabListener)); }
Isso é o básico do básico do básico para rodar um exemplo básico que não faz nada além do básico (na verdade, não faz nada, nem mesmo o básico). Mas pelo menos está rodando no emulador:
Tem muita coisa hardcoded nesse exemplo, como o TabListener. Essa é apenas uma ideia bem básica de como implementar essa funcionalidade do jeito mais simples, rápido e fácil possível (eu prometi o post ainda para 2012 e tive que correr pra conseguir terminar) – mas não é o melhor. Utilize o código desse post por sua própria conta e risco.
Para fazer algo realmente muito bem feito precisaríamos mais algumas 3 ou 4 classes (pagers, adapters, um PagerAdapter, …), e isso fica um pouco extenso demais para mostrar nesse post. Talvez no próximo, incluindo também o efeito de swipe. E futuramente ainda o SlidingMenu. 😉
Bom, já estou cheio de tarefas para 2013, então que 2012 termine logo e até ano que vem!
Amigo, tentei fazer o seu exemplo não consegui.
Meu projeto possui 2 classes R.java e quando chamo o layout de dentro do SherlockFragment ele não acha meu layout. O que pode ser?
Olá Wilian,
Duas classes R.java é estranho, só poderia existir uma… Já tentou limpar o projeto (Project > Clean), assim ele deve recriar essa classe.
Eduardo,
tinha a classe R do meu projeto e quando importei a ActionBarSherlock ele criou um novo pacote na pasta Gen.
Esta a seguinte estrutura.
Gen > meupacote
BuilConfig.java
R.java
Gen > com.actionbarsherlock
R.java
Os meus layouts nao estão no R.java do pacote com.actionbarsherlock.
Somente os meus layouts não estão lá.
Tentei criar manualmente, mas ai da erro e ele elimina minha inserção.
Chegou a limpar o projeto? Como esses arquivos são gerados automaticamente a partir dos arquivos XML do layout, não é possível editá-los na mão. Limpar o projeto é uma forma de gerar novamente esses arquivos; se existir algum erro neles, isso deve corrigir.
Mesmo assim, não vejo nenhum problema com a estrutura dos arquivos do seu projeto. Qual é o erro exatamente que você está enfrentando?
O problema é que quando vou chamar o meu layout nos fragmentos ele não é mostrado.
public View onCreateView (LayoutInflater inflater, ViewGroup group, Bundle saved ) {
return inflater.inflate(R.layout.activity_principal , group, false);
O R.layout não mostra minhas activitys.
Willian
Como eu disse, se a classe R não está atualizada, limpar o projeto vai forçar que esse arquivo seja recriado. Se você tiver esse layout “activity_principal.xml” no mesmo projeto ele deve encontrar e adicionar na classe. Se mesmo assim o problema não for resolvido, provavelmente pode ser algum erro na configuração do projeto ou no código mesmo, e se for isso só vendo o código pra saber o que é.
Olá boa tarde,
consegui resolver o problema, agora tenho um outro problema.
Eu já tinha um projeto onde eu tinha um buttton que chamada uma uma activity de informações.
Eu clico nesse button ele nao funciona dentro do fragmento.
Tem que declarar alguma outra coisa expecifica?
Tem que informar que ele vai ser aberto em um fragmento?
//Metodo para chamar a tela de informações
public void chamaInfo(){
Intent info = new Intent (Principal.this,Informacao.class);
startActivity(info);
}
o startActivity tem que ter outro tipo de chamada?
Não, para iniciar uma nova Activity você só precisa criar um Intent (foi o que você fez) informando a classe da Activity que deve ser executada (foi o que você também fez) e o contexto (que eu não sei bem como você fez). Eu não entendi porque você usou “Principal.this” como contexto para o Intent. O mais comum é utilizar getActivity() dentro do Fragment para obter o contexto. Ficaria assim:
startActivity(new Intent(getActivity(), Informacao.class));
Desde que a classe Informacao estenda de Fragment, isso deve funcionar.
tentei fazer como voce disse, porem ocorre o erro.
The method getActivity() is undefined for the type Principal
A classe que quero chamar é uma classe que extende de SherlockActivity.
Me desculpe eu demorei a entender aqui.
Na verdade eu estou chamando o layout principal atravez do
public View onCreateView (LayoutInflater inflater, ViewGroup group, Bundle saved ) {
return inflater.inflate(R.layout.activity_principal , group, false);
Na verdade eu estou apenas chamando o layout sem código algum eu não estou chamando a classe principal onde os códigos estão.
Agora que eu consegui entender o que se passa.
Mas então como carregar o layout e chamar a classe principal que contem os códigos para os botoes?
os códigos terão que ir para os fragmentos?
Um layout sozinho não tem como existir, ele precisa estar associado a alguma Activity. Todo Fragment também não passa de um item do layout, então ele também tem uma Activity associada. Sem ver como você está estruturando o código eu não tenho muito como ajudar.
Eu tenho uma classe principal que chama meu layout principal.
public class Principal extends SherlockActivity {
String mensagem =””;
private AdView adView;
EditText editAltura,editPeso;
@Override
public void onCreate(Bundle savedInstanceState) {
setTheme(R.style.Sherlock___Theme_Light);
setTitle(“Calculadora Corporal”);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_principal);
}
Eu criei um container para colocar os metodos para chamar os layouts.
public class Container extends SherlockFragmentActivity{
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar bar = getSupportActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Tab listener para executar a troca de abas
ActionBar.TabListener tabListener = new ActionBar.TabListener() {
// evento de seleção de uma aba
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// primeira aba
if (tab.getPosition() == 0) {
ft.replace(android.R.id.content, new FragmentoInicial() );
}
// segunda aba
else {
ft.replace(android.R.id.content, new FragmentoInformacao());
}
}
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {}
@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {}
};
bar.addTab(bar.newTab().setText(“Calculadora IMC”).setTabListener(tabListener));
bar.addTab(bar.newTab().setText(“Informações”).setTabListener(tabListener));
}
}
Depois criei um fragmento Principal para chamar o layout principal.
public class FragmentoInicial extends SherlockFragment{
@Override
public View onCreateView (LayoutInflater inflater, ViewGroup group, Bundle saved ) {
return inflater.inflate(R.layout.activity_principal , group, false);
}
Minha dúvida.
Como chamar a classe principal que chama o layout principal para que os códigos na mesma sejam executados, pois como estou chamando apenas o layout a classe principal não está sendo criada.
Já vi onde está a confusão: você tem duas Activity’s diferentes e quer tentar fazer uma funcionar dentro de outra:
Principal extends SherlockActivity
Essa é uma Activity comum, que não pode incluir Fragment’s dentro.
Container extends SherlockFragmentActivity
Essa classe é uma Activity que pode conter Fragment’s dentro dela.
FragmentoInicial extends SherlockFragment
Esse é um Fragment que pode ser incluído dentro do “Container” (mas não do “Principal”). O layout desse Fragment é igual ao da Activity “Principal”, mas é apenas o layout igual. É uma cópia da interface e nada mais.
Sugiro que as classes Principal e Container sejam mescladas em uma classe só que estende de SherlockFragmentActivity, é a melhor forma de resolver isso.
Minha classe principal ficou assim.
public class Principal extends SherlockFragmentActivity {
String mensagem =””;
private AdView adView;
EditText editAltura,editPeso;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar bar = getSupportActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Tab listener para executar a troca de abas
ActionBar.TabListener tabListener = new ActionBar.TabListener() {
// evento de seleção de uma aba
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// primeira aba
if (tab.getPosition() == 0) {
ft.replace(android.R.id.content, new FragmentoInicial() );
}
// segunda aba
else {
ft.replace(android.R.id.content, new FragmentoInformacao());
}
}
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {}
@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {}
};
bar.addTab(bar.newTab().setText(“Calculadora IMC”).setTabListener(tabListener));
bar.addTab(bar.newTab().setText(“Informações”).setTabListener(tabListener));
Button btn_limpar = (Button)findViewById(R.id.btn_Limpar);
btn_limpar.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
limpar();
}
});
Button btn_Info = (Button)findViewById(R.id.btn_Info);
btn_Info.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
chamaInfo();
}
});
Button btnSair = (Button)findViewById(R.id.btn_Sair);
btnSair.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Sair();
}
});
Ele executa mais mostra somente uma tela em branco.
O que estou fazendo errado?
Com esse código, o aplicativo deve iniciar exibindo a primeira aba inserida (no caso, seria “Calculadora IMC” e a classe FragmentoInicial). As abas chegam a ser exibidas sem conteúdo? Ou realmente nada é exibido no aplicativo (nem mesmo a ActionBar)? Eu não tenho o ambiente para testar agora, mas a princípio não vejo nenhum erro nessa classe.
Nem mesmo a action bar é exibida, somente o titulo e o logo. O resto tudo em branco.
Agora eu tenho o ambiente para testar o código. Consegui rodar a sua classe sem problemas, exibiu a Action Bar e as abas como deveria. Eu acho que pode ser algum problema com a configuração do seu projeto ou do AndroidManifest.xml. Verifique duas coisas:
– A classe que possui o Intent Filter com action MAIN e category LAUNCHER é a classe “Principal”
– O aplicativo use um tema do Sherlock
Esses dois tópicos estão descritos no post anterior, Introdução ao ActionBarSherlock.
Bom dia Eduardo,
desculpa a demora em responder.
Eu fiz o que voce disse acima e realmente não da certo.
O erro, ao que parece ocorre nessa linha.
ActionBar.TabListener tabListener = new ActionBar.TabListener()
Debuguei e quando passa nessa linha trava.
Como eu já havia dito, não achei nenhum problema com o seu código. Muito provavelmente é só alguma configuração do projeto que está errada. Se os dois pontos que eu comentei anteriormente estão OK (a classe Principal está configurada como launcher e o aplicativo usa um tema do Sherlock), então eu acho que o problema pode ser ou os imports errados ou alguma opção de compilação do Eclipse mal-configurada (eu suponho que você deve estar usando o Eclipse). Verifica todas as configurações, se você inclui a biblioteca do ActionBarSherlock e outras opções. Algumas vezes essa dica também pode ajudar http://stackoverflow.com/a/17205659
Boa Tarde Eduardo,
Primeiramente parabenizo pelo conteúdo apresentado e disponibilizado!
Estou com um problema na implementação desde projeto, se possível peço ajuda.
Nesta etapa:
if (tab.getPosition() == 0) {
ft.replace(android.R.id.content, new Exemplo1());
}
Neste meu teste a classe Exemplo1 está estendendo SherlockActivity, ocasionando o erro no replace da condição acima. Este erro permanece mesmo com a mudança de SherlockActivity para SherlockFragmentActivity.
O que pode estar ocasionando este erro?
Possui alguma forma de contorna-lo?
Desde já agradeço a atenção
Olá Fernando,
Obrigado pelos elogios 🙂
Bom, quanto ao seu problema, a classe “Exemplo1” deve ser um Fragment e não uma Activity, ou seja, ela deve estender de SherlockFragment.
Isso deve resolver. Qualquer problema pode deixar outro comentário 😉
Problema resolvido, nem havia percebido os “extends”.
Eduardo, tenho mais uma duvida.
na MainActivity.java onde existe o evento de seleção de cada aba, tem alguma maneira de passar assim que a aba é selecionada uma classe Activity que possui se respectivo layout.
Caso exista, como seria esta passagem? por métodos?
Pois estou tentando implementar este seu exemplo em um projeto meu, onde possui esta classe activity que está executando um “ListView” que retorna informações de diferentes sites.
Grato.
Não, uma aba só pode conter um item do tipo “Fragment” dentro dela. A não ser é claro que você queira iniciar uma nova Activity, mas nesse caso a aba perderia completamente o funcionamento padrão (clicar na aba não troca para a aba mas abre uma nova janela?). Se você quer exibir uma lista dentro de uma aba você pode criar uma classe que estenda de SherlockListFragment.
O que a ViewFragment faz?
A ViewFragment é apenas um exemplo que eu utilizei, nesse caso apenas para exibir um texto estático. Mas ela poderia fazer qualquer coisa.
Eduardo, obrigado pela resposta. Como que faço para recuperar o que foi digitado na Primeira Tab estando na Tab 2?
Fred, me desculpe se minha resposta for um pouco genérica demais, mas já faz um bom tempo que eu não mexo mais com Android. Se você quiser um exemplo mais completo, o site do Android Developers pode ajudar, nesses links: http://developer.android.com/guide/components/fragments.html e https://developer.android.com/training/basics/fragments/communicating.html
Vou tentar resumir um pouco:
Basicamente, quando o Fragment é criado pode-se definir argumentos para ele. No caso do exemplo desse post, esse código ficaria no TabListener da MainActivity. Por exemplo, poderia ser feito o seguinte (não testei esse código, mas deve funcionar):
E no método onCreateView() da classe ViewFragment, após carregar o layout você poderia usar this.getArguments() para obter um Bundle com os argumentos recebidos, e disso você poderia pegar um dos valores, por exemplo o nome, utilizando o método bundle.getString("nome").
Espero que isso tenha respondido a sua pergunta, mas qualquer outra dúvida pode perguntar 😉
Ok, tranquilo, e quanto a lista usando sqlite e fragment, Tem alguma coisa?
Dá uma olhada nesses sites:
http://www.mysamplecode.com/2012/07/android-listview-cursoradapter-sqlite.html
http://techblogon.com/sample-code-listview-sqlite-database-connection-in-android/
http://androiddevbr.wordpress.com/2013/02/19/sqlite-banco-de-dados-no-android/
Obrigado. Mas seria que algum desses usa lista com fragments?
Adicionar a lista dentro do Fragment é apenas uma questão de layout, pode ser feito através do XML. No exemplo desse post, a raiz dos layouts eram do tipo ScrollView, mas você pode utilizar o ListView como raiz, ou mesmo adicionar ele dentro de outro elemento…
Vc não teria nenhum exemplo de listview com fragment e sqlite?
Você chegou a ler os sites que eu comentei anteriormente?
http://www.mysamplecode.com/2012/07/android-listview-cursoradapter-sqlite.html
http://techblogon.com/sample-code-listview-sqlite-database-connection-in-android/
http://androiddevbr.wordpress.com/2013/02/19/sqlite-banco-de-dados-no-android/
http://lmgtfy.com/?q=Tutorial+ListView+com+SQLite+e+Fragment
Então, como faço um listview com fragment? To com essa duvida. Mais a respeito de listview com sqlite, entendeu?