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

sexta-feira, 2 de setembro de 2011

Android: Dicas 4

Olá povo,

Segue mais um POST da série "dicas de Android".

Dica 1 - Obter o espaço disponível no aparelho

File path = Environment.getDataDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
long ocupedBlocks =
stat.getBlockCount() - availableBlocks;

String s1 = Formatter.formatFileSize(
this, availableBlocks * blockSize);
String s2 = Formatter.formatFileSize(
this, ocupedBlocks * blockSize);
System.out.println("---------------");
System.out.println("s = "+ s1);
System.out.println("s = "+ s2);

Dica 2 - Teclado Virtual Sobre o Layout
Ao exibir o teclado virtual, o Android automaticamente redimensiona a tela do aparelho para exibir todos os elementos. Então se você tiver, por exemplo uma barra com botões na parte inferior, eles irão aparecer imediatamente em cima do teclado virtual. Para evitar isso, basta colocar a seguinte configuração na declaração da sua Activity no AndroidManifest.xml.

<activity
android:name=".ui.MainActivity"
android:windowSoftInputMode="adjustPan"
/>

Dica 3 - Evitando abrir a mesma atividade 2 vezes
Os engenheiros de teste com frequência tentam "destruir" a aplicação de algum jeito :) E um bem comum é clicar rapidamente em um botão. Se esse botão chamar uma Activity serão abertas duas em sequência. Para evitar isso, basta colocar a seguinte configuração na declaração da sua Activity no AndroidManifest.xml.


<activity
android:name=".ui.MainActivity"
android:launchMode="singleTop"
/>

Isso faz com que só seja possível apenas uma instância no topo da pilha de atividades.

Dica 4 - Alterando a linha abaixo da TabWidget
Essa dica é um complemento da dica sobre como mudar a imagem das abas da TabWidget. O código abaixo mostra como mudar a linha que fica na parte inferior da TabWidget. Ela tem um aspecto interessante, pois a API só disponibilizou um método "digno" pra isso a partir do Android 2.2, para as versões anteriores, essa operação tem que ser feita via Reflection.


// Esse código deve ser chamado dentro de
// uma TabActivity
TabWidget tabWidget = getTabWidget();

if (android.os.Build.VERSION.SDK_INT >=
android.os.Build.VERSION_CODES.FROYO){
// For Android 2.2
tabWidget.setLeftStripDrawable(
R.drawable.barra_menu);
tabWidget.setRightStripDrawable(
R.drawable.barra_menu);
} else {
// For Android 2.1 or before
try {
Field stripLeft = tabWidget.getClass().
getDeclaredField("mBottomLeftStrip");
Field stripRight = tabWidget.getClass().
getDeclaredField("mBottomRightStrip");

if (!stripLeft.isAccessible())
stripLeft.setAccessible(true);
if (!stripRight.isAccessible())
stripRight.setAccessible(true);

stripLeft.set(tabWidget,
getResources().getDrawable(
R.drawable.barra_menu));

stripRight.set(tabWidget,
getResources().getDrawable(
R.drawable.barra_menu));

} catch (Exception e) {
e.printStackTrace();
}
}

Nesse exemplo, estou usando a API level 8 (Android 2.2) no Eclipse para poder ter acesso aos métodos setLeftStripDrawable e setRightStripDrawable. Porém ele pode ser executado em aparelhos 2.1, que neste caso executará o código via Reflection. Para dar suporte a API 2.1, mesmo desenvolvendo com a 2.2 basta colocar a tag abaixo no AndroidManifest.xml.

<uses-sdk android:minSdkVersion="7" />

Dica 5 - Salvar estado do scroll da ListView
Na aplicação que estou desenvolvendo, sempre estava reatribuindo o Adapter à ListView no onResume da Activity. O problema era que eu clicava em um item da lista lá do final pra edita-lo era aberta a tela pra edição. Quando fechava essa tela, aí abria a tela de detalhes, mas quando voltava pra tela de listagem queria manter a posição do scroll.


// savedIndex e savedY é um atributo int

// Salvar estado
// Esse código coloquei no onPause
savedIndex = getListView().getFirstVisiblePosition();
View v1 = getListView().getChildAt(0);
savedY = (v1 == null) ? 0 : v1.getTop();

// Restaurando estado
// Esse código eu coloquei no onResume
setListAdapter(novoAdapter);
getListView().setSelectionFromTop(savedIndex, savedY);

