Русский
Русский
English
Статистика
Реклама

Тени

Как сделать цветные тени в Android с градиентом и анимацией

28.11.2020 18:12:01 | Автор: admin

На презентации новых макбуков обратил внимание на картинку процессора:

Переливающиеся цветные тени на темном фоне, выглядит классно.

Вот дошли руки, решил попробовать нарисовать на андроиде так же. Вот что получилось:

Сразу оговорюсь, что стандартным способом это сделать нельзя, до api 28 есть поддержка только черных elevation, после api 28 добавили поддержку цветных теней, но градиент сделать не получится. Поэтому мы будет рисовать drawable, устанавливать его в виде background и применять padding на целевой вьюхе, чтобы контент был внутри тени.

Напишем функцию создания Drawable с тенью:

/** * Создание drawable с градиентом-тенью */private fun createShadowDrawable(    @ColorInt colors: IntArray,    cornerRadius: Float,    elevation: Float,    centerX: Float,    centerY: Float): ShapeDrawable {    val shadowDrawable = ShapeDrawable()    // Устанавливаем черную тень по умолчанию    shadowDrawable.paint.setShadowLayer(        elevation, // размер тени        0f, // смещение тени по оси Х        0f, // по У        Color.BLACK // цвет тени    )    /**     * Применяем покраску градиентом     *     * @param centerX - Центр SweepGradient по оси Х. Берем центр вьюхи     * @param centerY - Центр по оси У     * @param colors - Цвета градиента. Последний цвет должен быть равен первому,     * иначе между ними не будет плавного перехода     * @param position - позиции смещения градиента одного цвета относительно другого от 0 до 1.     * В нашем случае null т.к. нам нужен равномерный градиент     */    shadowDrawable.paint.shader = SweepGradient(        centerX,        centerY,        colors,        null    )    // Делаем закугление углов    val outerRadius = FloatArray(8) { cornerRadius }    shadowDrawable.shape = RoundRectShape(outerRadius, null, null)    return shadowDrawable}

Поскольку у этого drawable фон представлен в виде радуги тех цветов, что мы передали в параметрах, нам нужен нормальный одноцветный фон. Для этого создаем вторую drawable:

/** * Создание цветного drawable с закругленными углами * Это будет основной цвет нашего контейнера */private fun createColorDrawable(    @ColorInt backgroundColor: Int,    cornerRadius: Float) = GradientDrawable().apply {        setColor(backgroundColor)        setCornerRadius(cornerRadius)    }

Функция установки бэкграунда на вьюху-контейнер. У нас будет LayerDrawable с двумя слоями. 1 - тень, 2 - просто цвет с закругленными углами.

/** * Устанавливаем бэкграунд с тенью на вьюху, учитывая padding */private fun View.setColorShadowBackground(    shadowDrawable: ShapeDrawable,    colorDrawable: Drawable,    padding: Int) {    val drawable = LayerDrawable(arrayOf(shadowDrawable, colorDrawable))    drawable.setLayerInset(0, padding, padding, padding, padding)    drawable.setLayerInset(1, padding, padding, padding, padding)    setPadding(padding, padding, padding, padding)    background = drawable}

Применяем на вьюхе:

// ждем когда вьюха отрисуется чтобы узнать ее размерыtargetView.doOnNextLayout {    val colors = intArrayOf(        Color.WHITE,        Color.RED,        Color.WHITE    )    val cornerRadius = 16f.dp    val padding = 30.dp    val centerX = it.width.toFloat() / 2 - padding    val centerY = it.height.toFloat() / 2 - padding    val shadowDrawable = createShadowDrawable(        colors = colors,        cornerRadius = cornerRadius,        elevation = padding / 2f,        centerX = centerX,        centerY = centerY    )    val colorDrawable = createColorDrawable(        backgroundColor = Color.DKGRAY,        cornerRadius = cornerRadius    )    it.setColorShadowBackground(        shadowDrawable = shadowDrawable,        colorDrawable = colorDrawable,        padding = 30.dp    )}

Теперь проанимируем изменение с одного набора цветов на другие. Зациклим.

/** * Анимация drawable-градиента */private fun animateShadow(    shapeDrawable: ShapeDrawable,    @ColorInt startColors: IntArray,    @ColorInt endColors: IntArray,    duration: Long,    centerX: Float,    centerY: Float) {    /**     * Меняем значение с 0f до 1f для применения плавного изменения     * цвета с помощью [ColorUtils.blendARGB]     */    ValueAnimator.ofFloat(0f, 1f).apply {        // Задержка перерисовки тени. Грубо говоря, фпс анимации        val invalidateDelay = 100        var deltaTime = System.currentTimeMillis()        // Новый массив со смешанными цветами        val mixedColors = IntArray(startColors.size)        addUpdateListener { animation ->            if (System.currentTimeMillis() - deltaTime > invalidateDelay) {                val animatedFraction = animation.animatedValue as Float                deltaTime = System.currentTimeMillis()                // Смешиваем цвета                for (i in 0..mixedColors.lastIndex) {                    mixedColors[i] = ColorUtils.blendARGB(startColors[i], endColors[i], animatedFraction)                }                // Устанавливаем новую тень                shapeDrawable.paint.shader = SweepGradient(                    centerX,                    centerY,                    mixedColors,                    null                )                shapeDrawable.invalidateSelf()            }        }        repeatMode = ValueAnimator.REVERSE        repeatCount = Animation.INFINITE        setDuration(duration)        start()    }}

Применим:

// Второй массив с цветами. Размер массивов должен быть одинаковый.val endColors = intArrayOf(Color.RED,Color.WHITE,Color.RED)animateShadow(shapeDrawable = shadowDrawable,  startColors = colors,  endColors = endColors,  duration = 2000,  centerX = centerX,  centerY = centerY)

Все. Если это будет кнопкой, нужно применить ripple эффект для foreground вьюхи и так же прописать там отступ, чтобы у нас отображалась анимация нажатия.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru