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

segunda-feira, 13 de junho de 2016

Chrome Custom Tabs para Android

Olá povo,

Mais um post rápido :) Quando precisamos abrir uma URL dentro de uma aplicação Android normalmente utilizamos uma Intent como a seguir:
Intent it = new Intent(Intent.ACTION_VIEW, 
                       Uri.parse("http://www.nglauber.com.br"));
startActivity(it);
O problema de usar essa abordagem é que exige o carregamento de outro aplicativo (o que é pesado computacionalmente falando) e fará com que o usuário deixe seu aplicativo, o que não é bom. Outro ponto negativo é que uma vez que você não tem acesso ao outro aplicativo (o browser nesse caso), você não consegue fazer nenhuma customização.

Uma outra abordagem é utilizar o componente WebView.
WebView webView = (WebView)findViewById(R.id.webView);
webView.loadUrl("http://www.nglauber.com.br");
webView.setWebViewClient(new WebViewClient() {
    public boolean shouldOverrideUrlLoading(WebView view, String url){
        view.loadUrl(url);
        return false; 
    }
});
Nesse caso você possui um controle maior, uma vez que tudo é feito dentro do seu aplicativo. Entretanto, você terá que fazer vários controles para a navegação (como eu fiz aqui tratando o redirecionamento de página). Um problema aqui é que o WebView não compartilha a sessão do browser.

Chrome Custom Tabs junta os pontos positivos de ambas as abordagens, pois permite o controle da experiência web dentro do seu aplicativo. Com essa API podemos: definir transições customizadas; personalizar título; adicionar ações personalizadas; fazer um pré-carregamento da página para agilizar o carregamento; entre outros.
Como pode-se imaginar, esse recurso só funcionará se o usuário possuir o Chrome instalado no aparelho. Caso contrário, será disparada a Intent que mostramos no início do post.
 Para usar o Chrome Custom Tabs, a primeira coisa a fazer é adicionar a dependência no build.gradle.
dependencies {
    ...
    compile 'com.android.support:customtabs:23.3.0'
}
Então é só chamar a aba como a seguir:
String url = "http://www.nglauber.com.br";
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();

// Definindo a cor da toolbar (opcional)
builder.setToolbarColor(ActivityCompat.getColor(this, R.color.colorPrimary));

// Adicionando uma ação/menu (opcional)
Bitmap icon = BitmapFactory.decodeResource(
        getResources(), android.R.drawable.ic_menu_agenda);
PendingIntent pit = PendingIntent.getActivity(
        this, 0, new Intent(this, MainActivity.class), 0);

// Ação
builder.setActionButton(icon, "Ação", pit, true);
// Menu
builder.addMenuItem("Menu", pit);

// Definindo animações (opcional)
builder.setStartAnimations(this, 
        R.anim.slide_in_right, R.anim.slide_out_left);
builder.setExitAnimations(this, 
        R.anim.slide_in_left, R.anim.slide_out_right);

// Abrindo a "aba"
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(this, Uri.parse(url));

Como podemos observar, é bastante simples criar as custom tabs do Chrome. Criamos uma instância da classe CustomTabsIntent.Builder e com ela criamos podemos customizar a aba da maneira que desejarmos. Primeiro definimos a cor do título usando o método setToolbarColor(int). Em seguida instancimamos um Bitmap e uma PendingIntent que podem ser utilizadas para adicionar uma ação ou uma opção de menu na barra de título. A ação é adicionada por meio do método setActionButton(Bitmap,String,PendingIntent,boolean) e o menu por meio do método addMenuItem(String,PendingIntent).
As animações foram definidas utilizando o método setStartAnimations e setExitAnimations. Essas animações foram definidas como a seguir:
// res/anim/slide_in_left.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="-100%p" android:toXDelta="0"
        android:duration="@android:integer/config_mediumAnimTime"/>
</set>

// res/anim/slide_in_right.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="100%p" android:toXDelta="0"
        android:duration="@android:integer/config_mediumAnimTime"/>
</set>

// res/anim/slide_out_left.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="0" android:toXDelta="-100%p"
        android:duration="@android:integer/config_mediumAnimTime"/>
</set>

// res/anim/slide_out_right.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="0" android:toXDelta="100%p"
        android:duration="@android:integer/config_mediumAnimTime"/>
</set>
Por fim, criamos uma instância da classe CustomTabsIntent e com o método launchUrl(Activity, Uri) abrimos essa nova aba.
Abaixo podemos ver a aplicação em execução.

Mais detalhes aqui:
https://developer.chrome.com/multidevice/android/customtabs

4br4ç05,
nglauber

terça-feira, 8 de novembro de 2011

AutoCompleteTextView personalizado

Olá povo,

Estou com um monte de posts legais pra publicar, mas infelizmente (pra variar) estou sem tempo. São coisas que precisei fazer nos projetos que trabalhei, e que gosto de compartilhar com quem lê o blog. Além do mais, me serve como fonte de consulta para uma uso posterior. Afinal de contas, é pra isso que serve o blog (pelo menos pra mim).

