Размытие фона android studio

Динамический blur на Android

Информации о том как быстро размыть картинку на Android существует предостаточно.
Но можно ли сделать это настолько эффективно, чтобы без лагов перерисовывать размытый bitmap при любом изменении контента, как это реализовано в iOS?

Итак, что хотелось бы сделать:

  1. ViewGroup, которая сможет размывать контент, который находится под ней и отображать в качестве своего фона. Назовем ее BlurView
  2. Возможность добавлять в нее детей (любые View)
  3. Не зависеть от какой-либо конкретной реализации родительской ViewGroup
  4. Перерисовывать размытый фон, если контент под нашей View меняется
  5. Делать полный цикл размытия и отрисовки менее чем за 16ms
  6. Иметь возможность изменять стратегию размытия

В статье я постараюсь обратить внимание только на ключевые моменты, за деталями прошу сюда.

Как получить bitmap с контентом под BlurView?

Создадим Canvas, Bitmap для него, и скажем всей View-иерархии нарисоваться на этом канвасе.

Теперь в internalBitmap нарисованы все View, которые видны на экране.

Проблемы:
Если у вашего rootView нет заданного фона, нужно предварительно нарисовать на канвасе фон Activity, иначе он будет прозрачным на битмапе.

Хотелось бы рисовать только ту часть иерархии, которая нам нужна. То есть под нашей BlurView, с соответствующим размером.
Кроме того, было бы неплохо уменьшить Bitmap, на котором будет происходить отрисовка. Это ускорит отрисовку View иерархии, сам blur, а так же уменьшит потребление памяти.
Добавляем поле scaleFactor, желательно, чтобы этот коэффициент был степенью двойки.

Уменьшаем bitmap в 8 раз и настраиваем матрицу канваса так, чтобы корректно на нем рисовать, учитывая позицию, размер и scale factor:

Теперь при вызове rootView.draw(internalCanvas), мы будем иметь на internalBitmap уменьшенную копию всей View-иерархии. Выглядеть она будет страшно, но это меня не очень волнует, т.к. дальше я все равно буду ее размывать.

Проблемы:
rootView скажет всем своим детям нарисоваться на канвасе, в том числе и BlurView. Этого хотелось бы избежать, BlurView не должна размывать сама себя. Для этого можно переопределить метод draw(Canvas canvas) в BlurView и делать проверку на каком канвасе ее просят отрисоваться.
Если это системный канвас — разрешаем отрисовку, если это internalCanvas — запрещаем.

Собственно, blur

Я сделал интерфейс BlurAlgorithm и возможность настройки алгоритма.
Добавил 2 реализации, StackBlur (by Mario Klingemann) и RenderScriptBlur. Вариант с RenderScript выполняется на GPU.
Чтобы сэкономить память, я записываю результат в тот же bitmap, который мне пришел на вход. Это опционально.
Так же можно попробовать кэшировать outAllocation и переиспользовать его, если размер входного изображения не изменился.

Когда перерисовывать blur?

Есть несколько вариантов:

  1. Вручную делать апдейт, когда вы точно знаете, что контент изменился
  2. Завязаться на события скролла, если BlurView находится над скроллящимся контейнером
  3. Слушать вызовы draw() через ViewTreeObserver

Я выбрал 3 вариант, используя OnPreDrawListener. Стоит заметить, что его метод onPreDraw дергается каждый раз, когда любая View в иерархии рисует себя. Это, конечно, не идеал, т.к. придется перерисовывать BlurView на каждый чих, но зато это не требует никакого контроля со стороны программиста.

Проблемы:
onPreDraw будет так же вызван, когда будет происходить отрисовка всей иерархии на internalCanvas, а так же при отрисовке BlurView.
Чтобы избежать этой проблемы, я завел флаг isMeDrawingNow.

Вроде все очевидно, кроме одного момента. Ставить его в false нужно через handler, т.к. диспатч отрисовки происходит асинхронно через очередь событий UI потока. Поэтому нужно так же добавить этот таск в очередь событий, чтобы он выполнился именно в конце отрисовки.

Производительность

Много статистики я не насобирал, но на Nexus 4, Nexus 5 весь цикл отрисовки занимает 1-4мс на экранах из демо-проекта.
Galaxy nexus — около 10мс.
Sony Xperia Z3 compact почему-то справляется хуже — 8-16мс.
Тем не менее, производительностью я удовлетворен, FPS держится на хорошем уровне.

Источник

Пишем эффективный blur на Android


