3

"Resumen" Curso Definitivo de Android - Parte 1

Lo necesario para empezar a desarrollar en Android

  • Java Development Kit (JDK) 7 (Mínimo) (Esto porque Android Studio usa la JVM y Dalvik(ART) para compilar tu aplicación).
  • Android Studio (Es el IDE oficial para desarrollar en Android).
  • Software Development Kit (SDK) (De las versiones de Android).
    • Las SDKs son independientes de las actualizaciones de Android Studio, debes tenerlas al día.
    • En el SDK Manager (settings > SDK Manager) encontrarémos 3 categorías.
      • Tools : Paquetes que necesita Android Studio para compilar y ejecutar.
      • SDK API (level) : También se pueden descargar Samples del SDK y System Images para usar el emulador nativo de Android Studio
      • Extras : Incluye todas las librerias oficiales de Google; además de herramientas que mejorarán tu experiencia al ejecutar las aplicaciones.
  • El Emulador nativo de Android Studio es bueno pero consume muchos recursos. Anahí recomienda Genymotion. Existen además emuladores alternativos.
  • Si necesitas una guía o estándar a seguir, ya hay una propuesta por la comunidad de desarrollo en GitHub.
  • Si necesitas librerías y recursos.

Arquitectura de una aplicación en Android

Arquitectura

  • Librerías de código
  • Archivos de recursos y vistas (las vistas suelen estar en formatos .xml)
  • Código fuente (normalmente en Java o Kotlin)
  • Android Manifest (toda la interacción que tendrá el exterior con la app se define acá)

