Es cierto que Lollipop aun no llega a todos los dispositivos, pero desde su antes nombre L ha dado mucho de que hablar. Esta vez, Android, nos ofrece un nuevo lenguaje visual denominado: “Material Design”, que si bien es muy atractivo, no era compatible con las versiones anteriores del Robot de Google.
Poco a poco se han visto aplicaciones que se adaptan a este nuevo diseño, ignorando la versión con la que corren y esto es gracias a herramientas que aprenderemos con este pequeño proyecto. Trate de simplificarlo en pasos muy puntuales, ademas de dos diseños diferentes (uno en cada branch del repositorio), recuerda que cualquier duda me encuentras en twitter como @thespianartist.
Paso 1: Tener actualizado tu entorno de trabajo:
Vale la pena recordar que Android Studio es el IDE oficial para el desarrollo de aplicaciones móviles para Android (incluyendo Wear, Auto y Glass), por lo que si aun trabajas bajo eclipse (pronto sin soporte), ten prioridad en actualizar pronto a este IDE que, actualmente ya dejó de ser Beta y la experiencia de usuario al estar creando proyectos es única.
Así mismo, antes de iniciar cualquier proyecto, es importante ver el conjunto de librerías y SDKs con los que estaremos trabajando y que de igual manera deben estar actualizados. Recuerda que esto se logra gracias al SDK Manager.
Paso 2: Creando el proyecto y agregando las librerías necesarias:
Vamos a crear un nuevo proyecto, en este caso la versión mínima puede ser a partir de Ice Cream Sandwich 4.0 (API 14). Si te preguntas por Gingerbread, la mayoría del marcado ya omite dicha versión, ya que requiere una reducción importante de features y el beneficio de cubrir las mismas ya no es tanto:
Ademas vamos a usar 4 librerías, 2 del SDK oficial y 2 de terceros:
Código :
//Librerias standar en el SDK de Android: //Necesario para usar Toolbar y configurar el Tema Material en V14+ compile 'com.android.support:appcompat-v7:21.0.2' //Libreria para usar un RecyclerView compile 'com.android.support:recyclerview-v7:21.0.0' //Librerias de terceros : //Libreria para agregar un Floating Action Button compile 'com.getbase:floatingactionbutton:1.2.1' //Libreria para volver circular una Imagen compile 'de.hdodenhof:circleimageview:1.2.1'
Recordar que dichas librerías se agregan en el build.gradle que se encuentra a la altura de la carpeta app, tal como se muestra en la siguiente imagen:
¿Cómo buscar una librería?
Un sitio muy recomendable para consultar las librerías compatibles con Android Studio (y contenidas en el repositorio Maven), es Gradle Please. Cuenta con un buscador excelente, que puede ir desde búsquedas muy especificas como el SDK de facebook, hasta mostrarnos las versiones que tienen actualmente las librerías nativas del SDK, como por ejemplo RecyclerView.
Paso 3: AppCompat, crea un tema compatible con todas las versiones
Recordemos un poco como funciona un tema Material Design, la sugerencia siempre son 3 colores: Primary, Primary Dark and Accent.
Esos 3 colores se pueden elegir de acuerdo a las guías de diseño
de material design. Una vez seleccionados, debemos agregarlos en un archivo colors.xml en la carpeta values, tal como se muestra en la siguiente imagen:
Código :
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="primary_color">#E91E63</color> <color name="primary_dark_color">#AD1457</color> <color name="accent_color">#69F0AE</color> </resources>
Ahora modifiquemos styles.xml de la carpeta values, el cual tendrá como tema base AppCompat. AppCompat nos permite dentro de sus muchas propiedades:
1.-Esconder el ActionBar, ya que este será sustituido por un nuevo Widget llamado Toolbar, que es el encargado de dar ese aspecto Material.
2.-Agregar los colores previamente elegidos en colors.xml a toda la aplicación.
Código :
<resources> //Darle el aspecto material, necesitamos configirar <style name="AppTheme" parent="Theme.AppCompat.NoActionBar"> <item name="colorPrimary">@color/primary_color</item> <item name="colorPrimaryDark">@color/primary_dark_color</item> <item name="colorAccent">@color/accent_color</item> </style> </resources>
La ultima configuración que necesita AppCompat para funcionar es nuestra Actividad extienda de ActionBarActivity, no te preocupes, tiene todos los base que tendría un Activity normal :
Código :
public class MainActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main) }
Paso 4: Toolbar, un ActionBar Personalizado
Así como AppCompat nos permite personalizar un tema, toolbar nos permite crear nuestro propio ActionBar, inclusive, al punto de llevarlo a necesidades muy puntuales de personalización. Toolbar se maneja como un archivo toolbar.xml dentro de nuestra carpeta de layout.
Para que quede un poco mas claro las posibilidades del widget, el proyecto se basa en dos configuraciones diferentes:
El primero no es nada ajeno a lo que haz visto antes, se trata de un ActionBar de un tamaño estándar y que hereda el color primario que configuramos:
Código :
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/activity_my_toolbar" android:layout_width="match_parent" android:layout_height="match_parent" android:minHeight="?attr/actionBarSize" android:background="@color/primary_color" app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:popupTheme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
De lo cual, es importante repasar lo siguiente:
android:id="@+id/activity_my_toolbar
Es importante asignarle un ID a nuestro widget,ya que va ser usado por nuestro Activity principal.
android:minHeight="?attr/actionBarSize"
Esto indica el tamaño del widget y si lo quieres ver así, de nuestro ActionBar. Para este ejemplo "heredamos" un párametro llamado actionBarSize que para fines prácticos, es una constante que nos entrega el tamaño por defecto de un ActionBar, ni mas, ni menos.
android:background="@color/primary_color"
Esto indica el color de fondo del ActionBar, para hacer referencia al declarado en colors.xml, lo hacemos mediante @color/primary_color.
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
Esto es importante, vamos a sobreescribir el ActionBar partiendo de un tema base, en este caso se trata de AppCompat.Dark.ActionBar. Esto hace que el fondo por defecto sea negro (Pero en este caso lo cambiamos a primary_color) y la letra de titulo sea color blanca. Si quisiéramos que el color de texto fuera negro, basta extender de AppCompat.Light o de cualquiera de los temas disponibles:
app:popupTheme="@style/ThemeOverlay.AppCompat.Dark.ActionBar
Esto es lo mismo para lo anterior solo que aplicable al contexto de los menús, podemos decidir si un menú se presenta del mismo tema o diferente al del ActionBar. Esto quiere decir que podemos tener un tema exclusivo para la aplicación y otro propio para el menú. En este caso lo deje igual, pero es elección tuya iterar sobre todas las posibilidades.
Una vez elegidos configurado el Toolbar procedemos a setearlo en nuestra Actividad, es muy sencillo, lo que hacemos primero es el llamado como objeto del Widget:
Código :
Toolbar toolbar = (Toolbar) findViewById(R.id.activity_my_toolbar);
Y de inmediato setearlo:
Código :
setSupportActionBar(toolbar);
En nuestra actividad principal, en nuestra vista activity_main.xml, heredamos el Toolbar que creamos como toolbar.xml (Debe ser siempre el primer Widget), tal como se muestra en la siguiente imagen:
Código :
<include layout="@layout/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" />
Como un paso opcional podemos cambiar el nombre del ActionBar, la siguiente imagen muestra el código implementado:
Y listo, ya tenemos el UI de la aplicación totalmente configurada, que queda de la siguiente manera:
Si notaste, en versiones anteriores a Lollipop, el StatusBar no cambia de color, pero en Android 5.0 si lo hace, pero a pesar de eso, conservan ese mismo look Material Design, y totalmente compatible para todos. Ahora veamos su segunda variante:
Lo único que cambia es el tamaño del ActionBar, que pasa de ser estándar a ser un poco grande (100dp), cosa que antes era imposible sin Toolbar, después puedes usar tu imaginación, podrías agregar widgets del tipo Button, ImageView o hasta Fragment.
Código :
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/activity_my_toolbar" android:layout_width="match_parent" android:layout_height="match_parent" android:minHeight="100dp" android:background="@color/primary_color" app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:popupTheme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
Paso 5: Agregando un Floating Action Button
No hay duda que Floating Action Button es un elemento que de inmediato lo relacionamos con Material Design, existen muchas formas de agregarlo, pero esta vez, optare por una librería hecha especialmente para ello (recordar que ese librería la agregamos en el paso 2):
Lo único que tenemos que hacer es agregar el widget en la vista que queremos, la configuración básica de la librería es:
Código :
<com.getbase.floatingactionbutton.FloatingActionButton android:id="@+id/pink_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" fab:fab_icon="@drawable/ic_add" fab:fab_colorNormal="@color/accent_color" fab:fab_colorPressed="@color/accent_color" />
Donde:
android:id="@+id/pink_icon"
Es el id que le asignamos al botón, con ello, podemos manipularlo fuera de nuestra vista, como por ejemplo, escuchar eventos "onClick"
android:layout_width="wrap_content"
Siempre se debe configurar el ancho con el contenido que necesite, nunca con todo el disponible.
android:layout_height="wrap_content"
Siempre se debe configurar el alto con el contenido que necesite, nunca con todo el disponible.
fab:fab_icon="@drawable/ic_add"
Es el icono dentro del botón, y dicho icono es una imagen contenida dentro de nuestras carpetas drawable, como tip Google tiene como descarga todos los iconos basados en Material Design.
fab:fab_colorNormal="@color/accent_color"
fab:fab_colorPressed="@color/accent_color"
Y estos últimos son los colores que tendrá el botón, precisamente como recomendación es el color Accent, configurado previamente en colors.xml.
Lo se, nuestro diseño muestra dos variaciones y parecieran muy diferentes entre ellas, pero lo único que cambia de nuestro botón es la posición, nada mas. La siguiente imagen muestra los cambios entre ellos (recuerda que todo el código se menciona en el paso 1):
Realmente ya configuramos lo importante del UI, esto es la base de una aplicación Material Design, todo lo demás depende mucho de lo que quieras hacer: Tabs, Navigation Drawer, Listas, etc. Solo como ejemplo, en este casó, use un RecyclerView para desplegar una lista de elementos, no seré muy especifico ya que fue algo que nos enfocamos mucho en otro tutorial.
Paso 6: Nuestro viejo amigo RecyclerView
Ya como punto final de este pequeño proyecto, tenemos a un viejo conocido, un RecyclerView. Recordar que en un RecyclerView se crea:
Un modelo (En este caso se llama Pusheen.java):
Código :
public class Pusheen { private Integer id; private String name; private String pasTime; public String getPasTime() { return pasTime; } public void setPasTime(String passTime) { this.pasTime = passTime; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
Una Vista (row.xml dentro de layout y es donde ademas usamos la librería para imágenes circulares):
Código :
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:layout_marginLeft="16dp" android:layout_marginTop="10dp" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <de.hdodenhof.circleimageview.CircleImageView android:id="@+id/image" android:layout_width="56dp" android:layout_height="56dp" android:src="@drawable/pusheen"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:text="Pusheen" android:id="@+id/name" android:textStyle="bold" android:textColor="#424242" android:layout_alignParentTop="true" android:layout_toRightOf="@+id/image" android:layout_toEndOf="@+id/image" android:layout_marginLeft="16dp" android:layout_marginTop="10dp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceSmall" android:text="pastime" android:textColor="#424242" android:id="@+id/passtime" android:layout_below="@+id/name" android:layout_alignLeft="@+id/name" android:layout_alignStart="@+id/name" /> </RelativeLayout>
Un Adapter (PusheenAdapter.java):
Código :
package la.mejorando.prelollipopmaterialdesign.adapters; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import java.util.ArrayList; import la.mejorando.prelollipopmaterialdesign.R; import la.mejorando.prelollipopmaterialdesign.models.Pusheen; /** * Created by thespianartist on 07/12/14. */ public class PusheenAdapter extends RecyclerView.Adapter<PusheenAdapter.ViewHolder> { private ArrayList<Pusheen> pusheenArrayList; private int itemLayout; public PusheenAdapter(ArrayList<Pusheen> data, int itemLayout){ this.pusheenArrayList = data; this.itemLayout = itemLayout; } public static class ViewHolder extends RecyclerView.ViewHolder { public ImageView image; public TextView name; private TextView pasTime; public ViewHolder(View itemView) { super(itemView); image = (ImageView) itemView.findViewById(R.id.image); name = (TextView) itemView.findViewById(R.id.name); pasTime = (TextView) itemView.findViewById(R.id.passtime); } } @Override public PusheenAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int i) { View itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(itemLayout, parent, false); ViewHolder viewHolder = new ViewHolder(itemLayoutView); return viewHolder; } @Override public void onBindViewHolder(PusheenAdapter.ViewHolder viewHolder, int position) { Pusheen pusheen = pusheenArrayList.get(position); viewHolder.name.setText(pusheen.getName()); viewHolder.pasTime.setText(pusheen.getPasTime()); if (pusheen.getId()!=null) { switch (pusheen.getId()) { case 1: viewHolder.image.setImageResource(R.drawable.pusheen); break; case 2: viewHolder.image.setImageResource(R.drawable.pusheen2); break; case 3: viewHolder.image.setImageResource(R.drawable.pusheen3); break; case 4: viewHolder.image.setImageResource(R.drawable.pusheen4); break; case 5: viewHolder.image.setImageResource(R.drawable.pusheen5); break; } }else{ viewHolder.image.setImageResource(R.drawable.pusheen); } viewHolder.itemView.setTag(pusheen); } @Override public int getItemCount() { return this.pusheenArrayList.size(); } }
y propiamente el Widget dentro de la vista
Código :
<android.support.v7.widget.RecyclerView android:layout_marginTop="?attr/actionBarSize" android:id="@+id/my_recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" />
Y eso es todo, tenemos un lindo proyecto Material Design para versiones anteriores a Lollipop, les dejo una ultima imagen de la aplicación vista en horizontal:
Recuerden que si tienen alguna pregunta no olviden consultarme en twitter @thespianartist, les dejo de nuevo el repositorio del ejemplo (Recuerden que tiene dos branches). Ademas, me gustaría saber si esto aporto en sus proyectos actuales (:
¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.
Por Dario Guzman el 13 de Diciembre de 2014
Por Alink el 18 de Diciembre de 2014
Por thespianartist el 22 de Diciembre de 2014
Alink-blog :
Por el toolbar por defecto no, sin embargo existen opciones. No lo recomiendan tanto, pero es posible (:
Por el 26 de Enero de 2015
Muy interesante el artículo, pero tengo un problema.
El caso es que yo intento integrar esta librería con gradle, pero primero, que si utilizo la versión 1.6, me da error, y tengo que bajar a la 1.5.
Y lo segundo, que no me actualiza estos campos:
fab:fab_plusIconColor="#FFFFFF"
fab:fab_colorNormal="#FF0000"
fab:fab_colorPressed="#990000"
Me da este error cuando intento importar la 1.6
Rendering Problems The following classes could not be instantiated:
- com.getbase.floatingactionbutton.AddFloatingActionButton (Open Class, Show Exception)
Tip: Use View.isInEditMode() in your custom views to skip code or show sample data when shown in the IDE Exception Details java.lang.NoSuchFieldError: FloatingActionButton_fab_colorDisabled at com.getbase.floatingactionbutton.FloatingActionButton.init(FloatingActionButton.java:7
at com.getbase.floatingactionbutton.AddFloatingActionButton.init(AddFloatingActionButton.java:36)
at com.getbase.floatingactionbutton.FloatingActionButton.<init>(FloatingActionButton.java:66)
at com.getbase.floatingactionbutton.AddFloatingActionButton.<init>(AddFloatingActionButton.java:23)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:806)
at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:64)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:782)
at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
at android.view.LayoutInflater.inflate(LayoutInflater.java:385)
Copy stack to clipboard
alguna idea? gracias.
Por juan el 14 de Febrero de 2015
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:ignore="MergeRootFrame">
<include
layout="@layout/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</FrameLayout>
este es el xml de fragment
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity$PlaceholderFragment" >
<ListView
android:id="@+id/listView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
tools:ignore="RtlHardcoded" >
</ListView>
</RelativeLayout>
gracias
Por Tathan0411 el 27 de Febrero de 2015
muchas gracias
Por Cesar el 17 de Junio de 2015
Por fercho el 21 de Junio de 2015
the following classes could not be found:
android.support.v7.widget.Toolbar
tengo instalada la versión 1.2.2 de android studio y seguí los pasos anteriores
cual seria la solución?
gracias
Por RafelCF el 26 de Julio de 2015
case 1: //stats
Intent intent = new Intent(getApplicationContext(), CadeteActual.class);
startActivity(intent);break;
Por Francisco el 01 de Septiembre de 2015
Por Fernando el 17 de Mayo de 2016