Colorful animation for Android ImageView

I want to add blur animation to ImageView , but with a set duration. So, for example, I want the image to get wet over time.

I already have a way to blur the image, but I need it to switch from blur to not blur, say, 2 seconds.

Can anybody help me?

EDIT: This is the method I currently have to blur.

 public Bitmap blur(Bitmap sentBitmap, int radius) { // Stack Blur Algorithm by Mario Klingemann < mario@quasimondo.com > Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true); if (radius < 1) { return (null); } int w = bitmap.getWidth(); int h = bitmap.getHeight(); int[] pix = new int[w * h]; Log.e("pix", w + " " + h + " " + pix.length); bitmap.getPixels(pix, 0, w, 0, 0, w, h); int wm = w - 1; int hm = h - 1; int wh = w * h; int div = radius + radius + 1; int r[] = new int[wh]; int g[] = new int[wh]; int b[] = new int[wh]; int rsum, gsum, bsum, x, y, i, p, yp, yi, yw; int vmin[] = new int[Math.max(w, h)]; int divsum = (div + 1) >> 1; divsum *= divsum; int dv[] = new int[256 * divsum]; for (i = 0; i < 256 * divsum; i++) { dv[i] = (i / divsum); } yw = yi = 0; int[][] stack = new int[div][3]; int stackpointer; int stackstart; int[] sir; int rbs; int r1 = radius + 1; int routsum, goutsum, boutsum; int rinsum, ginsum, binsum; for (y = 0; y < h; y++) { rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; for (i = -radius; i <= radius; i++) { p = pix[yi + Math.min(wm, Math.max(i, 0))]; sir = stack[i + radius]; sir[0] = (p & 0xff0000) >> 16; sir[1] = (p & 0x00ff00) >> 8; sir[2] = (p & 0x0000ff); rbs = r1 - Math.abs(i); rsum += sir[0] * rbs; gsum += sir[1] * rbs; bsum += sir[2] * rbs; if (i > 0) { rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; } else { routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; } } stackpointer = radius; for (x = 0; x < w; x++) { r[yi] = dv[rsum]; g[yi] = dv[gsum]; b[yi] = dv[bsum]; rsum -= routsum; gsum -= goutsum; bsum -= boutsum; stackstart = stackpointer - radius + div; sir = stack[stackstart % div]; routsum -= sir[0]; goutsum -= sir[1]; boutsum -= sir[2]; if (y == 0) { vmin[x] = Math.min(x + radius + 1, wm); } p = pix[yw + vmin[x]]; sir[0] = (p & 0xff0000) >> 16; sir[1] = (p & 0x00ff00) >> 8; sir[2] = (p & 0x0000ff); rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; rsum += rinsum; gsum += ginsum; bsum += binsum; stackpointer = (stackpointer + 1) % div; sir = stack[(stackpointer) % div]; routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; rinsum -= sir[0]; ginsum -= sir[1]; binsum -= sir[2]; yi++; } yw += w; } for (x = 0; x < w; x++) { rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; yp = -radius * w; for (i = -radius; i <= radius; i++) { yi = Math.max(0, yp) + x; sir = stack[i + radius]; sir[0] = r[yi]; sir[1] = g[yi]; sir[2] = b[yi]; rbs = r1 - Math.abs(i); rsum += r[yi] * rbs; gsum += g[yi] * rbs; bsum += b[yi] * rbs; if (i > 0) { rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; } else { routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; } if (i < hm) { yp += w; } } yi = x; stackpointer = radius; for (y = 0; y < h; y++) { // Preserve alpha channel: ( 0xff000000 & pix[yi] ) pix[yi] = ( 0xff000000 & pix[yi] ) | ( dv[rsum] << 16 ) | ( dv[gsum] << 8 ) | dv[bsum]; rsum -= routsum; gsum -= goutsum; bsum -= boutsum; stackstart = stackpointer - radius + div; sir = stack[stackstart % div]; routsum -= sir[0]; goutsum -= sir[1]; boutsum -= sir[2]; if (x == 0) { vmin[y] = Math.min(y + r1, hm) * w; } p = x + vmin[y]; sir[0] = r[p]; sir[1] = g[p]; sir[2] = b[p]; rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; rsum += rinsum; gsum += ginsum; bsum += binsum; stackpointer = (stackpointer + 1) % div; sir = stack[stackpointer]; routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; rinsum -= sir[0]; ginsum -= sir[1]; binsum -= sir[2]; yi += w; } } Log.e("pix", w + " " + h + " " + pix.length); bitmap.setPixels(pix, 0, w, 0, 0, w, h); return (bitmap); } 
+6
source share
5 answers

Blur effects are always complicated on Android. Essentially, you have to decide between looks and performance. The better the blur looks longer, the better, and if the blur itself is not instantaneous, you cannot really bring the blur to life.

The original blur algorithm gives really good results, but because of this, it also makes it very slow to blur the animation. To demonstrate what it takes to effectively blur this image, I created a simple blur animation by scaling the bitmap down:

 public class BlurAnimation extends Animation { private final ImageView imageView; private final Bitmap bitmap; private final float startValue; private final float stopValue; private final float difValue; private BlurAnimation(ImageView imageView, Bitmap bitmap, int startValue, int stopValue) { this.imageView = imageView; this.bitmap = bitmap; this.startValue = startValue; this.stopValue = stopValue; this.difValue = stopValue - startValue; } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { super.applyTransformation(interpolatedTime, t); int current = (int)(this.difValue * interpolatedTime + this.startValue + 0.5f); Bitmap blurred = quickBlur(this.bitmap, current); this.imageView.setImageBitmap(blurred); } public Bitmap quickBlur(Bitmap bitmap, int factor) { if(factor <= 0) { return Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); } return Bitmap.createScaledBitmap(bitmap, bitmap.getWidth() / factor, bitmap.getHeight() / factor, true); } } 

