Browse Category

Support

vector_drawables

Android Support Library (III) – VectorDrawables

Una de los principales inconvenientes de la fragmentación de dispositivos que existe en Android, es el uso de imágenes. Tienes que tener tantas imágenes como resoluciones quieras utilizar, haciendo que la aplicación sea más pesada ya que el número de imágenes se triplica o cuadriplica. Gracias a las nuevas versiones de las librerías de soporte podemos utilizar los ficheros SVG.


¿Qué es SVG?

(Scalable Vector Graphics o Gráficos Vectoriales Redimensionables)
Son ficheros xml que contienen la información para pintar una imagen. Estos ficheros nacieron en 1996 y en el 2001 en una recomendación de la W3C. Una de las grandes diferencias que podemos encontrar es que no se pixelan, es decir, por mucho que manipules el fichero, la imagen no se verá distorsionada.

vector_vs_png
Diferencia entre SVG y PNG

 


Uso de imágenes vectoriales en Android

Para comenzar, tendremos que añadir la librería de soporte si no la tuviéramos añadida y además incluir unas líneas en el fichero “build.gradle” de la aplicación para poder utilizar este tipo de imágenes.

Si utilizamos gradle 2.0 o superior:

defaultConfig {
    ...
    vectorDrawables.useSupportLibrary = true
    ...
}

Si utilizamos una versión anterior:

android {  
    defaultConfig {
        generatedDensities = []  
    }  
    
    aaptOptions {  
        additionalParameters "--no-version-vectors"  
    }  

}  

El siguiente paso que tenemos que dar es la creación del fichero que contendrá nuestra imagen vectorial. Android no utiliza los ficheros “SVG” sino una conversión de ellos, VectorDrawables, los cuales son ficheros “XML” con los datos de la imagen. Para crear estos ficheros desde un “SVG” tenemos varias opciones.

  • Herramienta online de conversión de SVG a VectorDrawable. http://inloop.github.io/svg2android/
  • Dentro de Android Studio tenemos la posibilidad de crear nuestros VectorDrawables desde un fichero SVG. Para ello tenemos que ir a “New”->”Vector Asset” y seguir los pasos del wizard.

También podemos obtener los ficheros xml de páginas web. En el caso del ejemplo que voy a mostrar, he utilizado recursos de https://materialdesignicons.com/, ya que ofrece descargar el fichero en el formato que deseemos. Una vez obtenido el fichero e insertado en nuestro directorio “res->drawable”, tan solo tenemos que inicializar el ImageView de esta manera.

<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" app:srcCompat="@drawable/android_vd"/>

Animar un vectorial en Android

Animar una imagen vectorial es bastante sencillo. Tenemos que tener 3 elementos:

  • Fichero que contenga la animación del vectorial dentro del directorio “res->animator”.
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

        <objectAnimator android:duration="250" android:propertyName="translateY" android:repeatCount="infinite" android:repeatMode="reverse" android:valueFrom="0" android:valueTo="-5" android:valueType="floatType" />

</set>
  • Fichero de la imagen vectorial. En el deberemos indicar un grupo que será el que queramos animar.
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportHeight="24" android:viewportWidth="24">

        <group android:name="element">

                <path android:fillColor="#000" android:pathData="M15,5H14V4H15M10,5H9V4H10M15.53,2.16L16.84,0.85C17.03,0.66 17.03,0.34 16.84,0.14C16.64,-0.05 16.32,-0.05 16.13,0.14L14.65,1.62C13.85,1.23 12.95,1 12,1C11.04,1 10.14,1.23 9.34,1.63L7.85,0.14C7.66,-0.05 7.34,-0.05 7.15,0.14C6.95,0.34 6.95,0.66 7.15,0.85L8.46,2.16C6.97,3.26 6,5 6,7H18C18,5 17,3.25 15.53,2.16M20.5,8A1.5,1.5 0 0,0 19,9.5V16.5A1.5,1.5 0 0,0 20.5,18A1.5,1.5 0 0,0 22,16.5V9.5A1.5,1.5 0 0,0 20.5,8M3.5,8A1.5,1.5 0 0,0 2,9.5V16.5A1.5,1.5 0 0,0 3.5,18A1.5,1.5 0 0,0 5,16.5V9.5A1.5,1.5 0 0,0 3.5,8M6,18A1,1 0 0,0 7,19H8V22.5A1.5,1.5 0 0,0 9.5,24A1.5,1.5 0 0,0 11,22.5V19H13V22.5A1.5,1.5 0 0,0 14.5,24A1.5,1.5 0 0,0 16,22.5V19H17A1,1 0 0,0 18,18V8H6V18Z"/>

        </group>