Сегодня мы попытаемся разобраться с методами размытия (blur) доступными для Android разработчиков. Прочитав определенное число статей и постов на StackOverflow, можно сказать, что мнений и способов выполнить эту задачу достаточно много. Я попытаюсь собрать все это в кучу.

Читайте также:  And cad для андроид

И так, зачем?

Все чаще и чаще можно заметить эффект размытия в приложениях появляющихся на просторах Google Play Store. Взять хотя бы замечательное приложение Muzei от +RomanNurik или тот же Yahoo Weather. Глядя на эти приложения можно заметить, что при умелом обращении размытием можно добиться очень впечатляющих результатов.

На написание данной статьи меня подтолкнула серия статей Blurring Images, поэтому первая часть статьи будет очень схожа. На самом деле я попытаюсь копнуть немного глубже.

Вот примерно то, чего мы будем пытаться добиться:

Приступим

Для начала хочу показать с чем мы работаем. Я создал 1 activity, внутри которой расположен ViewPager . ViewPager перелистывает фрагменты. Каждый фрагмент — отдельная реализация размытия.
Вот как выглядит мой main_layout.xml :

И вот как выглядит layout фрагмента (fragment_layout.xml):

Как видим, ничего военного — обычная картинка на весь экран с текстом посередине. Также можно заметить дополнительный LinearLayout — я буду его использовать для отображения всякой служебной информации.

Наша цель — размыть фон текста, тем самым подчеркнув его. Вот общий принцип того, как мы это будем делать:

  • Из картинки вырезаем тот участок, который находится непосредственно за TextView
  • Размываем
  • Получившийся результат ставим как фон для TextView

Renderscript

Наверное, самым популярным ответом сегодня на вопрос «как быстро размыть картинку в Android» является Renderscript. Это очень мощный инструмент для работы с изображениями. Несмотря на его кажущуюся сложность, многие его части очень даже просты в использовании. К счастью, blur — это одна из подобных частей.

Давайте разберемся что же здесь происходит:

  • При создании фрагмента — создается layout, добавляется TextView в мою «сервисную панель»(я ее буду использовать чтобы отображать скорость работы алгоритма) и запускается размытие
  • Внутри applyBlur() я регистрирую onPreDrawListener . Делаю я это потому, что на момент вызова этой функции мои UI элементы еще не готовы, поэтому и размывать-то особо нечего. Поэтому мне надо дождаться момента когда мой layout будет измерян и готов к отрисовке. Этот колбэк будет вызван непосредственно перед отрисовкой первого фрейма
  • Внутри onPreDraw() первым делом что я обычно делаю — это меняю возвращаемое значение на true. Дело в том, что IDE генерирует false по умолчанию, а это значит, что отрисовка первого фрейма будет пропущена. В данном случае меня интересует первый фрейм, поэтому ставим true.
  • Далее убираем наш колбек — нас больше не интересуют onPreDraw события
  • Теперь мне надо вытащить Bitmap из моей ImageView. Заставляю ее создать drawing cache и забираю его
  • Ну и, собственно, размытие. Рассмотрим этот процесс подробнее

Сразу хочу отметить, что данный код имеет ряд недостатков, о которых следует обязательно помнить:

  • Данный код не «переразмывает» при изменениях layout’a. По-хорошему необходимо зарегистрировать onGlobalLayoutListener и перезапускать алгоритм при получении этого события
  • Размытие производится в главном потоке. Не пытайтесь делать это в своих приложениях — подобного рода операции надо «выгружать» в отдельный поток, чтобы не блокировать UI. AsyncTask или что-то подобное справятся с этой задачей

Вернемся к blur() :

  • Создается пустой Bitmap, по размеру соответствующий нашему TextView — сюда мы скопируем кусок нашего фона
  • Создаем Canvas, чтобы можно было в этот Bitmap рисовать
  • Смещаем систему координат на позицию, на которой находится TextView
  • Рисуем кусок фона
  • На этом этапе у нас есть Bitmap, который содержит кусок фона, находящийся непосредственно за TextView
  • Создаем Renderscript объект
  • Копируем наш Bitmap в структуру, с которой работает Renderscript
  • Создаем скрипт для размытия (ScriptIntrinsicBlur)
  • Выставляем параметры размытия (в моем случае радиус 20) и запускаем скрипт
  • Копируем результат обратно в наш Bitmap
  • Отлично, у нас есть размытый Bitmap — устанавливаем его как фон для нашего TextView

Вот что получилось:

Как видим, результат довольно неплох на вид и занял у нас 57ms. Учитывая, что на отрисовку одного фрейма не должно уходить больше 16мс (

60fps), можно посчитать, что frame rate в нашем случае упадет до 17fps на период пока выполняется размытие. Я бы сказал, неприемлимо. Имеено поэтому необходимо сгрузить размытие в отдельный поток.

Хочу также заметить, что ScriptIntrinsicBlur доступен в API > 16. Безусловно, можно использовать renderscript support library, что позволит снизить необходимый уровень API.
Но, как нетрудно догадаться, на renderscript’e свет клином не сошелся, поэтому давайте рассмотрим одну из альтернатив.

Читайте также:  Виджет яндекс поиск для андроид

FastBlur

На самом деле размытие — ничто иное как манипуляция с пикселями, поэтому что нам мешает самим этими самыми пикселями и поманипулировать? Благо, на просторах интернета доступно довольно большое кол-во реализаций всевозможных алгоритмов размытия, поэтому наша задача сводится к тому, чтобы выбрать наиболее оптимальный.
На всезнающем StackOverflow (а точнее тут), я наткнулся на неплохую реализацию алгоритма размытия.

Давайте посмотрим что из этого получилось. Весь код приводить не буду, потому что отличаться будет только функция blur():

И вот результат:

Как видим, по качеству сложно заметить разницу с renderscript. Но вот производительность оставляет желать лучшего — 147ms! И это далеко не самый медленный алгоритм! Боюсь даже пробовать размывать по Гауссу.

Оптимизируем

Давайте на секунду задумаемся что из себя представляет размытие. По своей сути размытие очень тесно связано с «потерей» пикселей (здесь хотел бы попросить сильно не ругаться знатоков математики и графики, потому что описываю больше основываясь на свое понимание проблемы, чем на конкретные факты 🙂 ). Что же еще может легко нам помочь «потерять» пиксели? Уменьшение картинки!

Что если мы уменьшим картинку сначала, размоем ее, а потом увеличим обратно?

И так, имеем 13ms renderscript и 2ms FastBlur. Довольно неплохо, учитывая, что качество размытия осталось сравнимо по качеству с предыдущими результатами.

Давайте взглянем на код. Я опишу только вариант с FastBlur, т.к. код для Renderscript будет аналогичен (ссылка на полную версию кода доступна в конце статьи):

  • scaleFactor определяет насколько сильно будем уменьшать картинку. В моем случае уменьшать будем в 8 раз. Причем учитывая что львиную долю пикселей мы потеряем при уменьшении/увеличении картинки, можно смело уменьшать радиус размытия основного алгоритма. Путем научного тыка я уменьшил до 2х
  • Создаем Bitmap. В этот раз он будет меньше — в данном случае в 8 раз.
  • Заметим, что при отрисовке, я выставил флаг FILTER_BITMAP_FLAG , что позволит применить сглаживание при изменении размера картинки
  • Как и прежде, применяем размытие, но теперь ко много меньшей картинке и с меньшим радиусом, что позволяет ускорить алгоритм
  • Ставим эту маленькую картинку как фон для TextView — она автоматически будет увеличена.

Довольно интересно, что Renderscript отработал медленнее, чем FastBlur. Произошло это из-за того, что мы сэкономили время на копировании Bitmap в Allocation и обратно.

Как результат, мы получили довольно шустрый метод размытия картинок на Android

Источник

Тусклый и размытый фон за фрагментом Android

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

Однако это не размывает и не затемняет другой макет кадра, который содержит RecyclerView и CardView, эти элементы по-прежнему отображаются с полной непрозрачностью, не знаете почему?

Вот скриншот, как вы можете видеть, что фон становится размытым, но не все виды за фрагментом затемняются.

Я хотел бы получить тот вид, который имеет NavigationDrawer, когда вы его открываете, вот пример внутри того же приложения, и все правильно затемняется и размывается.

Вот мой XML-файл, если он помогает,

2 ответа

Как указано в комментарии, FLAG_BLUR_BEHIND не работал с макетом фрейма, который я использовал.

Вместо этого я решил просто изменить передний план родительского

А когда нужно убрать эффект «тусклости»

Флаг FLAG_BLUR_BEHIND устарел с API 14, поэтому не следует ожидать, что он будет работать.

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

Идея этого представления заключается в том, что вы вызываете .setBlurredView(View view) , причем view — это представление под BlurringView , которое должно быть размыто. Затем вызывайте .invalidate() всякий раз, когда размытие нужно перерисовать, поскольку вид для размытия изменился. Обратите внимание, что этот эффект размытия использует эффект RenderScript ScriptIntrinsicBlur .

Источник

Как я могу размыть фон моего textview в android studio