Hoje vou mostrar como criar uma consulta personalizada para o componente AutoCompleteTextView. Esse componente é utilizado quando você tem uma lista de valores, e ao invés de selecioná-lo em uma lista, você digita parte do texto e os resultados vão sendo exibidos em uma lista (estilo drop-down) abaixo do componente. Este componente já conta com um mecanismo de busca padrão, entretanto a necessidade de personalizá-lo surgiu quando precisei realizar a busca por nomes de cidades. O cliente solicitou que a acentuação fosse ignorada, ou seja, quando eu digitasse "sao" era para aparecer "São Paulo" nos resultados.

Vamos à implementação! Primeiro vou mostrar o método que substitui os caracteres acentuados pelos mesmos não acentuados.

public static String[] REPLACES = 
{ "a", "e", "i", "o", "u", "c" };

public static Pattern[] PATTERNS = null;

public static void compilePatterns() {
PATTERNS = new Pattern[REPLACES.length];
PATTERNS[0] = Pattern.compile(
"[âãáàä]", Pattern.CASE_INSENSITIVE);
PATTERNS[1] = Pattern.compile(
"[éèêë]", Pattern.CASE_INSENSITIVE);
PATTERNS[2] = Pattern.compile(
"[íìîï]", Pattern.CASE_INSENSITIVE);
PATTERNS[3] = Pattern.compile(
"[óòôõö]", Pattern.CASE_INSENSITIVE);
PATTERNS[4] = Pattern.compile(
"[úùûü]", Pattern.CASE_INSENSITIVE);
PATTERNS[5] = Pattern.compile(
"[ç]", Pattern.CASE_INSENSITIVE);
}

public static String removeAcentos(String text) {
if (PATTERNS == null) {
compilePatterns();
}

String result = text;
for (int i = 0; i < PATTERNS.length; i++) {
Matcher matcher = PATTERNS[i].matcher(result);
result = matcher.replaceAll(REPLACES[i]);
}
return result.toUpperCase();
}

O código acima, utiliza as classes Pattern e Matcher para checar a presença de caracteres acentuados e substitui-los pelos caracteres correspondentes sem acentuação. Observe que só são sendo tratadas as vogais e o cedilha, para textos em outros idiomas você deve fazer os ajustes necessários (como o 'ñ' do espanhol).

Para que um AutoCompleteTextView faça a busca, é necessário definir um Adapter com os dados que ele irá filtrar para exibir. Para fazer nossa busca personalizada (ignorando acentuação) devemos criar nosso Adapter e sobrescrever o método getFilter(). Esse método deve retornar um objeto da classe android.widget.Filter que representa o resultado da busca.

public class MeuAutoCompleteAdapter
extends ArrayAdapter<String>
implements Filterable {

private List<String> listaCompleta;
private List<String> resultados;
private Filter meuFiltro;

public MeuAutoCompleteAdapter(
Context ctx, int layout,
List<String> textos) {

super(ctx, layout, textos);
this.listaCompleta = textos;
this.resultados = listaCompleta;
this.meuFiltro = new MeuFiltro();
}

@Override
public int getCount() {
return resultados.size();
}

@Override
public String getItem(int position) {
if (resultados != null
&& resultados.size() > 0
&& position < resultados.size()){
return resultados.get(position);
} else {
return null;
}
}

@Override
public Filter getFilter() {
return meuFiltro;
}

private class MeuFiltro extends Filter {
@Override
protected FilterResults performFiltering(
CharSequence constraint) {

FilterResults filterResults =
new FilterResults();

ArrayList<String> temp =
new ArrayList<String>();

if (constraint != null) {
String term = removeAcentos(
constraint.toString().trim().toLowerCase());

String placeStr;
for (String p : listaCompleta) {
placeStr = removeAcentos(p.toLowerCase());

if ( placeStr.indexOf(term) > -1){
temp.add(p);
}
}
}
filterResults.values = temp;
filterResults.count = temp.size();
return filterResults;
}

@SuppressWarnings("unchecked")
@Override
protected void publishResults(
CharSequence contraint,
FilterResults filterResults) {

resultados = (ArrayList<String>)
filterResults.values;

notifyDataSetChanged();
}
}
}

A classe acima tem duas listas de strings: a original e a que serve como resultado da busca. Note que os métodos getCount e getItem trabalha em cima da lista dos resultados. O outro atributo da classe é da classe MeuFiltro, e esse atributo é retornado no método getFilter.
A classe interna MeuFiltro faz a nossa busca personalizada. O filtro é realizado no método performFiltering, que retorna um objeto da classe android.widget.Filter.FilterResults que contém o resultado da busca e o total de registros encontrados. Esse resultado é passado para o método publishResults que seta o resultado da busca no atributo resultados, e logo após atualiza o adapter através do método notifyDatasetChanged.

Agora vamos ver como usar esse nosso adapter.


List<String> cidade = new ArrayList<String>();
cidade.add("Recife");
cidade.add("São Paulo");
cidade.add("Santos");
cidade.add("Santa Cruz");

MeuAutoCompleteAdapter adapter =
new MeuAutoCompleteAdapter(
contexto,
android.R.layout.simple_dropdown_item_1line,
cidade);

AutoCompleteTextView actv = (AutoCompleteTextView)
findViewById(R.id.autoCompleteTextView1);
actv.setAdapter(adapter);


O resultado é exibido na figura abaixo:


Qualquer dúvida, deixem seus comentários.

4br4ç05,
nglauber