Dica 6 - Checar se o GPS está habilitado
Existe basicamente duas formas de obter a posição geográfica no Android: por GPS e pela Rede de Dados. Essa configuração fica no menu Configurações > Local > Meu Local. Se sua aplicação usa geolocalização, você deve checar se uma dessas opções está habilitada.

public boolean isEnabled() {
LocationManager lm = (LocationManager)
context.getSystemService(
Context.LOCATION_SERVICE);

return
locationManager.isProviderEnabled(
LocationManager.GPS_PROVIDER) ||
locationManager.isProviderEnabled(
LocationManager.NETWORK_PROVIDER);
}
Dica 7 - Problema no GoogleMaps
Essa dica foi mandada pelo meu aluno da LinuxFI, Sávio (Sávio saviojp@gmail.com).
Durante a aula de Mapas eu passei pelo seguinte problema: Mesmo com todas as configurações da API Key e permissões definidas de modo correto, o meu emulador não carregava o mapa. Para solucionar esse problema fiz o seguinte:

Customizei a execução da aplicação no eclipse por meio do Run Configurations/Android Application /na aba Target no campo Additional Emulator Command Line Options, setei o comando: -dns-server 8.8.8.8.

4br4ç05,
nglauber

segunda-feira, 20 de junho de 2011

Android: Dicas 3

Olá povo,

Meus alunos, mesmo após o fim das aulas, não me deixam em paz. E isso é bom ;) Eles ficam mandando dúvidas e soluções para problemas em que eles se deparam no dia-a-dia do desenvolvimento com Android. Sendo assim, lá vai mais uma leva de dicas de Android.

Dica 1 (dúvida de Felipe Bonezi)

A dúvida era como obter o tamanho da tela. Segue abaixo:
Display display = 
getWindowManager().getDefaultDisplay();

int width = display.getWidth();
int height = display.getHeight();


Dica 2 (dica de Bruno Baudel)

Ocultar o teclado virtual programaticamente.
InputMethodManager imm = (InputMethodManager) 
getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);


Dica 3 (dica de Felipe Vasconcelos)

Essa é a mais complicada de todas. Como modificar o background das abas de um TabHost. A primeira coisa que devemos ter são as imagens das abas. Se você não diver, crie no XML mesmo :) segue abaixo os XML para aba selecionada e normal, salve-os na pasta res/drawable com os nomes aba_normal.xml e aba_normal.xml.

<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">

<gradient
android:startColor="#000000"
android:endColor="#CCCCCC"
android:angle="90"
android:type="linear" />
<padding
android:left="10dp"
android:top="10dp" />
<corners
android:topLeftRadius="15dp"
android:topRightRadius="15dp" />
</shape>

<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">

<gradient
android:startColor="#000000"
android:endColor="#00FF00"
android:angle="90"
android:type="linear" />
<padding
android:left="10dp"
android:top="10dp" />
<corners
android:topLeftRadius="15dp"
android:topRightRadius="15dp" />
</shape>

Uma vez definida as imagens, precisamos associa-las ao estado da TabWidget, ou seja, quando a aba estiver selecionada, use a segunda imagem, caso contrário use a primeira. Crie o arquivo aba_selector também na pasta res/drawable.
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_selected="true"
android:drawable="@drawable/aba_selecionada" />
<item
android:state_selected="false"
android:drawable="@drawable/aba_normal" />
</selector>

Depois é só setar o background de cada aba do TabWidget.
TabWidget tabWidget = getTabWidget();
for (int i = 0; i < tabWidget.getChildCount(); i++) {
View v = tabWidget.getChildAt(i);
v.setBackgroundDrawable(
getResources().getDrawable(R.drawable.aba_selector));
}



Dica 4 (dica de Ricardo Gilson)

Sem mais aguentar a linha "TODO" que é adicionada toda vez que criamos algum tipo de bloco ou método no Eclipse, Ricardo foi em busca de como retirá-lo. A solução é ir até o menu Window > Preferences... No lado esquerdo, selecione Java > Code style > Code templates. Ao percorrer a lista é possível observar que o TODO está configurado para várias chamadas:
Method body, Construtor body, Catch....

O jeito é remover a linha do TODO de cada um deles...
// ${todo} Auto-generated catch block.


É isso pessoal, vão mandando suas dicas que eu coloco aqui! :)
Obrigado a todos que contribuíram.

4br4ç05,
nglauber

segunda-feira, 22 de novembro de 2010

TabHost, TabWidget e TabActivity

Olá povo,