This works pretty well (although there is still some lag), but the results cannot compare with your blur algorithm, it looks awful:

enter image description here

So, you see that it is very difficult to combine performance and good looks when it comes to blurring the image, but there are some options primarily RenderScript . RenderScript very fast and has a built-in Gaussian blur filter. I have never used it, but from what I heard may be the solution to your problem.

You can also try downloading already smaller versions of the image, this will lead to the same effect as in the gif above, but it will be even faster. The downside is that using this option in Animation is problematic again, but if you just need a blurry image and you really don't care about quality, you have to go for this option.

More information on RenderScript and other quick blur options in this answer

+8
source

I will not extend my answer too long with the code, because, frankly, I do not have it, but I will try to indicate the key things that you should consider and some useful links.

First, the approach:

  • blur as fast as possible
  • cache blurry result
  • Shading

Blur as fast as possible:

your algorithm looks very nice, and I believe that it gives a good effect, but actually it works on Java VM in a single thread. You will certainly get much better performance using RenderScript. This is because RenderScript automatically scales the rendering process to multiprocessors and GPUs.

the basic code for it below, taken directly from android-developers.blogspot.com :

 RenderScript rs = RenderScript.create(theActivity); ScriptIntrinsicBlur theIntrinsic = ScriptIntrinsicBlur.create(mRS, Element.U8_4(rs));; Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap); Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap); theIntrinsic.setRadius(25.f); theIntrinsic.setInput(tmpIn); theIntrinsic.forEach(tmpOut); tmpOut.copyTo(outputBitmap); 

cache blurry results:

This is because Blur takes time. There will also be many memory implications, and you should carefully monitor it. You, of course, cannot do this very well on the scroll list, which processes views and stuff. Perhaps a tip might use the Picasso library ( LINK ) for this, as well as handle your threads. Something like that:

 Picasso .with(context) .load(/* asset/res/file/url */) .transform(new BlurTransformation(value)) .into(target); // The transform method is automatically called by Picasso in a background thread public class BlurTransformation implements com.squareup.picasso.Transformation { private final float radius; // radius is corner radii in dp public BlurTransformation(final float radius) { this.radius = radius; } @Override public Bitmap transform(final Bitmap source) { // do the transformation and return it here } @Override public String key() { return "blur"+Float.toString(radius); } } // you can also use this to get it instantly Picasso... all the code... .get(); 

Shading:

here you can balance performance and good looks. The reality is that real animation is impossible without actually rendering each frame for each step, but with cross-fading between several key frames, you can achieve great results.

How many key frames you will use will depend on the required performance, the amount of free memory on the device, etc.

If you have everything in order with two keyframes (1 not blurry and 1 completely blurry), you can probably apply TransitionDrawable to it. If you want a more dramatic effect, you will have to create a series of cross fading transitions, or perhaps create your own custom one.

in just 2 keyframes, you can see an example of the Yahoo Weather application if you want to see an example with several keyframes that you want to check out Muzei live wallpapers .

very useful links *

