Mostrando postagens com marcador Menu. Mostrar todas as postagens
Mostrando postagens com marcador Menu. Mostrar todas as postagens

quarta-feira, 31 de julho de 2013

ActionBar na API de Compatibilidade

Olá povo,

No último 18/07 a Google finalmente adicionou o suporte à ActionBar na API de compatibilidade. Pelo menos para API v7 (Android 2.1 ou superior). Para usá-la, vá até o SDK Manager e atualize a API de compatibilidade marcando a opção Extras > Android Support Library.



Feito isso, vá até o Eclipse e importe o projeto appcompat disponível no diretório SDK_DIR/extras/android/support/v7. Crie um novo projeto e referencie o projeto importado anteriormente clicando com o botão direito sobre o projeto e selecionando Properties.  Em seguida, selecione a opção Android no lado esquerdo e na parte inferior, clique em Add. Selecione o projeto android-support-v7-appcompat. Agora apague o arquivo android-support-v4.jar da pasta lib do projeto, pois o projeto que acabamos de importar já tem esse arquivo.

Nossa Activity agora herdará ActionBarActivity (que herda de FragmentActivity).
import android.support.v7.app.ActionBarActivity;

public class MainActivity extends ActionBarActivity {
  // Implementação normal da Activity
}

Obrigatoriamente, nossa Activity tem que ter o estilo da R.style.Theme.AppCompat. Para tal, vá até o arquivo values/styles.xml e modifique o tema da aplicação conforme abaixo.

<style name="AppBaseTheme" 
  parent="@style/Theme.AppCompat">

Pronto! Agora é só usar a ActionBar como se estivesse no Android 3.0 ou superior :)

EDITADO em 05/08/2013

Para usar a SearchView nesse nova biblioteca, adicione o arquivo res/menu/main.xml.
<menu 
  xmlns:android="http://schemas.android.com/apk/res/android" 
  xmlns:suaapp="http://schemas.android.com/apk/res-auto">

  <item
    android:id="@+id/action_settings"
    android:orderInCategory="100"
    android:showAsAction="always|withText"
    android:icon="@android:drawable/ic_menu_info_details"
    android:title="@string/action_settings"/>

  <item android:id="@+id/search"
    android:title="Search"
    android:icon="@android:drawable/ic_menu_search"
    suaapp:showAsAction="collapseActionView|ifRoom"
    suaapp:actionViewClass="android.support.v7.widget.SearchView" />
</menu>
Agora deixe o código da sua Activity como abaixo:
public class MainActivity extends ActionBarActivity 
  implements SearchView.OnQueryTextListener {

  private MenuItem mSearchItem;
  private SearchView mSearchView;
  private TextView mTextTeste;
 
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mTextTeste =
     (TextView)findViewById(R.id.textView1);
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main, menu);
  
    mSearchItem = menu.findItem(R.id.search); 
    mSearchView = (SearchView) 
      MenuItemCompat.getActionView(mSearchItem); 
    mSearchView.setOnQueryTextListener(this);
  
    return true;
  }

  @Override
  public boolean onQueryTextChange(String text) {
    mTextTeste.setText(text);
    return false;
  }

  @Override
  public boolean onQueryTextSubmit(String text) {
    mTextTeste.setText(text +" GO!");
    MenuItemCompat.collapseActionView(mSearchItem);
    return true;
  }
}


4br4ç05,
nglauber

quarta-feira, 19 de junho de 2013

SlidingPaneLayout: um menu lateral estilo Facebook

Olá povo,

Uma das coisas boas de mexer a muito tempo com uma tecnologia, é que as pessoas sempre perguntam a você, mas obviamente, nem sempre você sabe a resposta. Meu amigo Rodrigo Jardim (a.k.a. Praieiro), me perguntou se eu conhecia o SlidingPaneLayout, e eu nunca tinha visto o dito cujo. Mas ele permite implementarmos um padrão de interface gráfica amplamente utilizada nas aplicações Android: menus laterais. Abaixo, coloquei um screenshot de duas "pequenas" aplicações que usam essa abordagem.


