Android Tv Background Dynamic Change with Transition Effect

Keywords: Android less

In Android TV, when an item is selected, the background is switched to a blurred image of the resource. The switching should not be very abrupt, but should have transitional effect.


Implementation steps

  • Get the image in the currently selected item: First, get the View where the current focus is, and monitor the global focus through ViewTreeObserver.OnGlobalFocusChangeListener. When the focus moves, get the View where the focus is. If the keystroke interval is less than 350 ms, it will not execute.
public class LauncherActivity extends BaseActivity implements ViewTreeObserver.OnGlobalFocusChangeListener{
    private final static int MSG_BLUR_BG = 0x2003;
    private final static int MSG_UPDATE_BG = 0x2004;
    private final static int MSG_REFRESH_BG_DELAY = 350;
    private ViewTreeObserver mViewTreeObserver;
    private TransitionDrawable mTransitionDrawable;
    private View focusView;
.......

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_launcher);
        .......
        mViewTreeObserver = this.getWindow().getDecorView().getViewTreeObserver();
        mViewTreeObserver.addOnGlobalFocusChangeListener(this);
        .......
    }

  @Override
    public void onGlobalFocusChanged(View oldFocus, View newFocus) {
        mHandler.removeMessages(MSG_BLUR_BG);
        Message msg = mHandler.obtainMessage();
        msg.what = MSG_BLUR_BG;
        msg.obj = newFocus;
        mHandler.sendMessageDelayed(msg, MSG_REFRESH_BG_DELAY);
    }
}
  • After getting the view where the focus is, the Bitmap object on the view is obtained by View.getDrawingCache(). This method is time-consuming, so it is executed in the thread, and then compressed and blurred. CustomFrameLayout is the layout of each item. View.setDrawingCacheEnabled(true) must be called before using View.getDrawingCache(), and View.destroyDrawingCache() must be called after using the Bitmap object.
    View. setDrawing CacheEnabled (false); release resources.
    Gauss blurring algorithm uses script Intrinsic Blur provided by android system to call the underlying C/C++. It is very efficient. Before implementing blurring, it is better to zoom out the image, so the efficiency will be faster.
private void blurCurFocusImage(View curFocusView) {
        if (curFocusView == null) {
            return;
        }
        focusView = curFocusView;
        if (focusView instanceof CustomFrameLayout) {//If the focus is on the top navigation bar, do not deal with it
            focusView.setDrawingCacheEnabled(true);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Bitmap newBitmap = focusView.getDrawingCache();//This method is time-consuming and executed in threads
                    Drawable newDrawable = new    BitmapDrawable(DisplayUtil.rsBlur(LauncherActivity.this, newBitmap));
                    Message msg = mHandler.obtainMessage();
                    msg.what = MSG_UPDATE_BG;
                    msg.obj = newDrawable;
                    mHandler.sendMessage(msg);
                    newBitmap.recycle();
                }
            }).start();
        }
 public static Bitmap rsBlur(Context context, Bitmap source) {
        int radius = BLUR_RADIUS;//Fuzzy degree
        float scale = BLUR_SCALE;//Scaling ratio
        int width = Math.round(source.getWidth() * scale);
        int height = Math.round(source.getHeight() * scale);
        Bitmap inputBmp = Bitmap.createScaledBitmap(source, width, height, false);
        RenderScript renderScript = RenderScript.create(context);
        // Allocate memory for Renderscript to work with
        final Allocation input = Allocation.createFromBitmap(renderScript, inputBmp);
        final Allocation output = Allocation.createTyped(renderScript, input.getType());
        // Load up an instance of the specific script that we want to use.
        ScriptIntrinsicBlur scriptIntrinsicBlur = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript));
        scriptIntrinsicBlur.setInput(input);
        // Set the blur radius
        scriptIntrinsicBlur.setRadius(radius);
        // Start the ScriptIntrinisicBlur
        scriptIntrinsicBlur.forEach(output);
        // Copy the output to the blurred bitmap
        output.copyTo(inputBmp);
        renderScript.destroy();
        return inputBmp;
    }
  • So far we have finished half of the work. If we set the processed image directly as the background and switch it from the original background to the new background in an instant, it will create a visual sense of abruptness. So we need to add transitional animation between the two. Android provides Transition Drawable to do this. When the latest background image is obtained, the following method is implemented to achieve background transition. mBgView is the background View. Transition Drawable can set up a Drawable array to store the images we want to convert. Transition Drawable Start Transition will gradually change from the images in the array.
    Get the background of the end of the View where the last focus was located as the starting background of the View where the current focus was located, and the blurred image as the ending background.
private void updateMainBg(Drawable drawable) {
        if (drawable == null) {
            return;
        }
        Drawable oldDrawable;
        //When the background is not set for the first time, current BgDrawable = null
        Drawable currentBgDrawable = mBgView.getDrawable();
        if (currentBgDrawable instanceof TransitionDrawable) {
            oldDrawable = ((TransitionDrawable) currentBgDrawable).getDrawable(1);
            mTransitionDrawable.setDrawable(0, oldDrawable);
            mTransitionDrawable.setDrawable(1, drawable);
        } else {
            //Setting Background for the First Time
            oldDrawable = getDrawable(R.drawable.launcher_bg_new);
            mTransitionDrawable = new TransitionDrawable(new Drawable[]{oldDrawable, drawable});
            mTransitionDrawable.setCrossFadeEnabled(true);
            mBgView.setImageDrawable(mTransitionDrawable);
        }
        mTransitionDrawable.startTransition(500);//Conversion time
        focusView.destroyDrawingCache();
        focusView.setDrawingCacheEnabled(false);
    }

handler code section

private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case MSG_BLUR_BG:
                    blurCurFocusImage((View) msg.obj);
                    break;
                case MSG_UPDATE_BG:
                    updateMainBg((Drawable) msg.obj);
                    break;
            }

        }
    };

Posted by amitshetye on Fri, 17 May 2019 13:13:27 -0700