</vector>
  • Fichero que haga de enlace entre la imagen vectorial y la animación. Éste será nuestro vector-drawable. En él indicaremos el grupo que queremos animar de la imagen vectorial y que animación queremos darle.
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/android_vd">

    <target android:name="element" android:animation="@animator/pulse_top"/>

</animated-vector>

 

Para utilizarlo tendremos que indicar al ImageView el atributo app:srcCompat como hicimos anteriormente. Para comenzar la animación, tendremos que recoger la imagen desde código y comenzar la animación.

ivAnimated = (ImageView) findViewById(...);
Drawable drawable = ivAnimated.getDrawable();
if (drawable instanceof Animatable) {
    ((Animatable) drawable).start();
}

Puedes ver un ejemplo completo en GITHUB

Animations

Android Support Library (II) – Transiciones entre actividades y fragments

Desde la versión lollipop de android, se ha dado mucha importancia a las animaciones para mostrar diferentes comportamientos o para dirigir al usuario a nuevas pantallas. Con la llegada de Material Design, se ha incrementado el número de animaciones, como el compartimiento de elementos visuales entre diferentes vistas. Gracias a las librerías de compatibilidad,  la tarea se ha simplificado considerablemente, dándonos la oportunidad de realizar aplicaciones más atractivas para el usuario final.  La librería de compatibilidad nos ofrece clases de utilidades para que estas transiciones se puedan hacer, sin tener en cuenta las diferentes versiones de android. Por ejemplo: En las versiones anteriores a la 5, las transiciones entre actividades no se mostrarán, pero en las versiones posteriores si que lo harán.

 

Transiciones entre Actividades

Con la incursión de material design, las transiciones y el compartimiento de elementos visuales entre actividades se ha vuelto casi un “MUST” de nuestras aplicaciones. Para utilizarlas, primero debemos asegurarnos de que utilizamos la librería

...
compile 'com.android.support:appcompat-v7:23.3.0'
...

Para comenzar, deberemos indicar en el nuestro tema de aplicación en values-v21 que se van a realizar animaciones y de que tipo son:

...



<style name="AppTheme" parent="AppTheme.Base">
    <item name="android:windowContentTransitions">true</item>
    <item name="android:windowAllowEnterTransitionOverlap">true</item>
    <item name="android:windowAllowReturnTransitionOverlap">true</item>
    <item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
    <item name="android:windowSharedElementExitTransition">@android:transition/move</item>
</style>



...

Debemos definir y ver que elementos queremos compartir y que actividades están relacionadas. Una vez localizados, comenzaremos por los ficheros de layouts, incluyendo en los elementos que queramos compartir(tanto en el origen como en el destino), el nombre con el que vamos a identificar a la transición de la vista en cuestión. En el nuestro caso, vamos a compartir un ImageView.

...
<ImageView android:id="@+id/iv_user_avatar" android:transitionName="@string/transition_avatar" android:layout_width="60dp" android:layout_height="60dp" android:layout_gravity="center"/>
...

Una vez hecho esto, deberemos indicar en la actividad de origen que elemento queremos compartir y con que nombre. Para ello deberemos utilizar clase ActivityOptionsCompat, la cual nos facilitará la tarea. En esta clase, deberemos indicar qué vista es y con que nombre de transición y pasárselo al intent de inicio de actividad.

Intent intent = new Intent(this, UserDetailActivity.class);

intent.putExtra(UserDetailActivity.EXTRA_USER, user);

ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(mImageView, getString(R.string.transition_avatar) ) ;

startActivity(intent, options.toBundle());

Si queremos compartir más de un elemento, deberemos usar tantos elementos Pair<View, String> como sea necesario.

Intent intent = new Intent(this, UserDetailActivity.class);

intent.putExtra(UserDetailActivity.EXTRA_USER, user);

Pair<View, String> p1 = Pair.create((View) holder.getIvUserAvarar(), getString(R.string.transition_avatar));

Pair<View, String> p2 = Pair.create((View) holder.getTvUserName(), getString(R.string.transition_name));

Pair<View, String> p3 = Pair.create((View) holder.getTvUserSurname(), getString(R.string.transition_surname));