Como podemos notar, o Facebook e o GMail são dois bons exemplos de grandes aplicações que usam essa abordagem. Nesse post vou mostrar como dar os primeiros passos para construir um menu desse tipo. Vamos começar pelo arquivo de layout da aplicação, mostrado abaixo.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SlidingPaneLayout 
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/sliding_pane_layout"
  android:layout_width="match_parent"
  android:layout_height="match_parent" >

  <!-- Menu Lateral -->
  <ListView
    android:id="@+id/left_pane"
    android:layout_width="280dp"
    android:layout_height="match_parent"
    android:layout_gravity="left" />
    
  <!-- Conteúdo da tela -->
  <RelativeLayout
    android:id="@+id/rightPane"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ff333333" >

    <Button
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentLeft="true"
      android:layout_alignParentTop="true"
      android:text="MENU" 
      android:onClick="abrirMenu"/>

    <ImageView
      android:id="@+id/imageView1"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:src="@drawable/ic_launcher" />

  </RelativeLayout>

</android.support.v4.widget.SlidingPaneLayout>
No SlidingPanelLayout temos apenas duas partes, a primeira (uma ListView) será o menu da aplicação. Enquanto que a segunda, será o conteúdo da tela em si. Abaixo temos o código da Activity.
public class MainActivity extends FragmentActivity 
  implements OnItemClickListener, PanelSlideListener {

  private SlidingPaneLayout mSlidingLayout;
  private ListView mList;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Colocando a Activity em tela cheia (opcional)
    requestWindowFeature(Window.FEATURE_NO_TITLE);

    setContentView(R.layout.activity_main);
  

    mSlidingLayout = (SlidingPaneLayout) 
      findViewById(R.id.sliding_pane_layout);
    mSlidingLayout.setPanelSlideListener(this);
  
    String[] opcoes = new String[] { 
      "Opção 1", "Opção 2", "Opção 3",
      "Opção 4", "Opção 5" };

    mList = (ListView) findViewById(R.id.left_pane);
    mList.setAdapter(new ArrayAdapter<String>(
      this, 
      android.R.layout.simple_list_item_1, 
      opcoes));
    mList.setOnItemClickListener(this);
  }

  // Evento de clique do botão
  public void abrirMenu(View v){
    // Se estive aberto, feche. Senão abra.
    if (mSlidingLayout.isOpen()){
      mSlidingLayout.closePane();
    } else {
      mSlidingLayout.openPane();
    }
  }

  @Override
  public void onItemClick(AdapterView<?> adapterView, 
    View view, int position, long id) {
    // TODO Tratar opções de Menu (ListView) aqui!
  }

  @Override
  public void onPanelClosed(View arg0) {
    // TODO Ao fechar o painel
  }

  @Override
  public void onPanelOpened(View arg0) {
    // TODO Ao abrir o painel
  }

  @Override
  public void onPanelSlide(View arg0, float arg1) {
    // TODO Enquanto o painel desliza
  }
}
O código acima é bem simples e está comentado.
O mais legal desse componente é que ao deslizar o dedo sobre a tela da esquerda para direita, o menu exibido (da direita para esquerda, ele fecha). Ou seja, o botão acima é opcional, mas indicado, como vemos nas aplicações em geral (como a do Facebook e Gmail) para facilitar a visualização do usuário.
Abaixo podemos ver nossa aplicações em execução com o menu lateral aberto.

É isso pessoal! Temos um menu no padrão de aplicações profissionais. Vale salientar que esse componente funciona em todas as versões do Android.

EDITADO em 29/11/2013

Várias pessoas me perguntaram (por email.... deixem os comentários aqui povo!) o que fazer com o clique do item da lista. O mais legal aqui é usar Fragments e sua stack. Ou seja, criar uma pilha de Fragments como o Android faz com as Activities. Ou seja, ao invés de irmos chamando Activities, chamamos Fragments e vamos empilhando-os no layout da direita.
Vamos ao exemplo... Crie a classe MeuFragment conforme abaixo:
public class MeuFragment extends Fragment {

