Android color change animation

Android: Change colour of drawable asset programmatically with animation

Jun 21, 2015 · 4 min read

If you have ever had to gradually change the colour of a button, image or drawable asset in your application from say… grey to orange, you have two options.

Options

  1. Bundle the same asset in the colour grey and orange, overlay them and fade in one above the other.
  2. Programmatically overlay the image or drawable with the colour you want.

While the purpose of this article is mainly to discuss option 2, option 1 will fulfil most requirements and most developers will find option 1 easier to implement. With option 1, your images can contain gradients, shadows and multiple colours and it will still work. With option 2, it would be very difficult to cater for gradients, shadows and different colours.

Option 1: Overlay 2 images and fade in

We want to change a grey image to orange. In order to do this we will need two images as shown. The images will have to be identical and position one over the other in your layout. We have 2 options here as well. Layout grey above orange and fade out grey when you want to convert the image to orange by animating it’s alpha to 0. The second option is to put the orange image above the grey one and set it’s alpha to zero, then animate its alpha to 1 when you want to turn the image orange.

In this scenario, our layout may look something like this.

As you can see above, the two images should perfectly overlay. The grey image is visible and the orange image has it’s alpha value set to zero meaning that it is not visible.

Now if we want to convert the image to orange, we can use a ValueAnimator to gradually change alpha from zero to one.

This works beautifully from Honeycomb and above and works exactly as expected.

Option 2: Overlay colour on top of image

When going down this route, keep in mind that when you overlay a colour, it will overlay all non transparent pixels. Also, you’ll either have to overlay a Drawable or an ImageView. In this example I overlay an ImageView however with a drawable the concept the largely the same.

This time our layout will contain just one ImageView on which we will overlay colour programmatically.

In order to overlay a colour, we will use an ObjectAnimator to animate the alpha for the colour we want to overlay from zero to one. If the overlay colour has an alpha value set on it, the alpha value will be retained and we will effectively animate from zero to whatever the alpha value of the overlay colour is.

In order for this to work, we will have to extract the solid colour from the given colour and adjust it’s alpha. This means that if we want to animate to orange, we will have to break down the orange color into it’s Alpah, Red, Green and Blue values and adjust the alpha depending on where we are in the transition. The code for this is below.

Читайте также:  Android composite adb interface driver win 7

In the code above, “mul” is a multiplier for the alpha value where zero means the overlay is transparent (we will remove the colour filter) and 1 means that the alpha value is set to the value specified by the colour hex code.

The Porter/Duff mode specifies the behaviour that our overlay will take, whether it’s colour will blend with the image’s colours or whether it will replace it. There are a few different modes here to choose from, if you are interested in what these are, a great explanation of Porter/Duff blend modes can be found here.

Result

Which ever approach you use, the result looks like this.

So which one should I use?

Ultimately, this comes down to your requirements. In my use case above, the results are identical to the extent that I record videos of both the outcomes and couldn’t tell the difference between them.

Option 1 can handle images with multiple colours and gradients and can even be used if your image changes slightly. Option 2 does not require you to bundle an extra asset and can be used to change to any colour you want (user could pick a colour from a colour picker for example).

Do you have any advice on how to achieve a similar result? Lets hear it in the comments.

For more Android development article or follow me on LinkedIn, Twitter or Google+.

Источник

Change Theme Dynamically with Circular Reveal Animation on Android

Introduction

Dark theme on Android is on a hype at the moment. More and more apps add support for Dark theme over time allowing users to customize their phones, save battery and provide better accessibility. Though another trend which grows today is animated theme changes. First app I saw support of this was Telegram:

After that in different modifications such feature started to appear in other apps, for example VK.
The effect is amazing. And in this article we’ll go into how to implement such functionality in your app.

Disclaimer: Android UI Toolkit currently is pretty bad, especially in dynamic styling. To implement such a feature one need to have custom views with custom theming support in the app. If your app is small, then there is no actual need for investing time into implementing your custom views. Hopefully with help of Jetpack Compose we’ll get more adequate dynamic theming and implementation of such a feature will be more straightforward. Though in this article we’ll try to get some simple solution for dynamic customization.

Basics

Thanks to developers of Telegram app for making code open sourced, so we can take a look at how developers implemented this feature in the repository (lines highlighted).
There is a lot of code, so let’s get the idea of the whole algorithm.

In Android 9 we have native Dark Theme support. The issue is that it is part of configuration and Android UI Toolkit doesn’t allow to change configuration dynamically and to change theme it is needed to restart all the activities in the app. That is clearly not the solution we are looking for.
Basic support for Dark Theme with app restart is fine and is better than only providing just light theme. But to provide a really good UX it seems without custom theming we’ll not be able to achieve what we want.

The main algorithm is the following:

  • we have some hidden ImageView on the screen
  • on request to change theme we draw all the content of the screen on the Canvas
  • convert content of Canvas into Bitmap and put it into ImageView
  • change theme on all views
  • start circular reveal animation for our content of the screen (from 0 radius to full size)
Читайте также:  Живые обои для андроида солнце

This will create animation when new theme reveals with animation over old theme.
Sounds hacky, though pretty working solution.

Also with such a technique we can implement other different effects, for example we can implement old theme to disappear with revealing new theme underneath. For such we’ll have:

  • hidden ImageView as in previous case with setting content of screen as Bitmap into it
  • change theme on all views
  • start circular reveal animation for our image (from full size to 0 radius)

Let’s dive into how this can be implemented

Implementation

Layout

We’ll start from describing our test layout:

Here we’ll have our hidden ImageView and container ( LinearLayout containing out test TextView and Button which we’ll use in our test).

Change Theme

Here is our code which is responsible to change theme with animation:

