123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607 |
- package com.kongzue.dialogx.style.views;
- import android.app.Activity;
- import android.content.Context;
- import android.content.ContextWrapper;
- import android.content.res.TypedArray;
- import android.graphics.Bitmap;
- import android.graphics.BitmapShader;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Matrix;
- import android.graphics.Outline;
- import android.graphics.Paint;
- import android.graphics.Rect;
- import android.graphics.RectF;
- import android.graphics.Shader;
- import android.os.Build;
- import android.renderscript.Allocation;
- import android.renderscript.Element;
- import android.renderscript.RenderScript;
- import android.renderscript.ScriptIntrinsicBlur;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.View;
- import android.view.ViewGroup;
- import android.view.ViewOutlineProvider;
- import android.view.ViewTreeObserver;
- import android.widget.LinearLayout;
- import com.kongzue.dialogx.DialogX;
- import com.kongzue.dialogx.interfaces.BaseDialog;
- import com.kongzue.dialogx.interfaces.BlurViewType;
- import com.kongzue.dialogx.iostheme.R;
- import com.kongzue.dialogx.util.views.MaxLinearLayout;
- public class BlurLinearLayout extends MaxLinearLayout implements BlurViewType {
- private float mDownSampleFactor = 4;
- private int mOverlayColor = Color.WHITE;
- private float mBlurRadius = 35;
- private boolean noAlpha = false;
- private boolean overrideOverlayColor = false;
- private float mRadius = 0;
- private boolean mDirty;
- private Bitmap mBitmapToBlur, mBlurredBitmap;
- private Canvas mBlurringCanvas;
- private RenderScript mRenderScript;
- private ScriptIntrinsicBlur mBlurScript;
- private Allocation mBlurInput, mBlurOutput;
- private boolean mIsRendering;
- private final Rect mRectSrc = new Rect(), mRectDst = new Rect();
- private View mDecorView;
- private boolean mDifferentRoot;
- private static int RENDERING_COUNT;
- private Paint mPaint;
- private RectF mRectF;
- public BlurLinearLayout(Context context) {
- super(context);
- init(context, null);
- }
- public BlurLinearLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(context, attrs);
- }
- public BlurLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init(context, attrs);
- }
- private boolean isInit = false;
- private boolean darkMode = false;
- Paint cutPaint;
- Paint overlayPaint;
- private void init(Context context, AttributeSet attrs) {
- if (!isInit && context != null) {
- TypedArray a = context.obtainStyledAttributes(attrs, com.kongzue.dialogx.R.styleable.RealtimeBlurView);
- darkMode = a.getBoolean(com.kongzue.dialogx.R.styleable.RealtimeBlurView_dialogxDarkMode, false);
- mBlurRadius = a.getDimension(com.kongzue.dialogx.R.styleable.RealtimeBlurView_realtimeBlurRadius, dip2px(context, 35));
- mDownSampleFactor = a.getFloat(com.kongzue.dialogx.R.styleable.RealtimeBlurView_realtimeDownsampleFactor, 4);
- mOverlayColor = a.getColor(com.kongzue.dialogx.R.styleable.RealtimeBlurView_realtimeOverlayColor, getResources().getColor(darkMode ? R.color.dialogxIOSBkgDark : R.color.dialogxIOSBkgLight));
- mRadius = a.getDimension(com.kongzue.dialogx.R.styleable.RealtimeBlurView_realtimeRadius, dip2px(context, 15));
- noAlpha = a.getBoolean(com.kongzue.dialogx.R.styleable.RealtimeBlurView_dialogxOverlayColorNoAlpha, false);
- a.recycle();
- mPaint = new Paint();
- mPaint.setAntiAlias(true);
- mRectF = new RectF();
- cutPaint = new Paint();
- cutPaint.setAntiAlias(true);
- cutPaint.setColor(getOverlayColor());
- overlayPaint = new Paint();
- overlayPaint.setAntiAlias(true);
- isInit = true;
- if (!isCompatMode()) {
- setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mRadius);
- }
- });
- setClipToOutline(true);
- }
- }
- }
- private boolean isCompatMode() {
- return Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP;
- }
- public void setBlurRadius(float radius) {
- if (mBlurRadius != radius) {
- mBlurRadius = radius;
- mDirty = true;
- invalidate();
- }
- }
- public void setRadiusPx(float r) {
- if (mRadius != r) {
- mRadius = r;
- mDirty = true;
- invalidate();
- if (!isCompatMode()) {
- setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mRadius);
- }
- });
- setClipToOutline(true);
- }
- }
- }
- @Override
- public void setRadiusPx(Float r) {
- if (r != null) {
- setRadiusPx((float) r);
- }
- }
- public void setDownsampleFactor(float factor) {
- if (factor <= 0) {
- throw new IllegalArgumentException("Downsample factor must be greater than 0.");
- }
- if (mDownSampleFactor != factor) {
- mDownSampleFactor = factor;
- mDirty = true; // may also change blur radius
- releaseBitmap();
- invalidate();
- }
- }
- public void setOverlayColor(int color) {
- if (mOverlayColor != color) {
- mOverlayColor = color;
- invalidate();
- }
- }
- @Override
- public void setOverlayColor(Integer color) {
- if (color != null) {
- setOverlayColor((int) color);
- }
- }
- private void releaseBitmap() {
- if (mBlurInput != null) {
- mBlurInput.destroy();
- mBlurInput = null;
- }
- if (mBlurOutput != null) {
- mBlurOutput.destroy();
- mBlurOutput = null;
- }
- if (mBitmapToBlur != null) {
- mBitmapToBlur.recycle();
- mBitmapToBlur = null;
- }
- if (mBlurredBitmap != null) {
- mBlurredBitmap.recycle();
- mBlurredBitmap = null;
- }
- }
- private void releaseScript() {
- if (mRenderScript != null) {
- mRenderScript.destroy();
- mRenderScript = null;
- }
- if (mBlurScript != null) {
- mBlurScript.destroy();
- mBlurScript = null;
- }
- }
- protected void release() {
- releaseBitmap();
- releaseScript();
- }
- protected boolean prepare() {
- if (mBlurRadius == 0 || !isAlive()) {
- release();
- return false;
- }
- float downsampleFactor = mDownSampleFactor;
- if (mDirty || mRenderScript == null) {
- if (supportRenderScript && useBlur) {
- if (mRenderScript == null) {
- try {
- mRenderScript = RenderScript.create(getContext());
- mBlurScript = ScriptIntrinsicBlur.create(mRenderScript, Element.U8_4(mRenderScript));
- } catch (Exception e) {
- supportRenderScript = false;
- if (isDebug()) {
- e.printStackTrace();
- }
- return false;
- }
- }
- mDirty = false;
- float radius = mBlurRadius / downsampleFactor;
- if (radius > 25) {
- downsampleFactor = downsampleFactor * radius / 25;
- radius = 25;
- }
- if (mBlurScript != null) mBlurScript.setRadius(radius);
- }
- }
- final int width = getWidth();
- final int height = getHeight();
- int scaledWidth = Math.max(1, (int) (width / downsampleFactor));
- int scaledHeight = Math.max(1, (int) (height / downsampleFactor));
- if (mBlurringCanvas == null || mBlurredBitmap == null || mBlurredBitmap.getWidth() != scaledWidth || mBlurredBitmap.getHeight() != scaledHeight) {
- releaseBitmap();
- boolean r = false;
- try {
- mBitmapToBlur = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
- if (mBitmapToBlur == null) {
- return false;
- }
- mBlurringCanvas = new Canvas(mBitmapToBlur);
- if (!supportRenderScript || !useBlur) {
- return true;
- }
- mBlurInput = Allocation.createFromBitmap(mRenderScript, mBitmapToBlur,
- Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT
- );
- mBlurOutput = Allocation.createTyped(mRenderScript, mBlurInput.getType());
- mBlurredBitmap = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
- if (mBlurredBitmap == null) {
- return false;
- }
- r = true;
- } catch (Exception e) {
- if (isDebug()) e.printStackTrace();
- } finally {
- if (!r) {
- releaseBitmap();
- return false;
- }
- }
- }
- return true;
- }
- private boolean isAlive() {
- Context context = getContext();
- if (context instanceof Activity) {
- return isAttachedToWindow() && !(((Activity) context).isDestroyed());
- }
- while (context instanceof ContextWrapper) {
- if (context instanceof Activity) {
- return isAttachedToWindow() && !(((Activity) context).isDestroyed());
- }
- context = ((ContextWrapper) context).getBaseContext();
- }
- return isAttachedToWindow() && getContext() != null;
- }
- protected void blur(Bitmap bitmapToBlur, Bitmap blurredBitmap) {
- mBlurInput.copyFrom(bitmapToBlur);
- mBlurScript.setInput(mBlurInput);
- mBlurScript.forEach(mBlurOutput);
- mBlurOutput.copyTo(blurredBitmap);
- }
- private final ViewTreeObserver.OnPreDrawListener preDrawListener = new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- if (!isAlive()) {
- destroy();
- return false;
- }
- final int[] locations = new int[2];
- Bitmap oldBmp = mBlurredBitmap;
- View decor = mDecorView;
- if (decor != null && isShown() && prepare()) {
- boolean redrawBitmap = mBlurredBitmap != oldBmp;
- decor.getLocationOnScreen(locations);
- int x = -locations[0];
- int y = -locations[1];
- getLocationOnScreen(locations);
- x += locations[0];
- y += locations[1];
- // just erase transparent
- mBitmapToBlur.eraseColor(getOverlayColor() & 0xffffff);
- int rc = mBlurringCanvas.save();
- mIsRendering = true;
- RENDERING_COUNT++;
- try {
- mBlurringCanvas.scale(1.f * mBitmapToBlur.getWidth() / getWidth(), 1.f * mBitmapToBlur.getHeight() / getHeight());
- mBlurringCanvas.translate(-x, -y);
- if (decor.getBackground() != null) {
- decor.getBackground().draw(mBlurringCanvas);
- }
- decor.draw(mBlurringCanvas);
- } catch (Exception e) {
- if (isDebug()) e.printStackTrace();
- } finally {
- mIsRendering = false;
- RENDERING_COUNT--;
- mBlurringCanvas.restoreToCount(rc);
- }
- try {
- blur(mBitmapToBlur, mBlurredBitmap);
- } catch (Exception e) {
- if (isDebug()) e.printStackTrace();
- }
- if (redrawBitmap || mDifferentRoot) {
- invalidate();
- }
- }
- return true;
- }
- };
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- Activity activity;
- if (getContext() instanceof Activity) {
- activity = (Activity) getContext();
- } else {
- activity = BaseDialog.getTopActivity();
- }
- ViewGroup decorView = ((ViewGroup) activity.getWindow().getDecorView());
- if (decorView.getChildCount() >= 1) {
- mDecorView = decorView.getChildAt(0);
- }
- if (mDecorView != null) {
- log("mDecorView is ok.");
- mDecorView.getViewTreeObserver().addOnPreDrawListener(preDrawListener);
- mDifferentRoot = mDecorView.getRootView() != getRootView();
- if (mDifferentRoot) {
- mDecorView.postInvalidate();
- }
- } else {
- log("mDecorView is NULL.");
- mDifferentRoot = false;
- }
- }
- @Override
- protected void onDetachedFromWindow() {
- destroy();
- super.onDetachedFromWindow();
- }
- private void destroy() {
- if (mDecorView != null) {
- mDecorView.getViewTreeObserver().removeOnPreDrawListener(preDrawListener);
- }
- release();
- }
- @Override
- protected void dispatchDraw(Canvas canvas) {
- if (isCompatMode()) {
- drawBlurredBitmapCompat(canvas);
- } else {
- drawBlurredBitmap(canvas, mBlurredBitmap);
- }
- super.dispatchDraw(canvas);
- }
- @Override
- public void draw(Canvas canvas) {
- log("#draw");
- if (!useBlur || !supportRenderScript) {
- mRectF.right = getWidth();
- mRectF.bottom = getHeight();
- overlayPaint.setColor(getOverlayColor());
- canvas.drawRoundRect(mRectF, mRadius, mRadius, overlayPaint);
- } else {
- if (!mIsRendering && RENDERING_COUNT <= 0) {
- log("draw: ok");
- super.draw(canvas);
- }
- }
- }
- @Override
- protected void onDraw(Canvas canvas) {
- if (isCompatMode()) {
- drawBlurredBitmapCompat(canvas);
- } else {
- drawBlurredBitmap(canvas, mBlurredBitmap);
- }
- super.onDraw(canvas);
- }
- private void drawBlurredBitmapCompat(Canvas canvas) {
- if (getWidth() <= 0 || getHeight() <= 0) return;
- if (mBlurredBitmap != null) {
- mRectDst.right = getWidth();
- mRectDst.bottom = getHeight();
- if (getWidth() > 0 && getHeight() > 0) {
- Bitmap readyDrawBitmap = getRoundedCornerBitmap(resizeImage(mBlurredBitmap, getWidth(), getHeight()), mRectDst);
- if (readyDrawBitmap != null) {
- canvas.drawBitmap(readyDrawBitmap, 0, 0, null);
- } else {
- Bitmap overlyBitmap = drawOverlyColor(Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888));
- if (overlyBitmap != null) canvas.drawBitmap(overlyBitmap, 0, 0, null);
- }
- }
- } else {
- Bitmap overlyBitmap = drawOverlyColor(Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888));
- if (overlyBitmap != null) canvas.drawBitmap(overlyBitmap, 0, 0, null);
- }
- }
- protected void drawBlurredBitmap(Canvas canvas, Bitmap blurredBitmap) {
- if (getWidth() <= 0 || getHeight() <= 0) return;
- if (blurredBitmap != null) {
- mRectSrc.right = blurredBitmap.getWidth();
- mRectSrc.bottom = blurredBitmap.getHeight();
- mRectDst.right = getWidth();
- mRectDst.bottom = getHeight();
- canvas.drawBitmap(blurredBitmap, mRectSrc, mRectDst, null);
- canvas.drawColor(getOverlayColor());
- } else {
- Bitmap overlyBitmap = drawOverlyColor(Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888));
- if (overlyBitmap != null) canvas.drawBitmap(overlyBitmap, 0, 0, null);
- }
- }
- private Bitmap getRoundedCornerBitmap(Bitmap bitmap, Rect mRectDst) {
- bitmap = drawOverlyColor(resizeImage(bitmap, mRectDst.width(), mRectDst.height()));
- if (bitmap == null) return null;
- Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(output);
- BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
- Paint paint = new Paint();
- paint.setAntiAlias(true);
- paint.setShader(bitmapShader);
- canvas.drawRoundRect(new RectF(mRectDst), mRadius, mRadius, paint);
- return output;
- }
- private Bitmap drawOverlyColor(Bitmap bitmap) {
- if (bitmap != null) {
- Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(output);
- Rect originRect = new Rect();
- originRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
- canvas.drawBitmap(bitmap, originRect, originRect, overlayPaint);
- canvas.drawColor(getOverlayColor());
- return output;
- } else {
- return null;
- }
- }
- private Bitmap resizeImage(Bitmap bitmap, int newWidth, int newHeight) {
- if (bitmap != null) {
- int width = bitmap.getWidth();
- int height = bitmap.getHeight();
- float scaleWidth = ((float) newWidth) / width;
- float scaleHeight = ((float) newHeight) / height;
- Matrix matrix = new Matrix();
- matrix.postScale(scaleWidth, scaleHeight);
- return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
- } else {
- return null;
- }
- }
- private static boolean supportRenderScript = false;
- private boolean useBlur = true;
- public boolean isUseBlur() {
- return useBlur;
- }
- public BlurLinearLayout setUseBlur(boolean useBlur) {
- this.useBlur = useBlur;
- invalidate();
- return this;
- }
- private boolean needRemoveAlphaColor() {
- if (overrideOverlayColor) {
- return false;
- } else {
- return noAlpha || !(supportRenderScript && useBlur);
- }
- }
- private static int removeAlphaColor(int color) {
- int alpha = 255;
- int red = Color.red(color);
- int green = Color.green(color);
- int blue = Color.blue(color);
- return Color.argb(alpha, red, green, blue);
- }
- private static int replaceAlphaColor(int color, int alpha) {
- int red = Color.red(color);
- int green = Color.green(color);
- int blue = Color.blue(color);
- return Color.argb(alpha, red, green, blue);
- }
- static {
- /**
- * 之所以需要启动一个新线程检测RenderScript是否可用的原因是不清楚Android什么时候对loadClass做了变更,
- * 会直接抛出NoClassDefFoundError无法拦截,在主线程检测会导致程序直接闪退,因此改为异步检测。
- * 检测后会给定(boolean)supportRenderScript用于判断时光支持
- */
- new Thread() {
- @Override
- public void run() {
- try {
- BlurLinearLayout.class.getClassLoader().loadClass(RenderScript.class.getCanonicalName());
- supportRenderScript = true;
- } catch (Throwable e) {
- if (isDebug()) {
- e.printStackTrace();
- }
- supportRenderScript = false;
- }
- }
- }.start();
- }
- public static boolean DEBUGMODE = false;
- static boolean isDebug() {
- return DEBUGMODE && DialogX.DEBUGMODE;
- }
- private static void log(Object o) {
- if (isDebug()) Log.i(">>>", "DialogX.BlurView: " + o.toString());
- }
- public static void error(Object o) {
- if (isDebug()) Log.e(">>>", o.toString());
- }
- public BlurLinearLayout setOverrideOverlayColor(boolean overrideOverlayColor) {
- log("setOverrideOverlayColor: " + overrideOverlayColor);
- this.overrideOverlayColor = overrideOverlayColor;
- return this;
- }
- private int dip2px(Context context, float dpValue) {
- final float scale = context.getResources().getDisplayMetrics().density;
- return (int) (dpValue * scale + 0.5f);
- }
- private int getOverlayColor() {
- return needRemoveAlphaColor() ? removeAlphaColor(mOverlayColor) : mOverlayColor;
- }
- }
|