In the following link, you will see a pleasant discussion of the creator of Muzei (Roman Nurik, who is also one of Google’s engineers working on Android) about how he achieved keyframes, why this is the only way to do it, and why, although more complicated code, he creates in the end a much more beautiful result: (short version) https://plus.google.com/+RomanNurik/posts/2sTQ1X2Cb2Z (full version) https://medium.com/@romannurik/serendipitous-ideas-3a1721a6f716

This link is the source code for Muzei live wallpapers, where you can check how it calculates key frames and animates wallpapers: https://github.com/romannurik/muzei

Good luck and happy coding!

+6
source

Blur itself takes a lot of time, even on new devices. Blur animations will be even worse. RenderScript didn't help either. It is best to cross between blurry and non-blurry images:

 package com.example.simon.crossfadeblur; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; public class MainActivity extends Activity { public Bitmap blur(Bitmap sentBitmap, int radius) { // Stack Blur Algorithm by Mario Klingemann < mario@quasimondo.com > Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true); if (radius < 1) { return (null); } int w = bitmap.getWidth(); int h = bitmap.getHeight(); int[] pix = new int[w * h]; Log.e("pix", w + " " + h + " " + pix.length); bitmap.getPixels(pix, 0, w, 0, 0, w, h); int wm = w - 1; int hm = h - 1; int wh = w * h; int div = radius + radius + 1; int r[] = new int[wh]; int g[] = new int[wh]; int b[] = new int[wh]; int rsum, gsum, bsum, x, y, i, p, yp, yi, yw; int vmin[] = new int[Math.max(w, h)]; int divsum = (div + 1) >> 1; divsum *= divsum; int dv[] = new int[256 * divsum]; for (i = 0; i < 256 * divsum; i++) { dv[i] = (i / divsum); } yw = yi = 0; int[][] stack = new int[div][3]; int stackpointer; int stackstart; int[] sir; int rbs; int r1 = radius + 1; int routsum, goutsum, boutsum; int rinsum, ginsum, binsum; for (y = 0; y < h; y++) { rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; for (i = -radius; i <= radius; i++) { p = pix[yi + Math.min(wm, Math.max(i, 0))]; sir = stack[i + radius]; sir[0] = (p & 0xff0000) >> 16; sir[1] = (p & 0x00ff00) >> 8; sir[2] = (p & 0x0000ff); rbs = r1 - Math.abs(i); rsum += sir[0] * rbs; gsum += sir[1] * rbs; bsum += sir[2] * rbs; if (i > 0) { rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; } else { routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; } } stackpointer = radius; for (x = 0; x < w; x++) { r[yi] = dv[rsum]; g[yi] = dv[gsum]; b[yi] = dv[bsum]; rsum -= routsum; gsum -= goutsum; bsum -= boutsum; stackstart = stackpointer - radius + div; sir = stack[stackstart % div]; routsum -= sir[0]; goutsum -= sir[1]; boutsum -= sir[2]; if (y == 0) { vmin[x] = Math.min(x + radius + 1, wm); } p = pix[yw + vmin[x]]; sir[0] = (p & 0xff0000) >> 16; sir[1] = (p & 0x00ff00) >> 8; sir[2] = (p & 0x0000ff); rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; rsum += rinsum; gsum += ginsum; bsum += binsum; stackpointer = (stackpointer + 1) % div; sir = stack[(stackpointer) % div]; routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; rinsum -= sir[0]; ginsum -= sir[1]; binsum -= sir[2]; yi++; } yw += w; } for (x = 0; x < w; x++) { rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; yp = -radius * w; for (i = -radius; i <= radius; i++) { yi = Math.max(0, yp) + x; sir = stack[i + radius]; sir[0] = r[yi]; sir[1] = g[yi]; sir[2] = b[yi]; rbs = r1 - Math.abs(i); rsum += r[yi] * rbs; gsum += g[yi] * rbs; bsum += b[yi] * rbs; if (i > 0) { rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; } else { routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; } if (i < hm) { yp += w; } } yi = x; stackpointer = radius; for (y = 0; y < h; y++) { // Preserve alpha channel: ( 0xff000000 & pix[yi] ) pix[yi] = ( 0xff000000 & pix[yi] ) | ( dv[rsum] << 16 ) | ( dv[gsum] << 8 ) | dv[bsum]; rsum -= routsum; gsum -= goutsum; bsum -= boutsum; stackstart = stackpointer - radius + div; sir = stack[stackstart % div]; routsum -= sir[0]; goutsum -= sir[1]; boutsum -= sir[2]; if (x == 0) { vmin[y] = Math.min(y + r1, hm) * w; } p = x + vmin[y]; sir[0] = r[p]; sir[1] = g[p]; sir[2] = b[p]; rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; rsum += rinsum; gsum += ginsum; bsum += binsum; stackpointer = (stackpointer + 1) % div; sir = stack[stackpointer]; routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; rinsum -= sir[0]; ginsum -= sir[1]; binsum -= sir[2]; yi += w; } } Log.e("pix", w + " " + h + " " + pix.length); bitmap.setPixels(pix, 0, w, 0, 0, w, h); return (bitmap); } public class FadeView extends FrameLayout { private long mFadeDelay = 1000; private ImageView mFirst; private ImageView mSecond; private boolean mFirstShowing; public FadeView(Context context) { super(context); init(context); } public FadeView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public FadeView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } private void init(Context c){ mFirst = new ImageView(c); mSecond = new ImageView(c); mFirst.setAlpha(1.0f); mSecond.setAlpha(0.0f); mFirstShowing = true; addView(mFirst); addView(mSecond); } public void setFadeDelay(long fadeDelay) { mFadeDelay = fadeDelay; } public void ShowImage(Drawable d){ if(mFirstShowing){ mSecond.setImageDrawable(d); mSecond.animate().alpha(1.0f).setDuration(mFadeDelay); mFirst.animate().alpha(0.0f).setDuration(mFadeDelay); }else { mFirst.setImageDrawable(d); mSecond.animate().alpha(0.0f).setDuration(mFadeDelay); mFirst.animate().alpha(1.0f).setDuration(mFadeDelay); } mFirstShowing = !mFirstShowing; } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final FadeView fw = new FadeView(this); setContentView(fw); fw.setOnClickListener(new View.OnClickListener() { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image); Bitmap blurredBitmap = blur(bitmap, 100); Drawable d1 = new BitmapDrawable(getResources(), blurredBitmap); Drawable d2 = getResources().getDrawable(R.drawable.image); boolean flag; @Override public void onClick(View view) { if(flag){ fw.ShowImage(d1); }else { fw.ShowImage(d2); } flag = !flag; } }); } } 

Note Crossfade code was taken from: Source (click animation)

Another way I can come up with is using jQuery and animating the blur inside the webview.

+1
source
 imageview = (ImageView) itemView.findViewById(R.id.imageView); BitmapDrawable drawable = (BitmapDrawable) imageview.getDrawable(); Bitmap bitmap = drawable.getBitmap(); Bitmap blurred = blurRenderScript(bitmap, 25); imageview.setImageBitmap(blurred); 

// these are blur methods

 @SuppressLint("NewApi") private Bitmap blurRenderScript(Bitmap smallBitmap, int radius) { try { smallBitmap = RGB565toARGB888(smallBitmap); } catch (Exception e) { e.printStackTrace(); } Bitmap bitmap = Bitmap.createBitmap( smallBitmap.getWidth(), smallBitmap.getHeight(), Bitmap.Config.ARGB_8888); RenderScript renderScript = RenderScript.create(context); Allocation blurInput = Allocation.createFromBitmap(renderScript, smallBitmap); Allocation blurOutput = Allocation.createFromBitmap(renderScript, bitmap); ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript)); blur.setInput(blurInput); blur.setRadius(radius); // radius must be 0 < r <= 25 blur.forEach(blurOutput); blurOutput.copyTo(bitmap); renderScript.destroy(); return bitmap; } private Bitmap RGB565toARGB888(Bitmap img) throws Exception { int numPixels = img.getWidth() * img.getHeight(); int[] pixels = new int[numPixels]; //Get JPEG pixels. Each int is the color values for one pixel. img.getPixels(pixels, 0, img.getWidth(), 0, 0, img.getWidth(), img.getHeight()); //Create a Bitmap of the appropriate format. Bitmap result = Bitmap.createBitmap(img.getWidth(), img.getHeight(), Bitmap.Config.ARGB_8888); //Set RGB pixels. result.setPixels(pixels, 0, result.getWidth(), 0, 0, result.getWidth(), result.getHeight()); return result; } 
0
source

I'm a little late to the party, but if I upset you right, do you want to "disappear in the blur" so that it grows constantly?

You can achieve this effect by stacking two ImageViews on top of each other. The bottom one shows an untouched image, the top one shows a blurry image that is previously displayed. The top one should be invisible (alpha = 0f). Then you fade in the upper ImageView and reduce the lower ImageView. This will give you the desired effect. You can adjust the effect by playing with timings and measurements.

Good luck :)

0
source

Source: https://habr.com/ru/post/972453/


All Articles