У меня есть изображение с textview поверх него. Мне интересно, как я могу размыть фон моего textview (только часть изображения), чтобы сделать его более читабельным. Я пробовал смотреть на размытую библиотеку, но, похоже, она может только размыть всю картину.

Читайте также:  Android permission bluetooth admin

3 ответа

В одном из моих проектов я использовал PopupWindow . Моя проблема в том, что при просмотре popupwindow дизайн кажется неудобным для работы. Поэтому я хочу затемнить или размыть свой фон активности. Я много искал, но большинство ответов, похоже, только для Dialog , а не для PopupWindow . Можно ли в.

Я видел много библиотек и примеров того, как размыть все, что находится за UIView. Я хотел бы сделать что-то подобное. В моем UIView я рисую пользовательскую фигуру, используя UIBezierPaths, а все остальное прозрачно — я хотел бы заполнить этот путь bezier размытой версией того, что находится под.

Добавьте это пользовательское решение BlurView: https://github.com/mmin18/RealtimeBlurView

Затем поместите BlurView за TextView в свой макет:

Наконец, установите размытие и цвет по желанию в коде

Вы можете использовать макет кадра для создания эффекта размытия , макет кадра позволяет выровнять виды по оси z последний дочерний элемент появляется над всеми остальными дочерними элементами, пример использования:-

Вы также можете установить фон textview на некоторый цвет (#AARRGGBB) с более низким aplha (AA max alpha), чтобы легко воспроизвести аналогичный эффект.

Поскольку вы хотите сделать свой textview более читабельным, поскольку он находится над imageview. Чтобы сделать это вместо размытия изображения, почему бы вам не использовать градиентный рисунок или цвет.

У меня было такое же требование в моем приложении, и я просто пошел с размещением представления оценки над частью ImageView.

Давайте сделаем это

Шаг 1: Создайте градиентную фигуру и поместите ее в папку drawable, допустим, имя фигуры gradient_overlay.xml

Шаг 2: Создайте фиктивное представление и поместите его поверх ImageView или части ImageView.

Шаг 3: Затем выровняйте textview по gradientView. так, чтобы текст стал правильно видимым.

Я ищу его с очень давних времен. Я хочу размыть фон нового добавленного вида в макет кадра. Новый добавленный вид представляет собой линейный макет, который открывается во всплывающем окне. Теперь, как я могу размыть этот макет кадра? Я просмотрел все сообщения о размытии фона, но я не нашел это.

Как размыть фон, но не текст, который находится поверх него? Это то, как я хочу показать.

Похожие вопросы:

Когда я запускаю свое приложение, оно запускает Activity , который должен иметь прозрачный заголовок, и все, что в данный момент отображается в фоновом режиме, должно быть размыто. Я в состоянии.

извините за мой английский :). Мне нужно размыть фон моей диалоговой активности, и я попробовал этот метод Размытие BackGround За AlertDialog И я посылаю свой bitmap с этим кодом : Bitmap back1 =.

У меня есть такая таблица на заднем плане: я хочу установить свой tableview с размытой анимацией на заднем плане вот так: Я попытался установить цвет фона таблицы на черный и установить Альфа-код.

В одном из моих проектов я использовал PopupWindow . Моя проблема в том, что при просмотре popupwindow дизайн кажется неудобным для работы. Поэтому я хочу затемнить или размыть свой фон активности.

Я видел много библиотек и примеров того, как размыть все, что находится за UIView. Я хотел бы сделать что-то подобное. В моем UIView я рисую пользовательскую фигуру, используя UIBezierPaths, а все.

Я ищу его с очень давних времен. Я хочу размыть фон нового добавленного вида в макет кадра. Новый добавленный вид представляет собой линейный макет, который открывается во всплывающем окне. Теперь.

Как размыть фон, но не текст, который находится поверх него? Это то, как я хочу показать.

У меня есть GUI, как это: Gui +LastFound +AlwaysOnTop +ToolWindow -Caption Gui, Add, Text,, 00:00 WinSet, Transparent, 200 Gui, Show, NoActivate Скриншот: Есть ли способ постепенно размыть фон.

Я хочу сделать глобальный размытый фон, поэтому я установил фоновое изображение в тег, затем я создал свойство фильтра размытия, но оно оказалось бесполезным. Изображение оставалось незамутненным.

Я хочу сделать свою верхнюю навигацию прозрачной ( opacity: 0.9 ), и я хочу сделать фон за верхней навигацией своего рода размытым (как это сделала здесь Apple Inc:) Как размыть фон?

Источник

Оцените статью