Dar aulas é um desafio bem grande, e às vezes você paga uns micos esquecendo coisas simples. Esse post é dedicado aos meus alunos da LinuxFI em João Pessoa, aos quais presenciaram mais um mico proporcionado por minha pessoa.
Estava explicando como se fazia para criar uma tela com abas (ou guias, como preferir) no Android, e como não queria fazer como estava no livro, fui fazer de outro jeito. Aí claro que deu merda. Então implementei de outro jeito e prometi que iria fazer esse post. No final acabou que um aluno (perdão por não lembrar do nome) Raniere Fernandes descobriu o que estava faltando (era um maldito tabHost.setup()), mas aí já era!

Então vamos lá! Vou mostrar primeiro a maneira mais simples. Primeiro vou criar dois arquivos de layout: aba1.xml e aba2.xml.


<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/raizAba1">

<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Nome:" />
<EditText
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:id="@+id/edtNome"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Email"/>
<EditText
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:id="@+id/edtEmail"/>
</LinearLayout>


<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/raizAba2"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Observações:"/>
<EditText
android:id="@+id/edtObs"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:gravity="top"/>
</LinearLayout>

Notem que o elemento raiz do XML tem os identificadores raizAba1 e raizAba2. Esses identificadores serão utilizados para setar o conteúdo das abas.
Vamos agora ao código que configura a tela.

public class ExTabActivity1 extends TabActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

TabHost tabHost = getTabHost();

LayoutInflater.from(this).inflate(
R.layout.aba1, tabHost.getTabContentView());

LayoutInflater.from(this).inflate(
R.layout.aba2, tabHost.getTabContentView());

TabSpec aba1 = tabHost.newTabSpec("foo1");
aba1.setIndicator("Informações");

aba1.setContent(R.id.raizAba1);

TabSpec aba2 = tabHost.newTabSpec("foo2");
aba2.setIndicator("Observações");
aba2.setContent(R.id.raizAba2);

tabHost.addTab(aba1);
tabHost.addTab(aba2);
}
}

A classe TabActivity da qual nossa classe está herdando facilita o nosso trabalho para telas que usam abas. No método onCreate estamos obtendo a instância do TabHost que é o gerenciador de layout responsável por esse tipo de tela. Internamente ele contém um objeto TabWidget e um FrameLayout que exibe o conteúdo das abas (como veremos no próximo exemplo).

Cada aba é representada por um objeto do tipo TabSpec, que é adicionado ao TabHost. Para criar uma TabSpec chamamos o método newTabSpec do objeto TabHost passando uma tag de identificação. Para definir o texto de cada aba chamamos o método setIndicator. E para setar o conteúdo, carregamos o arquivo de layout através da chamada:

LayoutInflater.from(this).inflate(
R.layout.aba1, tabHost.getTabContentView());

Isso carregará o arquivo de layout no FrameLayout interno do TabHost. Uma vez que o layout está carregado, podemos definir o conteúdo da TabSpec, chamando o método setContent e passando o id da view raiz do arquivo de layout. No caso, R.id.raizAba1 para primeira aba e R.id.raizAba2 para a segunda.

Mas e se eu quiser ter mais do que uma TabHost na minha tela? Como, por exemplo, um botão no canto inferior? Pois é, esse era o exemplo que eu queria ter terminado em "Jampa".
Primeiro devemos criar um arquivo de layout igual ao definido abaixo, e a este, chamaremos de meuTabHost.xml:

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">

<TabHost
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/meuTabHost"
android:layout_weight="1">
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<TabWidget
android:id="@android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>

<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@android:id/tabcontent"/>
</LinearLayout>
</TabHost>

<Button
android:text="Salvar"
android:id="@+id/Button01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>


Notem que nele, dentro de um LinearLayout, temos um TabHost, que dentro dele temos um TabWidget e um FrameLayout, conforme já tínhamos descrito. Uma atenção especial nos ids do TabHost e do TabWidget, que devem, obrigatoriamente chamar-se @android:id/tabs e @android:id/tabcontent respectivamente.

Para finalizar, a classe Java ficaria conforme abaixo:


public class ExTabActivity2 extends Activity {

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.meutab);

TabHost tabHost = (TabHost)findViewById(
R.id.meuTabHost);

tabHost.setup();

// O resto é igual ao exemplo anterior
}
}


Agora a nossa classe herda de Activity e não mais de TabActivity. Dessa forma, temos que chamar o método setContentView passando o nosso layout e chamar o (MALDITO) método setup do objeto TabHost, que agora é obtido através do arquivo de layout.

Aê turma da LinuxFI, um "Aleluia" pro professor! :)

4br4ç05,
nglauber