  public static MeuFragment newInstance(String s){
    Bundle args = new Bundle();
    args.putString("texto", s);
  
    MeuFragment f = new MeuFragment();
    f.setArguments(args);
    return f;
  }
 
  @Override
  public View onCreateView(LayoutInflater inflater, 
    ViewGroup container, Bundle savedInstanceState) {

    View layout = inflater.inflate(
      R.layout.meu_fragment, container, false);

    TextView txt = (TextView)
      layout.findViewById(R.id.textView1);

    txt.setText(getArguments().getString("texto"));
    return layout;
  }
}
O arquivo de layout do Fragment acima, só tem um RelativeLayout com um TextView centralizado (nada de mais, vocês conseguem :)
Agora, no clique de cada um dos itens, instanciamos esse fragment passando o texto da opção clicada.
@Override
public void onItemClick(AdapterView<?> adapterView, 
  View view, int position, long id) {

  String opcao = (String)
    mList.getAdapter().getItem(position);
  
  MeuFragment f = MeuFragment.newInstance(opcao);
  
  FragmentManager fm = getSupportFragmentManager();
  // Opcional: isso removerá o fragment anterior 
  // da pilha.
  fm.popBackStack(); 
  
  fm.beginTransaction()
    .replace(R.id.rightPane, f, "frag1")
    .addToBackStack(null)
    .commit();  
}
O método addToBackStack vai adicionar o Fragment a uma pilha, dessa forma, ao clicar no botão back do aparelho, o fragment será removido automaticamente e anterior será exibido.

Qualquer dúvida, deixem seus comentários.

4br4ç05,
nglauber

Fonte: http://androidtrainningcenter.blogspot.com.br/2013/06/slidingpanelayout-android-making.html

segunda-feira, 5 de novembro de 2012

ActionBar no Android 2.x

Olá povo,

Quem me conhece saber que não sou muito fã de frameworks e bibliotecas, gosto de procurar ao máximo uma solução nativa da plataforma ao qual estou trabalhando. E uma coisa que me deixava muito chateado no Android era a não retrocompatibilidade da ActionBar com versões anteriores à 3.0 (quando ela foi lançada).
Felizmente esse problema acabou com a biblioteca SherlockActionBar, que traz o recurso da ActionBar para aparelhos com Android 2.3 ou inferior, e mantém os nomes de métodos iguais à plataforma nativa. E o que é melhor, quando a aplicação está rodando em versões 3.0 ou superior, o Sherlock só faz chamar a API padrão, ou seja, utiliza a ActionBar nativa.

Vou fazer um exemplo que utiliza dois recursos da ActionBar: Menus e Abas. Faça o download em http://actionbarsherlock.com e descompacte em algum local do seu computador. No Eclipse, importe o projeto library para dentro do seu workspace, para tal acesse File/New.../Project, e na janela que for exibida selecione Android/Android Project From existing code selecione o diretório onde você descompactou o Sherlock. Aparecerá além do projeto library, os demos do Sherlock, por agora só importe o projeto library.

Crie um novo projeto selecionando o Build SDK 4.1 (o Sherlock utiliza Temas e Estilos dessa versão do Android) e o Minimum Required para 2.2. Depois de criado, vá até a pasta lib do projeto e apague o arquivo android-support-v4.jar (o Sherlock já inclui esse arquivo). Agora adicione a referência ao projeto library do Sherlock, para tal, clique com o botão direito no projeto e selecione Properties.

Selecione Android, e na parte inferior direita, clique em Add... e selecione o projeto library e clique em OK. Agora, deixe a Activity do seu projeto conforme abaixo:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.actionbarsherlock.app.*;
import com.actionbarsherlock.app.ActionBar.*;
import com.actionbarsherlock.view.Menu;

