
В данной статье я хочу поделиться «фишками», которые использовал при создании своего последнего приложения. В основном это набор полезных функций и небольших компонентов для создания современного пользовательского интерфеса. Каждая «фишка» будет сопровождаться примером кода, картинкой и небольшим описанием. Я считаю, что гораздо интереснее учится на живых примерах, поэтому в конце статьи будет ссылка на репозиторий реального приложения, которое использует все описанные в статье «фишки».
Статья не ставит своей целью научить проектировать пользовательский интерфейс или объяснить сокровенный смысл Material дизайна, но надеюсь, приведенные примеры смогут вдохновить Ввас на эксперименты с дизайном ваших приложений.
1. Извлекаем доминантный цвет из изображения
Иногда хочется добавить немного разнообразия в цветовую схему приложения, к примеру подбирать цвета динамически, в зависимости от определённой картинки. Специально для таких случаев существует библиотека от Google — Palette. Давайте посмотрим на один из примеров её использования:

// Не забудте добавить Palette в build.gradle : // compile 'com.android.support:palette-v7:+' public static int getDominantColor(Bitmap bitmap) { List<Palette.Swatch> swatchesTemp = Palette.from(bitmap).generate().getSwatches(); List<Palette.Swatch> swatches = new ArrayList<Palette.Swatch>(swatchesTemp); Collections.sort(swatches, new Comparator<Palette.Swatch>() { @Override public int compare(Palette.Swatch swatch1, Palette.Swatch swatch2) { return swatch2.getPopulation() - swatch1.getPopulation(); } }); // если по какой-то причине не удалось извлечь цвета из изображения, выбираем просто случайный цвет return swatches.size() > 0 ? swatches.get(0).getRgb() : getRandomColor(); } public static int getRandomColor() { Random rnd = new Random(); int color = Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256)); return color; }
2. Генерируем разноцветные квадраты с буквами прямо в коде
Такие квадраты часто встречаются в популярных приложениях. Их можно легко создать прямо в коде, в виде обычного Bitmap, без дополнительной графики или xml layout-ов. Я использовал их в качестве «заглушки» когда оригинальное изображение отсутствует. Для их создания вам понадобится всего одни класс LetterBitmap. Пример его использования и конечный результат ниже:

int COVER_IMAGE_SIZE = 100; //in pixels LetterBitmap letterBitmap = new LetterBitmap(context); Bitmap letterTile = letterBitmap.getLetterTile("string for letter", "string for color", COVER_IMAGE_SIZE, COVER_IMAGE_SIZE); ImageView imgAnyImageView = (ImageView) view.findViewById(R.id.imgAnyImageView); imgAnyImageView.setImageBitmap(letterTile);
3. Масштабируем изображение на лету
Достаточно интересная возможность, можно комбинировать с прозрачностью, а если наложить поверх растянутой картинки полупрозрачный фон получится эффект напоминающий «blur» фильтр. Если изображение большое, лучше выполнять масштабирование в фоновом потоке, чтобы не блокировать рендеринг. Примеры обоих вариантов ниже:

// Функция масштабирования public static Bitmap createScaledBitmap(Bitmap bitmap, float scaleFactor) { Matrix m = new Matrix(); m.setRectToRect(new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()), new RectF(0, 0, bitmap.getWidth() * scaleFactor, bitmap.getHeight() * scaleFactor), Matrix.ScaleToFit.CENTER); return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true); } // Пример использования: float COVER_SCALE_FACTOR = 2f; final Bitmap scaledBitmap = UIHelper.createScaledBitmap(regularBitmap, COVER_SCALE_FACTOR); // В фоновом потоке new Thread(new Runnable() { @Override public void run() { final Bitmap scaledBitmap = UIHelper.createScaledBitmap(regularBitmap, COVER_SCALE_FACTOR); getActivity().runOnUiThread(new Runnable() { @Override public void run() { anyImageView.setImageBitmap(scaledBitmap); } }); } }).run();
А это ссылка на Gist с вышеперечисленными примерами + примером для популярной библиотеки подгрузки картинок — Glide.
4. Программно меняем цвет текста поискового поля внутри Toolbar
Я потратил кучу времени пытаясь поменять цвет стандартной строки поиска внутри Toolbar не создавая отдельного layout. Большинство советуют настроить стили темы в styles.xml, иногда это помогает для Андрода 5.0+, но не работает на более ранних версиях. Поэтому я предлагаю простое и универсальное программное решение:

public static void changeSearchViewTextColor(View view, int color) { if (view != null) { if (view instanceof TextView) { ((TextView) view).setTextColor(color); return; } else if (view instanceof ViewGroup) { ViewGroup viewGroup = (ViewGroup) view; for (int i = 0; i < viewGroup.getChildCount(); i++) { changeSearchViewTextColor(viewGroup.getChildAt(i), color); } } } } // Пример использования: Toolbar toolbar = (Toolbar) findViewById(R.id.your_toolbar); MenuItem searchMenuItem = toolbar.getMenu().findItem(R.id.action_search); SearchView searchView = (SearchView) searchMenuItem.getActionView(); setSearchViewStyle(searchView); changeSearchViewTextColor(searchView, Color.WHITE);
5. Кнопки с закруглёнными краями
Завершить пятерку я решил примером layouta для кнопок с закруглёнными краями, такие кнопки использовались в одной из последних версий и Google Play и уж очень мне приглянулись. Возможно, и Вы сможете найти им применение в своем приложении:

Для Андроид 5.0+:
<?xml version="1.0" encoding="utf-8"?> <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="?attr/colorControlHighlight"> <item> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:radius="@dimen/rounded_btn_radius" /> <solid android:color="@color/indigo_800" /> </shape> </item> </ripple>
Для более ранних версий:
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_focused="true"> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:radius="@dimen/rounded_btn_radius" /> <solid android:color="@color/indigo_500" /> </shape> </item> <item android:state_pressed="true"> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:radius="@dimen/rounded_btn_radius" /> <solid android:color="@color/indigo_500" /> </shape> </item> <item> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:radius="@dimen/rounded_btn_radius" /> <solid android:color="@color/indigo_800" /> </shape> </item> </selector>
Для применения разложите XML файлы по папкам drawable и drawable-v21 соответственно, а потом просто задайте как фон для любой кнопки.
P.S Как и обещал, оставляю ссылку на репозиторий приложения, в котором применялись все вышеперечисленные «фишки» — Github
