5 UI фишек для современного Андроид приложения. Код, идеи и живой пример

    image

    В данной статье я хочу поделиться «фишками», которые использовал при создании своего последнего приложения. В основном это набор полезных функций и небольших компонентов для создания современного пользовательского интерфеса. Каждая «фишка» будет сопровождаться примером кода, картинкой и небольшим описанием. Я считаю, что гораздо интереснее учится на живых примерах, поэтому в конце статьи будет ссылка на репозиторий реального приложения, которое использует все описанные в статье «фишки».

    Статья не ставит своей целью научить проектировать пользовательский интерфейс или объяснить сокровенный смысл Material дизайна, но надеюсь, приведенные примеры смогут вдохновить Ввас на эксперименты с дизайном ваших приложений.


    1. Извлекаем доминантный цвет из изображения


    Иногда хочется добавить немного разнообразия в цветовую схему приложения, к примеру подбирать цвета динамически, в зависимости от определённой картинки. Специально для таких случаев существует библиотека от Google — Palette. Давайте посмотрим на один из примеров её использования:

    image


    // Не забудте добавить 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. Пример его использования и конечный результат ниже:

    image

    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» фильтр. Если изображение большое, лучше выполнять масштабирование в фоновом потоке, чтобы не блокировать рендеринг. Примеры обоих вариантов ниже:

    image


    // Функция масштабирования
    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+, но не работает на более ранних версиях. Поэтому я предлагаю простое и универсальное программное решение:

    image

        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 и уж очень мне приглянулись. Возможно, и Вы сможете найти им применение в своем приложении:

    image

    Для Андроид 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
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 15
    • 0

      Оставлю для вас эту ссылку: https://github.com/wasabeef/awesome-android-ui

      • 0
        Nagg awesome-android-ui — очень крутая подборка библиотек, частенько заглядываю туда за вдохновлением. Мои фишки не требуют сторонних библиотек (кроме Palette от Google из первого примера) + показаны на примере реальной апликации. Поэтому одно другому не мешает :)
        • +1

          Посмотрел, увидел много всякие Material-штук. А разве Android Studio по-умолчанию не создает проекты с такими стилями, что они Material-like и на >5 и на <5? Всяческие appcompat темы и прочее?

          • 0
            К сожалению, нет (по крайней мере, не было, когда я последний раз создавал проект). Библиотеки надо добавлять самому в зависимости от функционала. Для определенных вещей есть обратная совместимость (c помощью google support библиотек), например для Toolbar или для RecyclerView, а вот для Ripple Effect например ее можно добится только подключением стороних библиотек.
        • 0
          P.S Как и обещал, оставляю ссылку на репозиторий приложения, в котором применялись все вышеперечисленные «фишки» — Github

          666 commits

          Какое круглое число :)

          Спасибо за статью, взял пару фишек на заметку
          • 0
            На самом деле побольше бы таких статей, где простые казалось бы вещи, которые нельзя решить при помощи стандартных способов, решаются минимумом костылей.
            А с последним «хаком» все не так однозначно. Если понадобится реализовать тени или ripple effect на андроиде ниже 5, то начнутся интересности.
            • 0
              Artem_007 да, для ripple effect на андроиде ниже 5 придется использовать сторонние библиотеки( Поэтому я обычно использую отдельные, стандартные селекторы для Андроида < 5, имхо раз уж Google не реализовали обратную совместимость ripple effect в своих support библиотеках, то лучше просто использовать стандартные селекторы в зависимости от версии ОС.
            • 0
              Судя по скриншоту, LetterBitmap не понимает русского языка и просто подставляет «A». Или это не так?
              • 0
                dkv Вы правы, LetterBitmap поддерживает только английский язык, спасибо за замечаение. Добавил это в описание класса внутри gist.
                • 0
                  А что мешает просто доработать класс? Ведь надо поправить всего одну строку.
                  • 0
                    Можно либо убрать вообще эту проверку и разрешить делать любой символ, либо позволить менять дефолтный символ, либо передавать в класс какой-то компаратор для символов, возвращающий нужный литерал.
                    • 0
                      Character.isLetterOrDigit() должен делать требуемую проверку.
                      • 0
                        Просто не было необходимости поддерживать другие языки. Как будет свободное время проверю как класс рисует русские буквы, если все ок, подправлю проверку. Убирать ее нельзя т.к есть арабский, китайский и другие языки и надо тестить как все это будет выглядеть.
                        • 0
                          Спасибо за код в любом случае. Пофиксить строку — не проблема для тех, кому это будет нужно.
                  • 0
                    А почему для цветных квадратов используется Bitmap, а не Drawable с переопределенным `draw`?

                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.