Ejecutable

  • Se empaqueta en formato .apk
  • Contiene archivos .dex que son el código fuente empaquetado y optimizado y librerías.
    • Bytecode : classes.dex
    • Native code : libs/<arch>/*.so
  • Resources, es necesario buscar optimizar los recursos para mejorar el peso y rendimiento de la app.
  • res/
  • resources.arsc
  • Misc (misceláneos)
    • assets/
    • META-INF/
    • AndroidManifest.xml

Android Studio

Estructura del proyecto

  • Una vez se ha creado un nuevo proyecto, encontrarás los siguientes directorios:
    • App
      • manifests
        • AndroidManifest.xml (tiene toda la información que relaciona el sistema operativo y el hardware)
      • java (todos los controladores, lo que procesa los recursos y la interfaz, la muestra y hace funcionar)
      • res (los recursos del proyecto)
        • drawable (todas las imágenes)
        • layout (las estructuras de las interfaces en .xml)
        • menu (los menús de la aplicación)
        • mipmap (todos los íconos de la app)
        • values (todos los valores almacenados de la app)
          • colors.xml (los valores de los colores que distinguen la app)
          • dimens.xml (todo lo relacionado a dimensiones: margin, padding, etc)
          • strings.xml (todas las cadenas de texto de la app)
          • styles.xml (los temas que usa nuestra app - tiene que ver con material design)
    • Gradle Scripts
      • build.gradle (Module: app)
        • acá en la sección dependencies se incluyen las dependencias que se usarán en la app.
        • En la sección android se definen cosas como la version de SDK que compila, la versión mínima y target del SDK y mñas.

Java POJOS (Plain Old Java Object)

  • Los POJOS son clases simples, lo más simple posibles.
  • POJOs es utilizado para describir estructuras de objetos.
  • Un problema complicado hacerlo simple inspirándonos en objetos, abstraer sus atributos y convertir estos objetos en POJOs.

Ejemplo de POJO:

  • en: app > java > package : puedes hacer click derecho y crear una nueva clase.
  • En esta clase defines inicialmente los atributos del objeto.
  • Luego, normalmente, estebleces los métodos Getter & setter, puedes hacer click derecho y presionar generate, seleccionas el método, sombreas los atributos sobre los que quieres aplicar los métodos y ¡listo!

  • Aunque los POJOs no debería Heredar ni implementar. En caso de que se necesite hacer transferencia de objetos, bien se puede usar la interfaz Serializable. Esto es una excepción a la regla. - Diferencia entre Serializable y Parceable -

Arquitectura MVC - Modelo Vista Controlador

  • Todas las vistas están en Código .xml
  • El controlador maneja toda la interacción de las vistas, todo lo que ahí sucede está definido en el controlador (java)
  • El modelo hace referencia a la representación que le damos a nuestro proyecto, a nuestro negocio, y lo que lo compone, en código (estructuras de datos, bases de datos).

  • Las vistas están ubicadas en res > layout
  • Los controladores son los archivos java en app > java > package
  • Los modelos suelen ser los POJOs que creamos, estos, por cuestiones de orden, suele ser positivo archivarlos en un nuevo package llamado models en: **app > java > package **> models.

  • Nuestro controlador llama su vista desde el método:
setContentView(R.layout.mi_vista)
  • Los modelos se llaman creando un nuevo objeto de la clase del modelo:

Ejemplo

Alumno alumno = new Alumno();
alumno.setNombre("Carlos Salazar");
alumno.setFechaNacimiento(new Date());
alumno.setNumero_cuenta(1234567);

LinearLayout vs RelativeLayout

View

  • Es un objeto que sirve para dibujar algo en la pantalla, con el cual el usuario pueda interactuar. Básicamente todo lo que compone nuestra interfaz es un view.

ViewGroup

  • Es un objeto que se compone de otros views ordenados, dando como resultado un Layout.

LinearLayout

  • Es un ViewGroup que alinea a todos los hijos en una sola dirección, Vertical u Horizontal.

RelativeLayout

  • Es un ViewGroup que alinea a todos los hijos en posiciones relativas. Se pueden alinear en relación a:
    • otro View
    • la etiqueta Padre

ListView y GridView

ScrollView

  • Es un ViewGroup que permite hacer scroll en su contenido. Debe en ciertos casos para evitar contenido cortado.

FrameLayout

  • Es un ViewGroup que organiza los elementos uno encima de otro. Por defecto agrupa los elementos en la parte superior izquierda, recuerda acomodarlos como necesites usando layout_gravity y padding.

ConstraintLayout

  • Es un ViewGroup que permite hacer la vista de forma responsive, adapable a todo tipo de diseño por sus propiedades relativas.
  • Completamen+te sencillo de usar desde el editor gráfico.

CoordinatorLayout

  • Es el Layout padre, engloba toda la pantalla utilizable por la app.
  • Ayuda a especificar comportamientos e interacciones en los views hijos (como animaciones).
  • Permite vistas flotantes, es decir, vistas con elevación (propiedad elevation) y sombras.

Layouts tips

  • Lo contenido dentro de la etiqueta son las propiedades del view.

Widgets Básicos XML

  • TextView = Label.
  • EditText = Un campo para ingresar texto. Se define el tipo de contenido a ingresar con la etiqueta:
android:inputType="TIPO DE TEXTO"
  • Button = Puede contener texto e imagen con texto.
    • ImageButton = Boton que contiene sólo una imagen.
    • Para asignar una acción al botón:
      • Dentro de las propiedades del layout se puede definir un “onClick” que haga referencia a un método ya definido en el controlador Java respectivo.
      • Se puede definir un “setOnClickListener”.
      android:onClick="[metodo]"
      • Este método debe estar creado en el controlador java recibiendo un parámetro de tipo view, que en este caso será el mismo view.
      public void [metodo](View view) {}
      

Aplicación

  • Suele ser una buena práctica, asignar un id a cada view:
android:id="@+id/[id_asignado]"
  • Para los EditText, la propiedad hint es el texto que se muestra como ejemplo al usuario hasta que se posicione sobre este elemento.

Widgets Básicos JAVA

Todo view agregado en el xml ya tiene vida, es decir, ya es un objeto creado que tiene una referencia en memoria, en este caso la referencia es el id que le asignamos. Con este id podemos acceder a ese objeto desde el controlador JAVA.

Para acceder a la referencia, debemos entender que es tomado en cuenta como un “recurso”, estas referencias son almacenadas dentro de un archivo denominado R, por ello, para acceder a ellas debemos pasar por R.

Ejemplo en Java

EditText edtNombre = findViewById(R.id.[identificador])

Si te das cuenta, luego de R accedimos a id. Así mismo se puede obtener cualquier recurso de R.drawable.XXX, R.dimen.xxx, R.string.XXX*, etc.


  • Toast = Es un mensaje que nos notifica o nos dá retroalimentación sobre alguna acción realizada. No tiene un xml, se define directamente desde el código controlador JAVA.

Ejemplo para evento onClick. Recibe la información de un TextView y la muestra a través de un Toast.

public void enviarDatos(Viewview) {
        EditText edtNombre = (EditText) findViewById(R.id.nombre);
        String nombre = edtNombre.getText().toString();

        Toast.makeText(getBaseContext(),"Felicidades, tu nombre es " + nombre, Toast.LENGTH_LONG).show();

    }
  • Toast.makeText invoca al objeto Toast y a su método para escribirle texto.
  • Los parámetros que pide son:
    • (1.Contexto, 2.Mensaje, 3.Duración)
    • luego de definidos los parámetros, se le dice al Toast que se muestre con .show().

Material Design

  • https://www.materialpalette.com : Te permite generar una paleta a partir de 2 colores que seleccionas. Además te ofrece un preview de interfaz con los colores de la paleta.
  • Material Design tiene como fundamento que todo elemento debe tener dinamismo, generarle al usuario la sensación de que realmente interactua con la app.
  • Las librerías de material design son:
    • @android:style/Theme.Material (para el tema obscuro)
    • @android:style/Theme.Material.Light (tema claro)
    • @android:style/Theme.Material.Light.DarkActionBar (tema claro con action bar obscura)
  • Theme.AppCompat (es la libreria que nos da la compatibilidad de Material Design en versiones anteriores.
    • Theme.Material (obscuro)
    • Theme.AppCompat.Material (claro)

Tema

  • El tema, el estilo de la app está configurado en el archivo styles.xml (res > values > styles.xml)
  • Entre los diversos elementos que se pueden definir en el styles.xml, están:
    • colorPrimary
    • colorPrimaryDark (barra de notificaciones de android)
    • textColorPrimary
    • windowBackground
    • navigationBarColor

Configurando nuestro tema Material

res > values > styles.xml

  • en : https://material.io/tools/color/ se pueden encontrar distintas paletas de colores ofrecidas por Google.
  • https://www.materialpalette.com es una herramienta excelente para generar paletas.
  • Todos los colores están definidos en res > values > colors.xml
    • El colorPrimary normalmente debe ser un color 500 de intensidad.
    • El colorPrimaryDark suele ser 200 más intenso que el colorPrimary, es decir, 700 de intensidad.
    • Los colores de acentuación o colorAccent son aquellos con una letra A antes de la intensidad. Ej: A200

Widgets de Material Design

Material Design ofrece una librería de soporte con estos widgets y que además son compatibles con versiones anteriores android.support.v7.widget.Cardview

  • ToolBar
  • TextInputLayout
    • TextInputEditText (por defecto toma el colorAccent)
  • Raised Button
  • Floating Action Button
  • CardView
  • RecyclerView (sustituye ListView)

Más información sobre las librerías de soporte de Google - https://developer.android.com/topic/libraries/support-library/features.html#v7

Activity

  • Son las diversas “pantallas” dentro de Android. Es sumamente importante tener el mayor control posible sobre el comportamiento de las actividades para así causar una mejor experiencia al usuario.
  • En Android Nativo todas las pantallas (activities) deben estar compuestas de dos archivos:
    • Un archivo Java con un objeto que herede de la clase Activity. Este archivo es el que controla la Interfaz.
    • Un Layout (.xml) que contiene la interfaz gráfica. Este archivo es el que el Java se encargará de mostrar en pantalla.
  • Todo activity debe estar declarado en el AndroidManifest.xml
<activityandroid:name=".NombreActivity"><intent-filter><actionandroid:name="android.intent.action.MAIN" /><categoryandroid:name="android.intent.category.LAUNCHER" /></intent-filter></activity>
  • intent-filter : Le da instrucciones al sistema sobre que abrir cuando detecta cierta acción (se usa únicamente para definir y lanzar la pantalla inicial)
    • action…MAIN : Le dice al sistema que al abrir la aplicación, la primera pantalla que muestre será esta.
    • category…LAUNCHER : Ejecuta el lanzador, ya sabiendo que esta es la pantalla inicial.

Creando un Activity

  • Como buena práctica, el controlador (JAVA) del Activity inicial siempre estará en el primer nivel del package y los demás controladores (JAVA) de los Activity’s los ubicaremos en una nueva carpeta app > java > [paquete] > view.
  • Ubicados sobre la nueva carpeta hacemos click derecho y seleccionamos New > Activity > Empty Activity.
  • Colocamos el nombre del Activity (NombreActivity) y automáticamente se creará su layout .xml relacionado (activity_nombre).

Ciclo de vida (resumen por @JuanGonzalez97)

  • onCreate(Bundle): Se llama en la creación de la actividad. Se utiliza para realizar todo tipo de inicializaciones, como la creación de la interfaz de usuario o la inicialización de estructuras de datos. Puede recibir información de estado de la actividad (en una instancia de la clase Bundle), por si se reanuda desde una actividad que ha sido destruida y vuelta a crear.

  • onStart(): Nos indica que la actividad está a punto de ser mostrada al usuario.

  • onResume(): Se llama cuando la actividad va a comenzar a interactuar con el usuario.

  • onPause(): Indica que la actividad está a punto de ser lanzada a segundo plano, normalmente porque otra actividad es lanzada.

  • onStop(): La actividad ya no va a ser visible para el usuario.

  • onRestart(): Indica que la actividad va a volver a ser representada después de haber pasado por onStop().

  • onDestroy(): Se llama antes de que la actividad sea totalmente destruida. Por ejemplo, cuando el usuario pulsa el botón de volver o cuando se llama al método finish().

Maquetando nuestros activities

  • Una buena manera de guiarnos para iniciar un Layout es crear uno básico de referencia para poder ver la estructura que contiene. Por ejemplo para ver la estructura inicial del CoordinatorLayout.
  • Si copias el Layout de otro Activity, recuerda modificar el tools:context… para que haga referencia al controlador (JAVA) correcto.

namespace


Imagenes densificadas

  • Todas las imagenes deben ser densificadas. La resolución de la imagen debe corresponder a las distintas densidades de pantallas disponibles (ldpi, mdpi, hdpi, xhdpi, xxhdpi, xxxhdpi, tvdpi). Esto se hace con el fin de evitar la pérdida de resolución de la imagen al ser vista desde distintos dispositivos con distintas densidades de pantalla.
  • El plugin Android Drawable Importer nos ayuda con la densificación de las imagenes.
    • En Drawable hacemos click derecho y seleccionamos ** New > Batch Drawable Import**. En esta nueva pantalla seleccionamos el archivo a importar y luego nos permite definir cual es la densidad original de la imagen e incluir las densidades que queremos generar mediante el plugin. Al presionar aceptar, se crearán todas las versiones de densidad seleccionadas.

Textos

  • Como buena práctica, TODOS los textos deben declararse en ** app > res > values > strings.xml**.
  • Se les debe asignar un name, que será la variable por la que podrá ser llamada y el texto que se quiere mostrar. EJ.
<stringname="variable_string">Soy un texto</string>
  • Para llamarlo desde cualquier otro elemento, se usa:
android:xxxxx="@string/variable_string"
  • Para cambiar el tamaño del texto, es necesario crear la variable en el archivo dimens para que pueda ser añadida esta propiedad al texto con:
android:textSize="@dimen/VARIABLE"
  • La unidad de medida recomendada para el tamaño de texto es sp, en lugar de dp.
  • Si le quieres añadir un estilo personalizado a un TextInputLayout - TextInputEditText, debes hacerlo en el TextInputLayout a través de:
android:theme="@style/NOMBRE DE ESTILO

Internacionalización de texto

  • Android nos permite generar versiones de multiples idioma tomando en cuenta las variables en el archivo strings.xml
  • Para crear otro idioma:
    • Se debe crear un nuevo “Values Resource File” en el directorio Values con el nombre strings pero este debe tener un Available qualifier de tipo Locale. Una vez lo asignas, verás la lista de idiomas con su respectiva etiqueta para agragarla y así generar una nueva carpeta values-XX, donde estarán el archivo strings con el idioma correspondiente.
    • El nuevo archivo strings estará vacío y debes agregar en el, todas las variables de texto que necesites traducir desde el archivo original, y cambiar el texto por el idioma correspondiente.

Creando un estilo personalizado

  • En el archivo styles están definidos los estilos, cada estilo con una etiqueta style:
<stylename="CLASE u OBJETO"parent="SUELE SER EL TEMA PADRE"></style>
  • Dentro de esta etiqueta se definen los items
<itemname="VARIABLE">NUEVA CARACTERISTICA</item>
  • Por ejemplo, para crear el nuevo estilo de RaisedButtonDark:
<style name="RaisedButtonDark" parent="Theme.AppCompat.Light">
    <itemname="colorButtonNormal">@color/colorPrimaryDark</item>
    <itemname="colorControlHighlight">@color/colorPrimary</item>
    <itemname="textColor">@android:color/white</item>
</style>
  • Donde:
    • RaisedButtonDark = El objeto al que queremos aplicar el estilo.
    • Theme.AppCompat.Light = Es el Tema padre del cual estaremos tomando el estilo original.
    • colorButtonNormal = Es el color de fondo que tiene el botón.
    • colorControlHighlight = Es el color del botón cuando es presionado.
    • textColor = Es el color del texto del botón.
    • @android:color/white = Hace referencia a los colores ya predefinidos en android.
  • Para aplicar el estilo, tendrás que hacerlo agregando android:theme="@style/NAME DEL STYLE". Un EJ. siguiendo el ejemplo anterior:
<Button
android:id="@+id/login"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/text_button_login"
    android:theme="@style/RaisedButtonDark"
    />

EditText con Material Design

  • EJ de estilo:
<style name="EditTextWhite" parent="TextAppearance.AppCompat">
    <itemname="android:textColorHint">@color/textColorWhite</item>
    <itemname="android:textSize">@dimen/edittext_textsize_login</item>
    <itemname="android:textColorPrimary">@color/textColorWhite</item>
    <itemname="colorAccent">@color/textColorWhite</item>
    <itemname="colorControlNormal">@color/textColorWhite</item>
    <itemname="colorControlActivated">@color/textColorWhite</item>
</style>
<android.support.design.widget.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:passwordToggleEnabled="true"
    android:theme="@style/EditTextWhite"
    >

    <android.support.design.widget.TextInputEditText
        android:id="@+id/password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/hint_password"
        android:inputType="textPassword"
        />

</android.support.design.widget.TextInputLayout>

Toolbar

  • Cuando trabajamos con un Toolbar, es necesario que el ViewGroup que le sigue, tenga la siguiente propiedad para que se acomode bajo el Toolbar y no superpuesto:
app:layout_behavior="@string/appbar_scrolling_view_behavior"
  • La Toolbar suele ser un elemento que no está en todas las Activity’s de nuestra app, por lo tanto, suele ser más práctico hacer un archivo .xml propio para la Toolbar y luego llamarlo donde sea necesario, con:
<include layout="@layout/actionbar_toolbar"/>
  • Recuerda incluir en la Toolbar los namespaces que necesita; y que no es necesario que el actionbar_toolbar.xml inicie con algún ViewGroup. Debe iniciar directamente con:
<android.support.design.widget.AppBarLayoutxxxxxxxxxxxxxxxxxx;
	>
  • Una vez creada la lista de la Toolbar, necesitamos hacer que se muestre a través del controlador (JAVA) de la Activity sobre la que trabajamos.
  • Lo ideal es crear el siguiente método para poder reutilizarlo:
public void showToolbar(String tittle, boolean upButton){
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    getSupportActionBar().setTitle(tittle);
    getSupportActionBar().setDefaultDisplayHomeAsUpEnabled(upButton);
}
  • Donde:

    • String tittle = Es el título que se mostrará en la Toolbar.
    • boolean upButton = Es lo que nos confirma si tenemos, o no, un botón de regreso (Ya que no todas nuestras Activity’s necesitarán un botón de regreso)
    • Toolbar toolbar = (Toolbar) findViewByid = Crea un objeto de tipo toolbar y lo relaciona la vista (.xml) del elemento con el id que definimos.
    • setSupportActionBar = Hace que el nuevo objeto toolbar tenga soporte en versiones anteriores de Android.
  • Una vez está definido el método, es necesario invocarlo en el método onCreate de la Activity, sin embargo, debemos definir los parámetros que recibirá el método.

    • tittle : Para el título creamos una nueva variable string y la forma de llamar este recurso en la invocación del método es:
showToolbar(getResources().getString(R.string.[VARIABLE STRING]),false);
  • Donde false responde al parámetro boolean upButton.

Intents

Siempre que queramos unir distintos componentes, debemos usar la clase Intent y crear un objeto Intent.

  • Explicitos = Para conectar un componente con otro, dentro de la misma app.
  • Implicitos = Conectan componentes desde una app a otra.

Cuando se usa un Intent, la nueva Activity que se inicia siempre pasará por el método onCreate.


Aplicando un Intent

  • Para iniciar, es necesario que tengamos algún view que desencadene un evento, como un onClick(FUNCION).En el archivo controlador (JAVA) correspondiente se define ese método (recuerda que debe recibir como parámetro (View view).
  • Dentro del método, se crea un objeto intent que recibirá como 1er parámetro el contexto actual, la Activity donde está ubicado; y como 2do parámetro recibirá la Activity objetivo, colocando el sufijo .class.
  • Para finalizar invocamos stratActivity(intent) y esto será todo. EJ.
publicvoidgoCreateAccount(View view){
	Intent intent = new Intent(this, CreateAccountActivity.class);
	startActivity(intent);
}

Botón Back vs Botón Up

  • Botón Back
    • Destruye la Activity y regresa en un orden cronológico inverso al que venimos manejando en la app. No podemos controlarlo por defecto.
  • Botón Up
    • Regresa a una Activity superior en nivel de Jerarquía.
    • Para crear un Botón Up, es necesario establecer las jerarquías en el Android Manifest. En este caso, a la Activity hijo, le indicarémos cual es su actividad padre:
<activityandroid:name=".view.CreateAccountActivity"android:parentActivityName=".LoginActivity"
     ><meta-dataandroid:name="android.support.PARENT_ACTIVITY"android:value=".LoginActivity"
          /></activity>
  • Donde:
android:parentActivityName=".LoginActivity"
- Establece directamente la relación con la Activity padre, pero sólo funciona desde Lollypop en adelante.
  • Y
<meta-data
    android:name="android.support.PARENT_ACTIVITY"
    android:value=".LoginActivity"
/>
- Le damos soporte al establecimiento de la relación con una actividad padre, definida en **value**.
  • Luego, debemos situarnos en el controlador (JAVA) del Activity en cuestión, y en el método que creamos para generar la Toolbar, ya tiene sentido que colocaramos la recepción del parámetro upButton (que ahora debe ser true donde invocamos el método) y la función getSupportActionBar().setDisplayHomeAsUpEnabled(upButton) que es la que define la existencia del botón.

CardView

  • Es un ViewGroup que nos permite mostrar información dentro de “tarjetas”. Se pueden modificar los bordes y añadir sombras si lo deseamos.
  • La etiqueta CardView proviene del soporte.
  • Dentro de CardView debemos organizar el resto del los Views en Layouts.
  • Para poder usar CardView es NECESARIO añadir la librería de soporte correspondiente en Gradle (app).
  • CardView necesita de ciertas propiedades obligatorias:
    • android:id="@+id/id"
    • android:layout_width=“match_parent”
    • android:layout_height=""
  • Una buena práctica es mantener el CardView en un Layout separado porque suele contener muchos elementos, y para usarlo repetidas veces es mejor simplemente incluir un Layout que copiar y copiar tanto código.
  • CardView tiene sus propias propiedades y por eso necesita si propio namespace:
xmlns:cardview="http://schemas.android.com/apk/res-auto"
  • Las propiedades podemos verlas escribiendo cardview:. Ej.
cardview:cardCornerRadius=""

Personalizar estado de CheckBox

  • Es necesario crear un nuevo Layout Resource en el directorio ** app > res > drawable >**. Este recurso puede hacer referencia directa al checkbox selector sin problemas. Ej: checkbox_selector.xml
  • En este nuevo recurso ubicado en drawable aplicarémos la siguiente lógica:
<selectorxmlns:android="http://schemas.android.com/apk/res/android"><itemandroid:drawable="@drawable/heart"android:state_checked="false"></item><itemandroid:drawable="@drawable/heart_full"android:state_checked="true"></item><itemandroid:drawable="@drawable/heart"></item></selector>
  • Muestra la imagen del corazón vacío (heart), si el estado del selector es false.
  • Muestra la imagen del corazón lleno (heart_full), si el estado del selector es true.
  • Por defecto, el selector tendrá la imagen del corazón vacío (heart)
  • Luego, dentro del CheckBox podemos hacer referencia al selector definido, de la siguiente manera:
android:button="@drawable/checkbox_selector"

BottomNavigationView

  • Para poder usar este widget, es necesario que incluyas las librerías de soporte de diseño y compatibilidad:
dependencies {
    implementation 'com.android.support:appcompat-v7:X.X.X'
    implementation 'com.android.support:design:X.X.X'

    // donde X.X.X es la versión que prefieras usar
}
  • En primer lugar debemos generar un nuevo Layout para nuestro BottomNavigationView, este View debe tener asociado un menu:
<android.support.design.widget.BottomNavigationView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/bottombar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_gravity="bottom|end"

    android:background="@color/colorPrimary"
    app:itemBackground="@drawable/bottombar_itembackground"
    app:itemIconTint="@color/textColorWhite"
    app:itemTextColor="@color/textColorWhite"

    app:menu="@menu/bottombar_menu"
    />
  • El menú contendrá los botones del BottomNavigationView, cada item deberá tener un id, title e icon.
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/search"
        android:title="@string/tab_search"
        android:icon="@drawable/ic_search"
        />
    <item
        android:id="@+id/home"
        android:title="@string/tab_home"
        android:icon="@drawable/ic_home"
        />
    <item
        android:id="@+id/profile"
        android:icon="@drawable/ic_user"
        android:title="@string/tab_profile" />
</menu>
  • Si regresas al primer punto, verás app:itemBackground="@drawable/bottombar_itembackground", es decir, que al fondo de cada botón le estamos asignado no sólo un color. Este recurso bottombar_itembackground contiene lo siguiente en este caso:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true" android:drawable="@color/colorPrimaryDark"/>
    <item android:state_pressed="true" android:drawable="@color/colorPrimaryDark"/>
    <item android:drawable="@color/colorPrimary" />
</selector>
  • Por defecto el botón tendrá el colorPrimary.

  • Cuando el botón sea presionado y cuando esté seleccionado, tendrá el colorPrimaryDark.

  • Listo, ya el ButtonNavigationView tiene el estilo que deseamos.

Desde este sitio obtuve la información para hacerlo


RecyclerView

  • Está pensado como el sustituto de ListView, sencillamente por su nivel de eficiencia. En lugar de cargar todos los elementos listados, carga sólamente los que puedan ser mostrados en pantalla y va mostrando el resto a medida que se hace slide.
  • RecyclerView no sólo muestra sus elementos en forma de lista, sino también en forma de cuadrícula y escalonada.
  • Estructura:
    • RecyclerView = Compuesto del controlador (java) y el Layout .xml.
      • LayoutManager = Que está relacionado directamente al RecyclerView, este es el que define el tipo de Layout que se mostrará:
        • Lista (LinearLayoutManager)
        • Cuadrícula (GridLayoutManager)
        • Escalonada (StaggeredGridManager)
      • Adapter se compone de dos clases principales:
        • Clase Adapter = Que establecerá la relación entre la lista de elementos y el RecyclerView, será como la configuración.
        • Clase ViewHolder = Que gestionará todos los Views de cada elemento particular de la lista que se pasará al RecyclerView.
      • Dataset (POJO) = Será el modelo que seguirá nuestra CardView o cualquier elemento que sea nuestra unidad de lista.

Implementación del RecyclerView

  • Importa la librería de RecyclerView en Graddle (app):
implementation 'com.android.support:recyclerview-v7:28.x.x-x// donde .x.x-x es la versión
  • En el fragment o Activity donde quieras mostrar el RecyclerView, simplemente agregas la etiqueta que ya tienes disponible:
<android.support.v7.widget.RecyclerView
    android:id="@+id/pictureRecycler"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
  • En nuestro package principal creamos uno nuevo llamado adapter. Dentro de este nuevo paquete vamos a crear una nueva clase PictureAdapterRecyclerView.
  • Ubicados dentro de la clase que creamos, definimos el ViewHolder que hereda de RecyclerView.ViewHolder (Te saldrá subrayado y te pedirá crear un constructor).
  • Dentro del ViewHolder definimos todos los viewsvariables (username, likes, time, etc) que componen al CardView, como private.
  • A cada view definido en el ViewHolder se le relaciona el view que está en el CardView, mediante el id. Esto se hace dentro del constructor.
  • Hasta ahora se verá así:
public classPictureAdapterRecyclerView{

    public classPictureViewHolderextendsRecyclerView.ViewHolder{

        privateImageView pictureCard;
        privateTextView userNameCard;
        privateTextView timeCard;
        //private CheckBox likeCheckCard;privateTextView likeNumberCard;

        public PictureViewHolder(@NonNullView itemView) {
            super(itemView);

            pictureCard = (ImageView) itemView.findViewById(R.id.pictureCard);
            userNameCard = (TextView) itemView.findViewById(R.id.userNameCard);
            timeCard = (TextView) itemView.findViewById(R.id.timeCard);
            likeNumberCard = (TextView) itemView.findViewById(R.id.likeNumberCard);
        }
    }
}
  • Sin embargo, la clase PictureAdapterRecyclerView debe heredar de RecyclerView.Adapter, por lo que quedaría:
public classPictureAdapterRecyclerViewextendsRecyclerView.Adapter{
	...
  • Ahora, a la clase Adapter debemos hacerle llegar una colección de objetos, esto lo hacemos a través de nuestro POJO. Así que en nuestro package creamos un nuevo paquete llamado model y en este directorio creamos una nueva clase, en este caso llamada Picture.
  • Dentro de este POJO, definimos los elementos que serán enviados al Adapter, sería algo como esto:
publicclass Picture {
    privateString picture;
    privateString userName;
    privateStringtime;
    privateString like_number = "0";
}
  • Ahora es necesario generar un constructor, getters y setters, el generador lo puedes mostrar presionando alt + insert y seleccionando el método que quieres incluir o haciendo click derecho > Generate. El resultado será algo como esto:
publicclass Picture {
    privateString picture;
    privateString userName;
    privateString time;
    privateString like_number = "0";

    public Picture(String picture, String userName, String time, String like_number) {
        this.picture = picture;
        this.userName = userName;
        this.time = time;
        this.like_number = like_number;
    }

    publicString getPicture() {
        return picture;
    }

    publicvoid setPicture(String picture) {
        this.picture = picture;
    }

    publicString getUserName() {
        return userName;
    }

    publicvoid setUserName(String userName) {
        this.userName = userName;
    }

    publicString getTime() {
        return time;
    }

    publicvoid setTime(String time) {
        this.time = time;
    }

    publicString getLike_number() {
        return like_number;
    }

    publicvoid setLike_number(String like_number) {
        this.like_number = like_number;
    }
}
  • Una vez definido nuestro POJO, es necesario regresar al Adapter y agregarle la colección de datos que recibirá. En este caso, recibirá una colección de PictureViewHolder, por eso, nuestra clase PictureAdapterRecyclerView quedará de esta manera (cuando agregas la colección de datos <PictureAdapterRecyclerView.PictureViewHolder> te exigirá la creación de los nuevos métodos que también ves a continuación):
public classPictureAdapterRecyclerViewextendsRecyclerView.Adapter<PictureAdapterRecyclerView.PictureViewHolder>{

    @NonNull@Override
    public PictureViewHolder onCreateViewHolder(@NonNullViewGroup viewGroup, int i) {
        returnnull;
    }

    @Override
    public void onBindViewHolder(@NonNullPictureViewHolder pictureViewHolder, int i) {

    }

    @Override
    public int getItemCount() {
        return0;
    }

    public classPictureViewHolderextendsRecyclerView.ViewHolder{
		...
		...
		...
	}
}
  • Posterior a esto, aún trabajando en la clase Adapter, crearémos 3 variables:
    • private ArrayList<Picture> pictures; = es el arreglo de imagenes que recibiremos, aun no sabemos el origen, pero sabemos que recibirémos un arregle de imagenes.
    • private int resources; = el recurso será nuestro Layout, nuestro CardView.
    • private Activity activity; = es para definir la actividad desde la que se está llamando esta clase. Será útil cuando querramos ubicar la imagen que traerémos de internet.
  • Creamos un constructor para estas tres nuevas variables (recuerda que puedes hacerlo mediante el generador Alt + insert).
private ArrayList<Picture> pictures;
privateint resource;
private Activity activity;

publicPictureAdapterRecyclerView(ArrayList<Picture> pictures, int resource, Activity activity){
    this.pictures = pictures;
    this.resource = resource;
    this.activity = activity;
}
  • En el método onCreateViewHolder() de PictureViewHolder le pasarémos al constructor el view, es decir, nuestro CardView. Para esto primero debemos inflar (convertir de .xml a un view, algo mostrable en pantalla) el CardView y luego enviarlo. De esta manera queda nuestro método:
@NonNull@OverridepublicPictureViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i){
    View view = LayoutInflater.from(viewGroup.getContext()).inflate(resource, viewGroup, false);
    returnnew PictureViewHolder(view);
}
  • El método onBingViewHolder() es prácticamente el transmisor de datos. En este caso, asigna cada elemento del arreglo que definimos, al CardView correspondiente. En este método definimos lo siguiente:
    • Picture picture = pictures.get(position); = es el que se encarga de recorrer el arreglo y así ubicarse en un CardView por cada elemento del arreglo (viene de nuestro POJO).
    • Luego, accedemos a pictureViewHolder, un objeto que recibimos como parámetro en esta clase. Luego accedemos al view al cual le definirémos información, y la información que le asignarémos, la tendrémos en picture (lo que creamos en el paso anterior).
  • Quedará así:
@Override
public void onBindViewHolder(@NonNull PictureViewHolder pictureViewHolder, int i) {
    Picture picture = pictures.get(i);
    pictureViewHolder.userNameCard.setText(picture.getUserName());
    pictureViewHolder.timeCard.setText(picture.getTime());
    pictureViewHolder.likeNumberCard.setText(picture.getLike_number());
}
  • Después, al método getItemCount() le asignamos el tamaño del arreglo, es la cantidad de elementos a crear.
return pictures.size()

Mostrar RecyclerView (y otros) en el fragment Home

  • Ubicados en el HomeFragment.java agregamos en primer lugar la Toolbar. para esto creamos el método showToolbar (ya lo definimos antes en el CreateAccountActivity, pero esta vez tendrá ciertas diferencias).
  • Aparte de los parámetros String tittle y boolean upButton ahora tendrá también el parámetro View view porque recordemos el que fragment se va a comportar como un view. Quedaría así:
public void showToolbar(String tittle, boolean upButton, View view){
    Toolbar toolbar = view.findViewById(R.id.toolbar);
    ((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
    (((AppCompatActivity) getActivity()).getSupportActionBar()).setTitle(tittle);
    ((AppCompatActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(upButton);
}
  • Luego, en el método onCreateView() el inflater que retorna como respuesta se lo asignarémos a un nuevo objeto View view = inflater.inflate(R.layout.fragment_home, container, false); y el método retornará view.
  • Posterior al objeto creado invocamos al método showToolbar(“Home”, false, view) (false porque no tendrá upButton).
  • Definimos un objeto **RecyclerView picturesRecycler = (RecyclerView) view.findViewById(R.id.pictureRecycler);*.
  • Inicializamos un objeto LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext()); definiendo que adquiere el contexto actual.
  • Asignamos la orientación con setOrientation(LinearLayoutManager.VERTICAL).
  • Luego al objeto picturesRecycler le asignamos el LayputManager configurado con setLayoutManager().
  • Creamos un objeto PictureAdapterRecyclerView pictureAdapterRecyclerView = new PictureAdapterRecyclerView(buildPictures(), R.layout.cardview_picture, getActivity()); donde builPictures() es un array que definirémos ahora de forma estática.
  • Creamos el arreglo public ArrayList<Picture> buildPictures(){ … donde introducirémos objetos de tipo Picture con los parámetros que especificamos (picture, username, time, likes).
  • Finalmente, el código queda de esta manera:
publicclassHomeFragmentextendsFragment{


    publicHomeFragment(){
        // Required empty public constructor
    }


    @Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState){
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_home, container, false);
        showToolbar("Home", false, view);
        RecyclerView picturesRecycler = (RecyclerView) view.findViewById(R.id.pictureRecycler);

        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);

        picturesRecycler.setLayoutManager(linearLayoutManager);

        PictureAdapterRecyclerView pictureAdapterRecyclerView =
                new PictureAdapterRecyclerView(buildPictures(), R.layout.cardview_picture, getActivity());
        picturesRecycler.setAdapter(pictureAdapterRecyclerView);

        return view;
    }

    public ArrayList<Picture> buildPictures(){
        ArrayList<Picture> pictures = new ArrayList<>();
        pictures.add(new Picture("https://images.pexels.com/photos/466685/pexels-photo-466685.jpeg?auto=compress&cs=tinysrgb&h=350", "Nicoll Sarai", "2 horas", "48"));
        pictures.add(new Picture("https://images.pexels.com/photos/466685/pexels-photo-466685.jpeg?auto=compress&cs=tinysrgb&h=350", "Carlos Fernández", "1 día", "4"));
        pictures.add(new Picture("https://images.pexels.com/photos/466685/pexels-photo-466685.jpeg?auto=compress&cs=tinysrgb&h=350", "Nicoll Sarai", "2 semanas", "8"));
        pictures.add(new Picture("https://images.pexels.com/photos/466685/pexels-photo-466685.jpeg?auto=compress&cs=tinysrgb&h=350", "Fraini Salazar", "20 horas", "21"));
        pictures.add(new Picture("https://images.pexels.com/photos/466685/pexels-photo-466685.jpeg?auto=compress&cs=tinysrgb&h=350", "Erick Rengel", "1 día", "12"));
        pictures.add(new Picture("https://images.pexels com/photos/466685/pexels-photo-466685.jpeg?auto=compress&cs=tinysrgb&h=350", "Nicoll Sarai", "10 minutos", "123"));

        return pictures;
    }

    publicvoidshowToolbar(String tittle, boolean upButton, View view){
        Toolbar toolbar = view.findViewById(R.id.toolbar);
        ((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
        (((AppCompatActivity) getActivity()).getSupportActionBar()).setTitle(tittle);
        ((AppCompatActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(upButton);
    }
}

  • Listo, hasta ahora ya podemos ver nuestra RecyclerView aún no estamos importando la imagen desde internet y quedan detalles por arreglar.

Mostrar imágenes desde internet

Para esto utilizarémos la librería Picasso.

  • En primer lugar implementarémos la librería de Picasso (que está en su página web) a nuestro archivo build.gradle (app) y sincronizamos.
  • En el archivo PictureAdapterRecyclerView.java, en el método onBindViewHolder() agregarémos:
Picasso.get().load(picture.getPicture()).into(pictureViewHolder.pictureCard);
  • donde picture.getPicture() es la imagen, y pictureViewHolder.pictureCard es el objeto en el cual se agregará.
  • Por último, en el archivo AndroidManifest.xml, antes de la etiqueta <application … debemos dar permiso a nuestra app para que acceda a internet:
<uses-permission android:name="android.permission.INTERNET"/>

CollapsingToolbarLayout y AppBarLayout

AppBarLayout

  • Es esencialmente un LinearLayout vertical que nos permite acomodar los elementos que trabajarán con un Toolbar.
  • Nos permite manejar características de Material Design en AppBar.

CollapsingToolbarLayout

  • Es un Wrapper para Toolbar el cual implemente un efecto de Collapse en toolbar y los elementos hijos.
  • Para poder usar este efecto, debe ser hijo directo de AppBarLayout.

**Creando Activity “Detalles de imagen”

  • Esta vez dejo el código comentado porque es más de lo que ya hemos visto.
    • en activity_picture_detail:
<android.support.design.widget.CoordinatorLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".view.PictureDetailActivity"
    ><android.support.design.widget.AppBarLayoutandroid:id="@+id/appBar"android:layout_width="match_parent"android:layout_height="@dimen/height_appbarlayout"android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"><android.support.design.widget.CollapsingToolbarLayoutandroid:id="@+id/collapsingToolbar"android:layout_width="match_parent"android:layout_height="match_parent"app:layout_scrollFlags="scroll|exitUntilCollapsed"app:contentScrim="@color/colorPrimary"
            ><!--
            app:layout_scrollFrags : Definimos que los hijos deben poder hacer scroll
            app:contentScrim : Es el color que tendra la toolbar una vez colapsa
            --><ImageViewandroid:id="@+id/pictureDetailHeader"android:layout_width="match_parent"android:layout_height="match_parent"android:scaleType="centerCrop"android:background="@drawable/image"app:layout_collapseMode="parallax"
                /><!--
                android:scaleType="centerCrop" : La imagen no se estira, se centra y se corta.
                app:layout_collapseMode="parallax" : Agrega efecto Parallax mientra colapsa
                --><android.support.v7.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="wrap_content"android:layout_height="?attr/actionBarSize"app:popupTheme="@style/ThemeOverlay.AppCompat.Light"app:layout_collapseMode="pin"
                /><!--
                app:layout_collapseMode="pin" : Hace que este view se mantenga fijo
                --></android.support.design.widget.CollapsingToolbarLayout></android.support.design.widget.AppBarLayout><android.support.v4.widget.NestedScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"app:layout_behavior="@string/appbar_scrolling_view_behavior"
        ><!--
        app:layout_behavior="@string/appbar_scrolling_view_behavior" : 
        Este ViewGroup se muestra luego de la Toolbar, no sobre ella
        --><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:paddingTop="@dimen/padding_vertical_text_card"
            ><TextViewandroid:id="@+id/usernamePictureDetail"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="@dimen/textsize_username_detail"android:text="@string/username_card"android:paddingStart="@dimen/padding_horizontal_text_card"android:paddingEnd="@dimen/padding_horizontal_text_card"
                /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingBottom="@dimen/padding_vertical_text_card"android:paddingStart="@dimen/padding_horizontal_text_card"android:paddingEnd="@dimen/padding_horizontal_text_card"
                ><TextViewandroid:id="@+id/likeNumberPictureDetail"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="@dimen/textsize_likenumber_detail"android:text="10"
                    /><TextViewandroid:id="@+id/secondWordPictureDetail"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="@dimen/textsize_likenumber_detail"android:text="@string/secondword_detail"android:layout_marginStart="@dimen/marginleft_secondword"
                    /></LinearLayout><Viewandroid:layout_width="match_parent"android:layout_height="@dimen/height_divider"android:background="@android:color/darker_gray"
                /><TextViewandroid:id="@+id/tittlePictureDetail"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="@dimen/textsize_likenumber_detail"android:text="@string/tittle_picturedetail"android:layout_gravity="center_horizontal"android:textStyle="bold"android:paddingTop="@dimen/paddingtop_tittle_picturedetail"
                /><TextViewandroid:id="@+id/textContentPictureDetail"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="@dimen/textsize_likenumber_detail"android:text="@string/lorem"android:layout_gravity="center_horizontal"android:paddingTop="@dimen/paddingtop_tittle_picturedetail"android:paddingStart="@dimen/padding_horizontal_textcontent_picturedetail"android:paddingEnd="@dimen/padding_horizontal_textcontent_picturedetail"
                /></LinearLayout></android.support.v4.widget.NestedScrollView><android.support.design.widget.FloatingActionButtonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="@dimen/fab_margin"android:src="@drawable/heart"app:layout_anchor="@+id/appBar"app:layout_anchorGravity="bottom|end"
        /><!--
        app:layout_anchor="@+id/appBar" : Hace que este view cuelgue sobre appBar
        app:layout_anchorGravity="bottom|end" : Le da una gravedad al view en relacion al anchor
        --></android.support.design.widget.CoordinatorLayout>
  • Declaramos la Toolbar en PictureDetailActivity.java:
public classPictureDetailActivityextendsAppCompatActivity{

    @Overrideprotected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_picture_detail);
        showToolbar("", true);
    }

	// No hace falta el parámetro view porque estamos trabajando en un activity, no en fragment. Lo mismo pasa con el ((AppCompatActivity) getActivity()).

    public void showToolbar(String tittle, boolean upButton){
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setTitle(tittle);
        getSupportActionBar().setDisplayHomeAsUpEnabled(upButton);

		// Esto lo dejamos por acá porque seguramente lo necesitarémos luego, simplemente un objeto.CollapsingToolbarLayout collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapsingToolbar);
    }
}
  • Por último, establecemos la relación con la Activity padre en el AndroidManifest.
<activityandroid:name=".view.PictureDetailActivity"android:parentActivityName=".view.ContainerActivity"><meta-dataandroid:name="android.support.PARENT_ACTIVITY"android:value=".view.ContainerActivity" /></activity>

onClick Listener en RecyclerView

  • En el PictureAdapterRecyclerView, dentro del método onBindViewHolder (el que establece la relación de cada elemento CardView), declaramos un Listener, el método onClick y dentro de este método el intent:
pictureViewHolder.pictureCard.setOnClickListener(new View.OnClickListener() {
            @OverridepublicvoidonClick(View view){
                Intent intent = new Intent(activity, PictureDetailActivity.class);
                activity.startActivity(intent);
            }
        });

Vista de perfil (e imagen circular)

  • En el fragment_profile.xml definimos una estructura similar a la del activity_picture_detail.xml, tendrémos lo siguiente, para iniciar:
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".view.fragment.ProfileFragment"
    >

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appBarProfile"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay"
        android:background="@color/colorPrimary"
        >

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsingToolbarProfile"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/usernameProfile"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/username_card"
                android:textColor="@color/textColorWhite"
                android:textSize="@dimen/textsize_username_profile"
                />

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbarProfile"
                android:layout_width="wrap_content"
                android:layout_height="?attr/actionBarSize"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                />

        </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/circleImageProfile"
        android:layout_width="@dimen/dimen_circleimage_profile"
        android:layout_height="@dimen/dimen_circleimage_profile"
        android:src="@drawable/image"
        android:layout_gravity="center|top"
        android:layout_marginTop="@dimen/margintop_circleimage_profile"
        android:elevation="@dimen/elevation_circleimage_profile"
        />

</android.support.design.widget.CoordinatorLayout>
  • Donde el TextView será el nombre de usuario y <de.hdodenhof.circleimageview.CircleImageView … será nuestra imagen de perfil circular. Este View proviene de una librería llamada CircleImageView que tendrémos que agregar a nuestras dependencias (versión actual en el enlace).

Comportamientos dependientes

Aquí está la documentación del plugin que nos permite establecer comportamientos en Views, dependiendo del comportamiento de otro view. Es super sencillo de usar.
https://github.com/zoonooz/simple-view-behavior

Transiciones en Android

  • Sólo están disponibles desde Android 5.0 en adelante. Por lo tanto, debemos hacer una validación de la versión actual.
  • Hay 3 tipos de transiciones. Cada una tiene clases desde las que puedes crear un objeto o una clase que herede, para hacer tus propios efectos:
    • Fade
    • Slide
    • Explode
  • Para hacer un efecto de transición dependiente, debemos identificar el elemento de salida y el de entrada.
  • Al elemento de salida le agregamos un:
android:transitionName="@string/transitionname_X"
  • Este nombre de transición será una especie de identificador y es una cadena de texto.
  • Luego el mismo atributo se lo debemos agregar al elemento de entrada.
  • Ya que tenemos el identificador de la transición, debemos hacer que funcione, y para eso es necesario que entendamos donde está el evento que desencadena la transición (normalmente un onClick() ) y en este evento definimos la validación y la transición:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
    Explode explode = new Explode();
    explode.setDuration(1000);
    activity.getWindow().setExitTransition(explode);
	activity.startActivity(intent, ActivityOptionsCompat.makeSceneTransitionAnimation(activity, view, activity.getString(R.string.transitionname_picture)).toBundle());
	} else {
	    activity.startActivity(intent);
	}
  • En este caso quisimos hacer una personalización al efecto y por eso creamos un objeto de la clase Explode, modificamos uno de sus valores y luego aplicamos la transición de salida explode. Sin embargo, si quisieramos no hacer cambios en el efecto por defecto, implementaríamos
getWindow().setExitTransition(new Explode);
  • Otra cosa importante es que, si el evento que desencadena la transición está definido en el controlador (java) de la Activity de salida, no es necesario hacer referencia a la Activity, sin embargo, si el evento está definido fuera de la Activity como en este caso donde está definido en un Adapter, si es necesario hacer referencia a la Activity de salida antes del método getWindow().
  • Posterior a esto lanzarémos la nueva actividad, pero aparte del intent pasarémos un parámetro de opciones.
activity.startActivity(intent, ActivityOptionsCompat.makeSceneTransitionAnimation(activity, view, activity.getString(R.string.transitionname_picture)).toBundle());
  • Donde definimos que se ejecutará una animación de transición y recibirá como parámetros:

    • La Activity actual.
    • El view actual.
    • el identificador de la transición.
  • Luego del makeSceneTransitionAnimation(…) agregamos .toBundle().

  • Nos resta definir la transición de entrada. Nos ubicamos en el elemento de entrada, en onCreate() en caso de que sea el método que queremos controlar y hacemos lo mismo, validamos y ejecutamos la transición.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
    getWindow().setEnterTransition(new Fade());
} 

StatusBar transparente

La StatusBar puede ser transparente sólo a partir de Lollypop (API 21). Para esto, en el archivo styles v-21 copiamos el estilo:

<stylename="AppTheme"parent="Theme.AppCompat.Light.NoActionBar">

y agregamos un nuevo item:

<item name="android:statusBarColor">@android:color/transparent</item>
Escribe tu comentario
+ 2