Pair<View, String> p4 = Pair.create((View) holder.getTvUserActor(), getString(R.string.transition_actor));

ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(this, p1, p2, p3, p4);

startActivity(intent, options.toBundle());

Para finalizar, en la actividad de origen sólo debemos inicializar el valor de la vista con lo que queramos. En nuestro caso, es un recurso de la aplicación.

 

Transiciones entre Fragmentos

Muchos de los proyectos, en vez de hacerse todo entre actividades, se utilizan fragments con solo una actividad. Como es normal, también existen las transiciones entre fragments.
Lo primero que debemos saber, es que en este caso si que debemos preocuparnos de la versión en la que se está ejecutando la aplicación. Para realizar las transiciones, deberemos tener la referencia de ambos fragmentos, indicarle la que queremos que se produzca, e insertar todo en el FragmentTransaction

...
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

heroeDetailFragment = HeroeDetailFragment.newInstance(heroe);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

    // Inflate transitions to apply
    Transition changeTransform = TransitionInflater.from(this).inflateTransition(R.transition.change_image_transform);

    Transition explodeTransform = TransitionInflater.from(this).inflateTransition(android.R.transition.explode);

    // Setup exit transition on first fragment
    heroesListFragment.setSharedElementReturnTransition(changeTransform);
    heroesListFragment.setExitTransition(explodeTransform);

    // Setup enter transition on second fragment
    heroeDetailFragment.setSharedElementEnterTransition(changeTransform);
    heroeDetailFragment.setEnterTransition(explodeTransform);

    transaction.addSharedElement(holder.getIvAvatar(), getString(R.string.

}

transaction.addToBackStack(null);

transaction.replace(R.id.main_container, heroeDetailFragment );

transaction.commit();
...

Para acabar, puedes ver el código  en un proyecto de ejemplo de GITHUB

app_launch_checker

Android Support Library (I) – AppLaunchChecker

A principios de abril, el equipo de desarrollo de Google lanzó la nueva versión de su librería de soporte, la versión 23.3.0 . En esta versión se han solucionado una gran cantidad de bugs. Podéis ver los cambios AQUÍ.

Esta entrada no es para comentar los bugs, sino para hablar de un nuevo elemento que han implementado. AppLaunchChecker

¿Qué es AppLaunchChecker?

Esta clase ofrece la posibilidad de saber si la aplicación se ha ejecutado alguna vez. Para ello solo se necesita inicializar la clase en el método onCreate(Bundle savedInstanceState) de nuestra actividad principal, y preguntar, donde queramos, si la aplicación ha sido lanzada alguna vez.

¿Cómo funciona realmente AppLaunchChecker?

AppLaunchChecker es un simple gestor de shared preferences, el cual ofrece dos métodos públicos. El primero es onActivityCreate(Activity activity) , que es el inicializa la clase. Lo primero que realiza es comprobar el valor actual de la preferencia, y si ya está inicializada no sigue. Por el contrario, si la variable no tiene valor, pondrá la preferencia a true si la actividad es ACTION_MAIN y además tiene alguno de los flags CATEGORY_LAUNCHER o CATEGORY_LEANBACK_LAUNCHER.

El método hasStartedFromLauncher(Context context) lo único que realiza es devolver el valor de la preferencia.

Una vez se ejecute por primera ver el onActivityCreate(Activity activity), el métodohasStartedFromLauncher(Context context) siempre nos devolverá true, por lo que si queremos ver si es la primera vez que se ejecuta, deberemos ejecutar las llamadas a los métodos en el orden correcto.

¿Para que me sirve en mis aplicaciones?

Muchos desarrolladores de aplicaciones necesitan al inicio de la aplicación recuperar algunos datos de un servidor, o inicializar ciertos aspectos (ya sea configuraciones personalizadas, como propias,..). Antes se hacia la misma comprobación (Si no es la misma, muy parecida). Se creaba una preferencia que indicaba si ya se había inicializado la aplicación.

 

Ejemplo práctico

public class MainActivity extends AppCompatActivity {

    private TextView tvAppState;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        tvAppState = (TextView) findViewById( R.id.tv_app_state );

        if( AppLaunchChecker.hasStartedFromLauncher(this) ){

            tvAppState.setText("Application has been launched at least once");

        }else{

            tvAppState.setText("Application has never been started");

        }
        AppLaunchChecker.onActivityCreate( this );

    }
    
}

 

Puedes ver el ejemplo AQUI