diff --git a/.gitignore b/.gitignore index c9c2248..fbb8a3b 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,7 @@ proguard/ # Android Studio captures folder captures/ +.idea/*.* +.idea/* +/*/build +/*/*.iml \ No newline at end of file diff --git a/Material-BottomNavigation.iml b/Material-BottomNavigation.iml new file mode 100644 index 0000000..f90cb48 --- /dev/null +++ b/Material-BottomNavigation.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index b827805..ff1d2cf 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,11 @@ # Material Bottom Navigation Library - +[ ![Download](https://api.bintray.com/packages/jjhesk/maven/bottom-navigation/images/download.svg) ](https://bintray.com/jjhesk/maven/bottom-navigation/_latestVersion) [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-MaterialBottomNavigation-green.svg?style=true)](https://android-arsenal.com/details/1/3414) -[![Build Status](https://travis-ci.org/sephiroth74/Material-BottomNavigation.svg?branch=master)](https://travis-ci.org/sephiroth74/Material-BottomNavigation) +[![Build Status](https://travis-ci.org/jjhesk/Material-BottomNavigation.svg?branch=master)](https://travis-ci.org/jjhesk/Material-BottomNavigation)
-[![Maven Central](https://maven-badges.herokuapp.com/maven-central/it.sephiroth.android.library.bottomnavigation/bottom-navigation/badge.svg)](https://maven-badges.herokuapp.com/maven-central/it.sephiroth.android.library.bottomnavigation/bottom-navigation) - Lightweight Bottom Navigation library component inspired by the Google Material Design Guidelines at https://www.google.com/design/spec/components/bottom-navigation.html - This project is also inspired by https://github.com/roughike/BottomBar - Table of contents ================= @@ -29,9 +25,9 @@ Installation ================= In your project's `build.gradle` file add the following line to the `dependencies` group: - - compile 'it.sephiroth.android.library.bottomnavigation:bottom-navigation:1.0.7' - +``` +compile 'com.hkm.ui:bottom-navigation:1.0.11' +``` Usage ================= diff --git a/app/app.iml b/app/app.iml new file mode 100644 index 0000000..ea71587 --- /dev/null +++ b/app/app.iml @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index e1b335a..db122bc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,6 +11,10 @@ android { versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + + renderscriptTargetApi ANDROID_BUILD_TARGET_SDK_VERSION as int + renderscriptSupportModeEnabled true + } buildTypes { release { @@ -18,6 +22,7 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + lintOptions { disable "AppLinksAutoVerifyError", "AppLinksAutoVerifyWarning", "AllowBackup", "IconMissingDensityFolder", "GoogleAppIndexingWarning", "SetTextI18n", "HardcodedText" @@ -29,14 +34,16 @@ android { } } + + dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:24.0.0' - compile 'com.android.support:design:24.0.0' - compile 'com.android.support:cardview-v7:24.0.0' - compile 'com.android.support:gridlayout-v7:24.0.0' - compile 'com.android.support:palette-v7:24.0.0' - compile 'com.android.support:recyclerview-v7:24.0.0' + compile 'com.android.support:appcompat-v7:24.2.1' + compile 'com.android.support:design:24.2.1' + compile 'com.android.support:cardview-v7:24.2.1' + compile 'com.android.support:gridlayout-v7:24.2.1' + compile 'com.android.support:palette-v7:24.2.1' + compile 'com.android.support:recyclerview-v7:24.2.1' compile 'com.squareup.picasso:picasso:2.5.2' @@ -48,8 +55,8 @@ dependencies { - androidTestCompile 'com.android.support:recyclerview-v7:24.0.0' - androidTestCompile 'com.android.support:support-annotations:24.0.0' + androidTestCompile 'com.android.support:recyclerview-v7:24.2.1' + androidTestCompile 'com.android.support:support-annotations:24.2.1' androidTestCompile 'com.android.support.test:rules:0.5' androidTestCompile 'com.android.support.test:runner:0.5' androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2' @@ -57,6 +64,7 @@ dependencies { androidTestCompile('com.android.support.test.espresso:espresso-contrib:2.2.2') { exclude module: 'recyclerview-v7' exclude module: 'appcompat-v7' + exclude module: 'support-v4' exclude module: 'design' } @@ -64,7 +72,7 @@ dependencies { configurations.all { resolutionStrategy { - forcedModules = ['com.android.support:support-annotations:23.0.1'] + forcedModules = ['com.android.support:support-annotations:24.2.1'] } } diff --git a/app/src/main/java/it/sephiroth/android/library/bottomnavigation/app/BaseActivity.java b/app/src/main/java/it/sephiroth/android/library/bottomnavigation/app/BaseActivity.java index da7bf6b..7ec7315 100644 --- a/app/src/main/java/it/sephiroth/android/library/bottomnavigation/app/BaseActivity.java +++ b/app/src/main/java/it/sephiroth/android/library/bottomnavigation/app/BaseActivity.java @@ -3,12 +3,15 @@ import android.annotation.TargetApi; import android.graphics.Typeface; import android.os.Build; +import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; +import android.view.View; import android.view.WindowManager; import com.readystatesoftware.systembartint.SystemBarTintManager; import it.sephiroth.android.library.bottomnavigation.BottomNavigation; +import it.sephiroth.android.library.bottomnavigation.app.blury.RealtimeBlurView; /** * Created by crugnola on 4/11/16. @@ -30,6 +33,10 @@ public void onContentChanged() { mBottomNavigation.setOnMenuItemClickListener(this); mBottomNavigation.setDefaultTypeface(typeface); + RealtimeBlurView view = new RealtimeBlurView(this); + view.setOverlayColor(ContextCompat.getColor(getApplicationContext(), R.color.colorWhiteBlur)); + view.setBlurRadius(15f); + mBottomNavigation.overrideBackgroundLayoutAnimation(view); } } @@ -48,13 +55,13 @@ public int getStatusBarHeight() { return getSystemBarTint().getConfig().getStatusBarHeight(); } - @TargetApi (19) + @TargetApi(19) public boolean hasTranslucentStatusBar() { if (!mTranslucentStatusSet) { if (Build.VERSION.SDK_INT >= 19) { mTranslucentStatus = - ((getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) - == WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + ((getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) + == WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); } else { mTranslucentStatus = false; } @@ -63,17 +70,17 @@ public boolean hasTranslucentStatusBar() { return mTranslucentStatus; } - @TargetApi (19) + @TargetApi(19) public boolean hasTranslucentNavigation() { if (!mTranslucentNavigationSet) { final SystemBarTintManager.SystemBarConfig config = getSystemBarTint().getConfig(); if (Build.VERSION.SDK_INT >= 19) { boolean themeConfig = - ((getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) - == WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); + ((getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) + == WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); mTranslucentNavigation = themeConfig && config.hasNavigtionBar() && config.isNavigationAtBottom() - && config.getNavigationBarHeight() > 0; + && config.getNavigationBarHeight() > 0; } mTranslucentNavigationSet = true; } diff --git a/app/src/main/java/it/sephiroth/android/library/bottomnavigation/app/blury/RealtimeBlurView.java b/app/src/main/java/it/sephiroth/android/library/bottomnavigation/app/blury/RealtimeBlurView.java new file mode 100644 index 0000000..a4565f1 --- /dev/null +++ b/app/src/main/java/it/sephiroth/android/library/bottomnavigation/app/blury/RealtimeBlurView.java @@ -0,0 +1,316 @@ +package it.sephiroth.android.library.bottomnavigation.app.blury; + +import android.app.Activity; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Rect; +import android.graphics.drawable.ColorDrawable; +import android.support.v4.content.ContextCompat; +import android.support.v8.renderscript.Allocation; +import android.support.v8.renderscript.Element; +import android.support.v8.renderscript.RenderScript; +import android.support.v8.renderscript.ScriptIntrinsicBlur; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewTreeObserver; + +import it.sephiroth.android.library.bottomnavigation.app.R; + + +/** + * A realtime blurring overlay (like iOS UIVisualEffectView). Just put it above + * the view you want to blur and it doesn't have to be in the same ViewGroup + * + */ +public class RealtimeBlurView extends View { + + private float mDownsampleFactor; // default 4 + private int mOverlayColor; // default #aaffffff + private float mBlurRadius; // default 10dp (0 < r <= 25) + + 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 static int RENDERING_COUNT; + + public RealtimeBlurView(Context context, AttributeSet attrs) { + super(context, attrs); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RealtimeBlurView); + mBlurRadius = a.getDimension(R.styleable.RealtimeBlurView_realtimeBlurRadius, + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, context.getResources().getDisplayMetrics())); + mDownsampleFactor = a.getFloat(R.styleable.RealtimeBlurView_realtimeDownsampleFactor, 4); + mOverlayColor = a.getColor(R.styleable.RealtimeBlurView_realtimeOverlayColor, 0xAAFFFFFF); + a.recycle(); + } + + public RealtimeBlurView(Context context) { + super(context, null); + mOverlayColor = ContextCompat.getColor(context, R.color.cardview_light_background); + mDownsampleFactor = 4; + mBlurRadius = 10f; + } + + public void setBlurRadius(float radius) { + if (mBlurRadius != radius) { + mBlurRadius = radius; + mDirty = true; + invalidate(); + } + } + + 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(); + } + } + + 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) { + release(); + return false; + } + + float downsampleFactor = mDownsampleFactor; + + if (mDirty || mRenderScript == null) { + if (mRenderScript == null) { + try { + mRenderScript = RenderScript.create(getContext()); + mBlurScript = ScriptIntrinsicBlur.create(mRenderScript, Element.U8_4(mRenderScript)); + } catch (android.support.v8.renderscript.RSRuntimeException e) { + if (e.getMessage() != null && e.getMessage().startsWith("Error loading RS jni library: java.lang.UnsatisfiedLinkError:")) { + throw new RuntimeException("Error loading RS jni library, Upgrade buildToolsVersion=\"23.0.3\" or higher may solve this issue"); + } else { + throw e; + } + } + } + + mDirty = false; + float radius = mBlurRadius / downsampleFactor; + if (radius > 25) { + downsampleFactor = downsampleFactor * radius / 25; + radius = 25; + } + mBlurScript.setRadius(radius); + } + + final int width = getWidth(); + final int height = getHeight(); + + int scaledWidth = (int) (width / downsampleFactor); + int scaledHeight = (int) (height / downsampleFactor); + + if (mBlurringCanvas == null || mBlurredBitmap == null + || mBlurredBitmap.getWidth() != scaledWidth + || mBlurredBitmap.getHeight() != scaledHeight) { + releaseBitmap(); + + mBitmapToBlur = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888); + if (mBitmapToBlur == null) { + return false; + } + + mBlurredBitmap = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888); + if (mBlurredBitmap == null) { + return false; + } + + mBlurringCanvas = new Canvas(mBitmapToBlur); + mBlurInput = Allocation.createFromBitmap(mRenderScript, mBitmapToBlur, + Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT); + mBlurOutput = Allocation.createTyped(mRenderScript, mBlurInput.getType()); + } + return true; + } + + protected void blur() { + mBlurInput.copyFrom(mBitmapToBlur); + mBlurScript.setInput(mBlurInput); + mBlurScript.forEach(mBlurOutput); + mBlurOutput.copyTo(mBlurredBitmap); + } + + private final ViewTreeObserver.OnPreDrawListener preDrawListener = new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + final int[] locations = new int[2]; + if (isShown() && prepare()) { + Activity a = null; + Context ctx = getContext(); + while (true) { + if (ctx instanceof Activity) { + a = (Activity) ctx; + break; + } else if (ctx instanceof ContextWrapper) { + ctx = ((ContextWrapper) ctx).getBaseContext(); + } else { + break; + } + } + if (a == null) { + // Not in a activity + return true; + } + + View decor = a.getWindow().getDecorView(); + decor.getLocationInWindow(locations); + int x = -locations[0]; + int y = -locations[1]; + + getLocationInWindow(locations); + x += locations[0]; + y += locations[1]; + + if (decor.getBackground() instanceof ColorDrawable) { + mBitmapToBlur.eraseColor(((ColorDrawable) decor.getBackground()).getColor()); + } else { + mBitmapToBlur.eraseColor(Color.TRANSPARENT); + } + + int rc = mBlurringCanvas.save(); + mIsRendering = true; + RENDERING_COUNT++; + try { + mBlurringCanvas.scale(1.f * mBlurredBitmap.getWidth() / getWidth(), 1.f * mBlurredBitmap.getHeight() / getHeight()); + mBlurringCanvas.translate(-x, -y); + decor.draw(mBlurringCanvas); + } catch (StopException e) { + } finally { + mIsRendering = false; + RENDERING_COUNT--; + mBlurringCanvas.restoreToCount(rc); + } + + blur(); + } + + return true; + } + }; + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + getViewTreeObserver().addOnPreDrawListener(preDrawListener); + } + + @Override + protected void onDetachedFromWindow() { + getViewTreeObserver().removeOnPreDrawListener(preDrawListener); + release(); + super.onDetachedFromWindow(); + } + + @Override + public void draw(Canvas canvas) { + if (mIsRendering) { + // Quit here, don't draw views above me + throw STOP_EXCEPTION; + } else if (RENDERING_COUNT > 0) { + // Doesn't support blurview overlap on another blurview + } else { + super.draw(canvas); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + drawBlurredBitmap(canvas, mBlurredBitmap, mOverlayColor); + } + + /** + * Custom draw the blurred bitmap and color to define your own shape + * + * @param canvas + * @param blurredBitmap + * @param overlayColor + */ + protected void drawBlurredBitmap(Canvas canvas, Bitmap blurredBitmap, int overlayColor) { + 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(overlayColor); + } + + private static class StopException extends RuntimeException { + } + + private static StopException STOP_EXCEPTION = new StopException(); + + static { + try { + RealtimeBlurView.class.getClassLoader().loadClass("android.support.v8.renderscript.RenderScript"); + } catch (ClassNotFoundException e) { + throw new RuntimeException("RenderScript support not enabled. Add \"android { defaultConfig { renderscriptSupportModeEnabled true }}\" in your build.gradle"); + } + } +} \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index bfc57d7..17b5f64 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -4,4 +4,5 @@ #303F9F #FF4081 #991041 + #9b983357 diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 9f2fdb4..8a15016 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -21,4 +21,9 @@