public class ExemploSherlockActivity 
  extends SherlockFragmentActivity 
  implements TabListener {

  private Fragmento1 f1;
  private Fragmento2 f2;
 
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setTheme(R.style.Theme_Sherlock_Light);
    setContentView(R.layout.activity_exemplo_sherlock);

    f1 = (Fragmento1)getSupportFragmentManager()
         .findFragmentById(R.id.fragmento1);
    f2 = (Fragmento2)getSupportFragmentManager()
         .findFragmentById(R.id.fragmento2);
        
    getSupportActionBar().setNavigationMode(
      ActionBar.NAVIGATION_MODE_TABS);
        
    Tab aba1 = getSupportActionBar().newTab()
               .setText("Aba 1")
               .setTabListener(this);

    Tab aba2 = getSupportActionBar().newTab()
               .setText("Aba 2")
               .setTabListener(this);        
        
    getSupportActionBar().addTab(aba1);
    getSupportActionBar().addTab(aba2);
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getSupportMenuInflater().inflate(
      R.menu.activity_exemplo_sherlock, menu);
    return super.onCreateOptionsMenu(menu);
  }

  @Override
  public void onTabSelected(Tab tab, 
    FragmentTransaction ft) {

    if (tab.getPosition() == 0){
      ft.show(f1).hide(f2);
    } else {
      ft.show(f2).hide(f1);
    }
  }

  @Override
  public void onTabUnselected(
    Tab tab, FragmentTransaction ft) {}

  @Override
  public void onTabReselected(
    Tab tab, FragmentTransaction ft) {}
    
  public static class Fragmento1 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater infltr, 
      ViewGroup container, Bundle savedState){

      TextView txt = new TextView(getActivity()); 
      txt.setText("Fragmento 1");
      return txt;
    }
  }
 
  public static class Fragmento2 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater infltr, 
      ViewGroup container, Bundle savedState){

      TextView txt = new TextView(getActivity());
      txt.setText("Fragmento 2");
      return txt;
    }
  }
}
Como estamos trabalhando com Fragment, nossa classe herda de SherlockFragmentActivity. Implementamos a interface TabChangeListener para detectarmos quando houver a alternância entre abas. Declaramos dois fragmentos que serão nas abas, essa classes estão declaradas no final do arquivo, obviamente o ideal é que cada fragmento fique em um arquivo separado.
No onCreate setamos o tema do Sherlock, e em seguida setamos o arquivo de layout da Activity (que está logo abaixo). Depois inicializamos os fragmentos e definimos a forma de navegação da ActionBar para o modo de abas. E por fim, criamos e adicionamos as abas na ActionBar.

Abaixo temos o arquivo de layout da aplicação (res/layout/activity_exemplo_sherlock.xml):
<FrameLayout 
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/FrameLayout1"
  android:layout_width="match_parent"
  android:layout_height="match_parent" >

  <fragment
    android:id="@+id/fragmento1"
    android:name="ngvl.android.exemplosherlock.ExemploSherlockActivity$Fragmento1"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

  <fragment
    android:id="@+id/fragmento2"
    android:name="ngvl.android.exemplosherlock.ExemploSherlockActivity$Fragmento2"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

</FrameLayout>

Note que o nome da classe é composto do pacote da aplicação + o nome da classe. Como estamos usando uma Inner Class, o sinal de $ é usado. Se você definir os Fragmentos em arquivos separados (o que é o normal) coloque apenas o nome completo da classe.

E abaixo o arquivo de menu da aplicação (res/menu/activity_exemplo_sherlock.xml) ele é carregado no método onCreateOptionsMenu. Para tratar cada opção adicione o método onMenuItemSelected.
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
  <item
    android:id="@+id/menu_new"
    android:showAsAction="always|withText"
    android:icon="@android:drawable/ic_menu_add"
    android:title="Novo"/>
  <item
    android:id="@+id/menu_edit"
    android:showAsAction="ifRoom|withText"
    android:icon="@android:drawable/ic_menu_edit"
    android:title="Editar"/>
  <item
    android:id="@+id/menu_listar"
    android:showAsAction="ifRoom"
    android:icon="@android:drawable/ic_menu_my_calendar"
    android:title="Listar Itens"/>
</menu>
O primeiro item sempre aparece com ícone e texto. No segundo, o ícone sempre aparece, mas texto só aparece (na barra) se houver espaço. O último só aparecerá se houver espaço, para vê-lo, você deverá pressionar a tecla menu (ou nos dispositivo que não tenham, esse item ficará "colapsed" mas a direita).

