En este artículo vamos a continuar con las novedades de Lollipop, seguimos ampliando la aplicación que empezamos en anteriores artículos. En este artículo vamos a ver como extraer los colores de una imagen utilizando la librería Palette y que uso podemos darle.
Introducción a Palette
Palette es una nueva librería disponible con Lollipop, solo esta disponible en la librería support AppCompat.Para utilizar Palette es necesario añadir la dependencia Gradle.
dependencies { compile 'com.android.support:palette-v7:21.0.0' }
Para extraer los colores existen dos formas, una síncrona y otra asíncrona.
Métodos síncronos
- generate(Bitmap)
- generate(Bitmap, int)
Métodos asíncronos
- generateAsync(Bitmap, PaletteAsyncListener)
- generateAsync(Bitmap, int, PaletteAsyncListener)
Palette.PaletteAsyncListener listener = new Palette.PaletteAsyncListener() { public void onGenerated(Palette palette) { } }
La librería intenta generar 16 colores pero estos son los colores que se suelen usar.
- Vibrant
- Vibrant Dark
- Vibrant Light
- Muted
- Muted Dark
- Muted Light
Ejemplo
Vamos a seguir con nuestra aplicación, en esta ocasión dandole funcionalidad con Palette. Antes de este post he hecho una pequeña refactorización sobre la pantalla de detalle. A nivel visual ahora se muestra un título una descripción del item además de la imagen, y a nivel técnico he dividido el contenido del activity en dos fragments al estilo de lista detalle clásico, de forma que tengo un fragment para visualizar la imagen del item y otro con los datos del item. En portrait la imagen se muestra encima de los datos del item y en landscape a la izquierda.Cuando utilizamos Palette podemos hacer cosas como establecer el color de fonfo de algún control en base a los colores de la foto que se visualiza en la misma pantalla. Vamos a hacer eso, vamos a colorear el fondo del título del item en función de la paleta y además vamos a mostrar también los 6 colores básicos extraidos de la imagen en una leyenda.
Necesitamos que los dos fragments se comuniquen de forma que el fragment de la imagen cuando esta se haya cargado comunique al fragment de los datos la paleta de colores extraida de la imagen. Vamos a ver los pasos para conseguirlo.
En el fragment de la imagen definimos un interface y un listener, también sobreescribimos el método onAttach para asignar el listener en caso de que el activity lo implemente. Entonces cuando se ha cargado la imagen invocamos el método Palette.generateAsync, cuando la paleta se ha generado invocamos el método onPaletteGenerated del listener.
public class ItemImageFragment extends Fragment { . . . OnPaletteGeneratedListener onPaletteGeneratedListener; . . . @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); Item item = (Item) getActivity().getIntent().getSerializableExtra("item"); Picasso.with(imageView.getContext()) .load(item.getImageUrl()) .into(imageView, new Callback() { @Override public void onSuccess() { Palette.generateAsync(((BitmapDrawable)imageView.getDrawable()).getBitmap(), new Palette.PaletteAsyncListener() { @Override public void onGenerated(Palette palette) { if (onPaletteGeneratedListener != null) onPaletteGeneratedListener.onPaletteGenerated(palette); } }); } @Override public void onError() { } }); } @Override public void onAttach(Activity activity) { super.onAttach(activity); if (activity instanceof OnPaletteGeneratedListener) { onPaletteGeneratedListener = (OnPaletteGeneratedListener) activity; } } public static interface OnPaletteGeneratedListener { public void onPaletteGenerated(Palette palette); } }
En el fragment de los datos definimos un método updatePalette donde coloreamos el fondo del título y los colores de la leyenda en base a la paleta de colores recibida.
public class ItemDataFragment extends Fragment { TextView titleTextView; TextView descriptionTextView; TextView vibrantTextView ; TextView vibrantDarkTextView; TextView vibrantLightTextView; TextView mutedTextView; TextView mutedDarkTextView; TextView mutedLightTextView; public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_item_data, container, false); titleTextView = (TextView)rootView.findViewById(R.id.detailItemTitle); descriptionTextView = (TextView)rootView.findViewById(R.id.detailItemDescription); //Colors vibrantTextView = (TextView)rootView.findViewById(R.id.vibrant_color); vibrantDarkTextView = (TextView)rootView.findViewById(R.id.vibrant_dark_color); vibrantLightTextView = (TextView)rootView.findViewById(R.id.vibrant_light_color); mutedTextView = (TextView)rootView.findViewById(R.id.muted_color); mutedDarkTextView = (TextView)rootView.findViewById(R.id.muted_dark_color); mutedLightTextView = (TextView)rootView.findViewById(R.id.muted_light_color); return rootView; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); Item item = (Item) getActivity().getIntent().getSerializableExtra("item"); titleTextView.setText(item.getTitle()); descriptionTextView.setText(item.getDescription()); } public void updatePalette(Palette palette){ int defaultColor = Color.WHITE; int titleColor = palette.getVibrantColor(defaultColor); titleTextView.setBackgroundColor(titleColor); vibrantTextView.setBackgroundColor(palette.getVibrantColor(defaultColor)); vibrantDarkTextView.setBackgroundColor(palette.getDarkVibrantColor(defaultColor)); vibrantLightTextView.setBackgroundColor(palette.getLightVibrantColor(defaultColor)); mutedTextView.setBackgroundColor(palette.getMutedColor(defaultColor)); mutedDarkTextView.setBackgroundColor(palette.getDarkMutedColor(defaultColor)); mutedLightTextView.setBackgroundColor(palette.getLightMutedColor(defaultColor)); } }
El activity va a hacer de mediador entre los fragments de forma que va a ser el listener del fragment de la imagen y cuando el fragment comunica que se ha generado la paleta, se lo comunicará al fragment de los datos pasandole la paleta generada.
public class ItemDetailActivity extends ActionBarActivity implements ItemImageFragment.OnPaletteGeneratedListener { private static final String TAG_IMAGE_FRAGMENT = "image_fragment"; private static final String TAG_DATA_FRAGMENT = "data_fragment"; ItemImageFragment itemImageFragment; ItemDataFragment itemDataFragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_item_detail); itemImageFragment = (ItemImageFragment) getSupportFragmentManager().findFragmentByTag(TAG_IMAGE_FRAGMENT); itemDataFragment = (ItemDataFragment) getSupportFragmentManager().findFragmentByTag(TAG_DATA_FRAGMENT); if (itemImageFragment == null) { itemImageFragment = new ItemImageFragment(); getSupportFragmentManager().beginTransaction() .add(R.id.itemImageContainer, itemImageFragment,TAG_IMAGE_FRAGMENT) .commit(); } if (itemDataFragment == null) { itemDataFragment = new ItemDataFragment(); getSupportFragmentManager().beginTransaction() .add(R.id.itemDataContainer, itemDataFragment,TAG_DATA_FRAGMENT) .commit(); } } //OnPaletteGeneratedListener @Override public void onPaletteGenerated(Palette palette) { if (itemDataFragment != null) itemDataFragment.updatePalette(palette); } }
Concusiones
Mediante Palette podemos extraer los colores de una imagen y dar una variabilidd al look & feel de nuestra app que en ciertos casos puede ser muy interesante. Hemos visto los sencillo que es implementar esta carácteristica de Lollipop.Código fuente en GitHub - tag 0.4
Libros relacionados
Android Programming: The Big Nerd Ranch GuideAndroid Programming In a Day!: The Power Guide for Beginners In Android App Programming
No hay comentarios:
Publicar un comentario