Open Event Organizer is an Android Application for the Event Organizers and Entry Managers. The core feature of the App is to scan a QR code from the ticket to validate an attendee’s check in. Other features of the App are to display an overview of sales, ticket management and basic editing in the Event Details. Open Event API Server acts as a backend for this App. The App uses Navigation Drawer for navigation in the App. The side drawer contains menus, event name, event start date and event image in the header. Event name and date is shown just below the event image in a palette. For a better visibility Android Palette is used which extracts prominent colors from images. The App uses Glide to handle image loading hence GlidePalette library is used for palette generation which integrates Android Palette with Glide. I will be talking about the implementation of GlidePalette in the App in this blog.
The App uses Data Binding so the image URLs are directly passed to the XML views in the layouts and the image loading logic is implemented in the BindingAdapter class. The image loading code looks like:
GlideApp .with(imageView.getContext()) .load(Uri.parse(url)) ... .into(imageView);
So as to implement palette generation for event detail label, it has to be implemented with the event image loading. GlideApp takes request listener which implements methods on success and failure where palette can be generated using the bitmap loaded. With GlidePalette most of this part is covered in the library itself. It provides GlidePalette class which is a sub class of GlideApp request listener which is passed to the GlideApp using the method listener. In the App, BindingAdapter has a method named bindImageWithPalette which takes a view container, image url, a placeholder drawable and the ids of imageview and palette. The relevant code is:
@BindingAdapter(value = {"paletteImageUrl", "placeholder", "imageId", "paletteId"}, requireAll = false) public static void bindImageWithPalette(View container, String url, Drawable drawable, int imageId, int paletteId) { ImageView imageView = (ImageView) container.findViewById(imageId); ViewGroup palette = (ViewGroup) container.findViewById(paletteId); if (TextUtils.isEmpty(url)) { if (drawable != null) imageView.setImageDrawable(drawable); palette.setBackgroundColor(container.getResources().getColor(R.color.grey_600)); for (int i = 0; i < palette.getChildCount(); i++) { View child = palette.getChildAt(i); if (child instanceof TextView) ((TextView) child).setTextColor(Color.WHITE); } return; } GlidePalette<Drawable> glidePalette = GlidePalette.with(url) .use(GlidePalette.Profile.MUTED) .intoBackground(palette) .crossfade(true); for (int i = 0; i < palette.getChildCount(); i++) { View child = palette.getChildAt(i); if (child instanceof TextView) glidePalette .intoTextColor((TextView) child, GlidePalette.Swatch.TITLE_TEXT_COLOR); } setGlideImage(imageView, url, drawable, null, glidePalette); }
The code is pretty obvious. The method checks passed URL for nullability. If null, it sets the placeholder drawable to the image view and default colors to the text views and the palette. The GlidePalette object is generated using the initializer method with which takes the image URL. The request is passed to the method setGlideImage which loads the image and passes the GlidePalette to the GlideApp as a listener. Accordingly, the palette is generated and the colors are set to the label and text views accordingly. The container view in the XML layout looks like:
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" app:paletteImageUrl="@{ event.largeImageUrl }" app:placeholder="@{ @drawable/header }" app:imageId="@{ R.id.image }" app:paletteId="@{ R.id.eventDetailPalette }">
Links:
1. Documentation for Glide Image Loading Library
2. GlidePalette Github Repository
3. Android Palette Official Documentation