Let’s look in details what we do here:

  • first of all we make a defensive check to not start new animation when previous is still in progress
  • then we get the dimensions of the container with content to create bitmap, draw all the content into that bitmap and set that bitmap into ImageView
  • we have left TODO in the code, where we’ll need to change theme for all views. We’ll get back to that later
  • finally we start reveal animation for container, which will actually reveal our new theme

Next we should somehow make our views to support dynamic theming.

ThemeManager

We’ll create single place for managing application theme — ThemeManager, and object which describes the Theme itself.
Theme will contain different sub-Themes for each design component — TextView, Button etc.

For example for TextView we can create the following Theme description:

Similarly for container (e.g. LinearLayout) we can create:

And the Theme itself will be enum containing different combinations mapped over some finite number of themes — for example LIGHT and DARK:

And our ThemeManager will just provide single instance of current theme:

Custom Views

Next we need to create our own wrappers for views to support changes of dynamic theme changing.
Let’s make our own custom TextView as example:

We just create our view with setTheme method, where we apply all the required fields to be styled.

Then we replace in xml our TextView with com.MyTextView and in our TODO access that view and set theme.
Such approach would work, but the issue is that it doesn’t scale and it requires layout files changes. But there is a way to fix all the issues, let’s see how.

Dynamic theme changes

Instead of explicitly setting themes on each view it would be better if views subscribed to theme changes and reactively updated by themselves.
For this we’ll add a bit more functionality into ThemeManager — we’ll add ability to add listeners. Yes, listeners in 2020 🙂 One can use RxJava or kotlin Flow, it actually doesn’t matter. Listeners will be enough, so, we’ll use them.

Nothing really interesting, just added listeners, ability to add and remove them and we update listeners on each change of theme.

Views with reactive theme changes support

Using these listeners we update our MyTextView to trigger update on theme changed:

Instead of setTheme method we now have onThemeChanged . And in different callbacks of View lifecycle we subscribe and unsubscribe from ThemeManager .

Custom LayoutInflater

In order to not change our layouts we can use custom layout inflater factories. The idea is that we can intercept inflating views based on the names (“TextView”, “Button”, “com.MyTextView” etc.). And we can provide our own implementations for base views. Same approach is done in AppCompat.

Basic implementation of the LayoutInflater.Factory2 looks like this:

Читайте также:  Titanium backup pro для андроид что это

We intercept in onCreateView some views which support our dynamic theme changes and other views we ask for AppCompatDelegate to create.

But there is one trick with setting this factory — it should be done before super.onCreate(. ) :

Finally

And we’re good! Let’s look at the results (sorry, for artifacts in gif, unfortunately video recorder in Android Studio didn’t want to record without them 🙁 ):

Also if we change our setTheme method we can implement another version:

Awesome results, it works pretty smooth and provides a good UX with not that huge effort so far.

What next

You can find code for these in this gist.
Also if you’d like to play with this as an exercise you can change place where reveal animation starts. Currently we use center for simplicity, but you can use for example Switch (which changes theme) as a pivot.

One can take a look at sample project here.
But, please, take it as inspiration and don’t copy paste as is into production.
Thank you

Conclusion

I hope you found this article useful and maybe some ideas will help you to implement new cool features in your apps.
Don’t forget to try new things, read code written by others, add animations to your app for better UX.

Thanks for reading!
If you enjoyed this article you can like it by clicking on the👏 button (up to 50 times!), also you can share this article to help others.

Have you any feedback, feel free to reach me on twitter , facebook

Источник

Анимации в Android по полочкам (Часть 3. «Низкоуровневые» анимации)

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

Часть 3. «Низкоуровневые» анимации

1. Рисование на канвасе View

Первый способ который мы рассмотрим это рисование в методе onDraw нашего объекта View . Реализуется данный способ просто, достаточно переопределить onDraw и в конце вызвать postInvalidateOnAnimation() .

В данном примере наш drawable будет перемещаться по оси x.

Пример со снежинками выше будет занимать несколько больше кода, т.к. нам нужно хранить состояние каждой отдельной снежинки отдельно.

  • Случаи в которых легче нарисовать анимацию программно

Достоинства:

  • Можно создавать анимации зависящие абсолютно от любых параметров
  • Нет лишних затрат на объекты View

Недостатки:

  • Расчёты анимации и отрисовка происходят в UI thread

2. Рисование на канвасе SurfaceView

Что если расчёт следующего шага анимации будет занимать значительное время? Мы всё ещё можем воспользоваться первым способом и вынести расчёты в отдельный поток. Но это всё равно не приведёт к 100% плавности в анимации т.к. UI thread может быть загружен ещё чем либо помимо нашей анимации.

Android позволяет отвязаться от основного цикла(main loop) отрисовки с помощью компонента SurfaceView . А раз мы больше не привязаны к основному циклу, то нам придётся держать свой поток для расчётов и отрисовки. SurfaceView предоставляет коллбэки в которых мы можем запустить и остановить наш поток. В потоке по окончанию расчётов мы будем отрисовывать нашу анимацию.

Реализация той же анимации снежинок будет выглядеть следующим образом:

  • Случаи в которых легче нарисовать анимацию программно
  • Игры

Достоинства:

  • Можно создавать анимации зависящие абсолютно от любых параметров
  • Нет лишних затрат на объекты View

Недостатки:

3. OpenGL


Точно также, как и на канвасе, мы можем рисовать используя OpenGL API. Если вы задумали что-либо сложнее чем куб на картинке, то стоит посмотреть в сторону какого-либо движка, например libgdx. К сожалению, даже базовый пример займёт здесь довольно много места, поэтому ограничимся только этим кратким превью.

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

Недостатки:

Источник

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