Ao mandar executar a aplicação devemos ter uma tela similar a abaixo.

Esse post é em homenagem aos meus alunos da FA7, que me obrigaram a aprender essa biblioteca durante a aula :) Abraço a todos!

Qualquer dúvida, deixem seus comentários.

4br4ç05,
nglauber

segunda-feira, 22 de outubro de 2012

Context Menu em Listas no Android

Olá povo,

Estava dando aula e precisei mostrar para os meus alunos um exemplo de um menu de contexto. Mas o que é um menu de contexto? É basicamente é uma lista de opções que é exibida quando o usuário dá um clique longo em um componente da tela. Isso é particularmente útil em uma lista, onde você pode realizar várias operações sobre um determinado item.
É esse exemplo que mostraremos aqui. Crie um novo projeto, e em seguida crie o arquivo menu_contexto.xml na pasta menu (essa pasta não existe, você deve criá-la).
<menu 
  xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:id="@+id/opcao1" 
    android:title="Opção 1"/>
  <item android:id="@+id/opcao2" 
    android:title="Opção 2"/>
  <item android:id="@+id/opcao3" 
    android:title="Opção 3"/>
</menu>
Esse arquivo contém as opções de menu que aparecerão no menu de contexto. Carregaremos essas opções no método onCreateContextMenu na nossa Activity.
public class MainActivity extends ListActivity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
        
    String[] nomes = {
      "Fulano", "Cicrano", "Beltrano", "João",
      "Maria", "José", "Antônio", "Francisco" };
        
    ArrayAdapter<String> adapter = 
      new ArrayAdapter<String>(this,
        android.R.layout.simple_list_item_1, nomes);
    setListAdapter(adapter);
    registerForContextMenu(getListView());
  }
    
  @Override
  public void onCreateContextMenu(ContextMenu menu, 
    View v, ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    getMenuInflater().inflate(
      R.menu.menu_contexto, menu);
  }
    
  @Override
  public boolean onContextItemSelected(MenuItem item){
    AdapterContextMenuInfo info = 
      (AdapterContextMenuInfo)item.getMenuInfo();
     
    String nomeSelecionado = (String)
      getListView().getItemAtPosition(info.position);
     
    switch (item.getItemId()) {
    case R.id.opcao1:
      Toast.makeText(this, "Opção 1 - "+ 
        nomeSelecionado, Toast.LENGTH_SHORT).show();
      return true;
    case R.id.opcao2:
      Toast.makeText(this, "Opção 2 - "+ 
        nomeSelecionado, Toast.LENGTH_SHORT).show();
      return true;
    case R.id.opcao3:
      Toast.makeText(this, "Opção 3 - "+ 
        nomeSelecionado, Toast.LENGTH_SHORT).show();
      return true;   
    }
    return super.onContextItemSelected(item);
  }
}
A primeira etapa para criar o menu de contexto é chamar o método registerForContextMenu, passando um objeto View. Pode ser qualquer View, mas no nosso exemplo estamos pegando a ListView (que a classe ListActivity tem internamente). No método onCreateContextMenu utilizamos a classe MenuInflater para carregar o arquivo de menu que criamos anteriormente.
Por fim, para tratar as opções de menu, utilizamos o método onContextItemSelected. Esse método começa resolvendo um problema que temos quando usamos um menu de contexto em uma lista: quando o menu de contexto é aberto, perdemos o item que estava selecionado na lista.
Felizmente, podemos obter essa informação através do método getMenuInfo, que quando chamado em um item de menu que está associada a view, que é preenchida por um Adapter (a ListView está usando um ArrayAdapter para exibir seu conteúdo), retorna uma instância da classe AdapterContextMenuInfo. Nela podemos obter a linha que foi selecionada através do atributo position.
Para saber a opção de menu que foi selecionada, usamos o método getItemId, e comparamos com os ids que foram definidos no arquivo XML de menu. Abaixo temos a nossa aplicação em execução.

Qualquer dúvida, deixem seus comentários.

4br4ç05,
nglauber