Permalink
Please sign in to comment.
Showing
with
1,722 additions
and 0 deletions.
- +13 −0 .gitignore
- 0 README.md
- +1 −0 ahbottomnavigation/.gitignore
- +25 −0 ahbottomnavigation/build.gradle
- +17 −0 ahbottomnavigation/proguard-rules.pro
- +13 −0 ahbottomnavigation/src/androidTest/java/com/aurelhubert/ahbottomnavigation/ApplicationTest.java
- +12 −0 ahbottomnavigation/src/main/AndroidManifest.xml
- +665 −0 ahbottomnavigation/src/main/java/com/aurelhubert/ahbottomnavigation/AHBottomNavigation.java
- +66 −0 ahbottomnavigation/src/main/java/com/aurelhubert/ahbottomnavigation/AHBottomNavigationItem.java
- +185 −0 ahbottomnavigation/src/main/java/com/aurelhubert/ahbottomnavigation/AHHelper.java
- +34 −0 ahbottomnavigation/src/main/res/layout/bottom_navigation_item.xml
- +33 −0 ahbottomnavigation/src/main/res/layout/bottom_navigation_small_item.xml
- +10 −0 ahbottomnavigation/src/main/res/values/colors.xml
- +31 −0 ahbottomnavigation/src/main/res/values/dimens.xml
- +3 −0 ahbottomnavigation/src/main/res/values/strings.xml
- +15 −0 ahbottomnavigation/src/test/java/com/aurelhubert/ahbottomnavigation/ExampleUnitTest.java
- +1 −0 app/.gitignore
- +27 −0 app/build.gradle
- +17 −0 app/proguard-rules.pro
- +13 −0 app/src/androidTest/java/aurelhubert/com/ahbottomnavigation/ApplicationTest.java
- +22 −0 app/src/main/AndroidManifest.xml
- +74 −0 app/src/main/java/aurelhubert/com/ahbottomnavigation/HomeActivity.java
- BIN app/src/main/res/drawable-hdpi/ic_maps_local_attraction.png
- BIN app/src/main/res/drawable-hdpi/ic_maps_local_bar.png
- BIN app/src/main/res/drawable-hdpi/ic_maps_local_restaurant.png
- BIN app/src/main/res/drawable-hdpi/ic_maps_place.png
- BIN app/src/main/res/drawable-mdpi/ic_maps_local_attraction.png
- BIN app/src/main/res/drawable-mdpi/ic_maps_local_bar.png
- BIN app/src/main/res/drawable-mdpi/ic_maps_local_restaurant.png
- BIN app/src/main/res/drawable-mdpi/ic_maps_place.png
- BIN app/src/main/res/drawable-xhdpi/ic_maps_local_attraction.png
- BIN app/src/main/res/drawable-xhdpi/ic_maps_local_bar.png
- BIN app/src/main/res/drawable-xhdpi/ic_maps_local_restaurant.png
- BIN app/src/main/res/drawable-xhdpi/ic_maps_place.png
- BIN app/src/main/res/drawable-xxhdpi/ic_maps_local_attraction.png
- BIN app/src/main/res/drawable-xxhdpi/ic_maps_local_bar.png
- BIN app/src/main/res/drawable-xxhdpi/ic_maps_local_restaurant.png
- BIN app/src/main/res/drawable-xxhdpi/ic_maps_place.png
- BIN app/src/main/res/drawable-xxxhdpi/ic_maps_local_attraction.png
- BIN app/src/main/res/drawable-xxxhdpi/ic_maps_local_bar.png
- BIN app/src/main/res/drawable-xxxhdpi/ic_maps_local_restaurant.png
- BIN app/src/main/res/drawable-xxxhdpi/ic_maps_place.png
- +61 −0 app/src/main/res/layout/activity_home.xml
- BIN app/src/main/res/mipmap-hdpi/ic_launcher.png
- BIN app/src/main/res/mipmap-mdpi/ic_launcher.png
- BIN app/src/main/res/mipmap-xhdpi/ic_launcher.png
- BIN app/src/main/res/mipmap-xxhdpi/ic_launcher.png
- BIN app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
- +11 −0 app/src/main/res/values-v19/styles.xml
- +6 −0 app/src/main/res/values-w820dp/dimens.xml
- +9 −0 app/src/main/res/values/colors.xml
- +31 −0 app/src/main/res/values/dimens.xml
- +3 −0 app/src/main/res/values/strings.xml
- +11 −0 app/src/main/res/values/styles.xml
- +15 −0 app/src/test/java/aurelhubert/com/ahbottomnavigation/ExampleUnitTest.java
- +23 −0 build.gradle
- +18 −0 gradle.properties
- BIN gradle/wrapper/gradle-wrapper.jar
- +6 −0 gradle/wrapper/gradle-wrapper.properties
- +160 −0 gradlew
- +90 −0 gradlew.bat
- +1 −0 settings.gradle
13
.gitignore
@@ -0,0 +1,13 @@ | ||
+*.iml | ||
+.gradle | ||
+/local.properties | ||
+/.idea/workspace.xml | ||
+/.idea/libraries | ||
+.DS_Store | ||
+/build | ||
+/captures | ||
+ | ||
+gen | ||
+ | ||
+.idea | ||
+*.iml |
1
ahbottomnavigation/.gitignore
@@ -0,0 +1 @@ | ||
+/build |
25
ahbottomnavigation/build.gradle
@@ -0,0 +1,25 @@ | ||
+apply plugin: 'com.android.library' | ||
+ | ||
+android { | ||
+ compileSdkVersion 23 | ||
+ buildToolsVersion "23.0.2" | ||
+ | ||
+ defaultConfig { | ||
+ minSdkVersion 16 | ||
+ targetSdkVersion 23 | ||
+ versionCode 1 | ||
+ versionName "1.0" | ||
+ } | ||
+ buildTypes { | ||
+ release { | ||
+ minifyEnabled false | ||
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||
+ } | ||
+ } | ||
+} | ||
+ | ||
+dependencies { | ||
+ compile fileTree(dir: 'libs', include: ['*.jar']) | ||
+ testCompile 'junit:junit:4.12' | ||
+ compile 'com.android.support:appcompat-v7:23.2.1' | ||
+} |
17
ahbottomnavigation/proguard-rules.pro
@@ -0,0 +1,17 @@ | ||
+# Add project specific ProGuard rules here. | ||
+# By default, the flags in this file are appended to flags specified | ||
+# in /Users/aurelien/Library/Android/sdk/tools/proguard/proguard-android.txt | ||
+# You can edit the include path and order by changing the proguardFiles | ||
+# directive in build.gradle. | ||
+# | ||
+# For more details, see | ||
+# http://developer.android.com/guide/developing/tools/proguard.html | ||
+ | ||
+# Add any project specific keep options here: | ||
+ | ||
+# If your project uses WebView with JS, uncomment the following | ||
+# and specify the fully qualified class name to the JavaScript interface | ||
+# class: | ||
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
+# public *; | ||
+#} |
13
...omnavigation/src/androidTest/java/com/aurelhubert/ahbottomnavigation/ApplicationTest.java
@@ -0,0 +1,13 @@ | ||
+package com.aurelhubert.ahbottomnavigation; | ||
+ | ||
+import android.app.Application; | ||
+import android.test.ApplicationTestCase; | ||
+ | ||
+/** | ||
+ * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a> | ||
+ */ | ||
+public class ApplicationTest extends ApplicationTestCase<Application> { | ||
+ public ApplicationTest() { | ||
+ super(Application.class); | ||
+ } | ||
+} |
12
ahbottomnavigation/src/main/AndroidManifest.xml
@@ -0,0 +1,12 @@ | ||
+<manifest package="com.aurelhubert.ahbottomnavigation" | ||
+ xmlns:android="http://schemas.android.com/apk/res/android"> | ||
+ | ||
+ <application | ||
+ android:allowBackup="true" | ||
+ android:label="@string/app_name" | ||
+ android:supportsRtl="true" | ||
+ > | ||
+ | ||
+ </application> | ||
+ | ||
+</manifest> |
665
ahbottomnavigation/src/main/java/com/aurelhubert/ahbottomnavigation/AHBottomNavigation.java
@@ -0,0 +1,665 @@ | ||
+package com.aurelhubert.ahbottomnavigation; | ||
+ | ||
+import android.animation.Animator; | ||
+import android.content.Context; | ||
+import android.graphics.Color; | ||
+import android.os.Build; | ||
+import android.support.v4.content.ContextCompat; | ||
+import android.util.AttributeSet; | ||
+import android.util.Log; | ||
+import android.util.TypedValue; | ||
+import android.view.Gravity; | ||
+import android.view.LayoutInflater; | ||
+import android.view.View; | ||
+import android.view.ViewAnimationUtils; | ||
+import android.view.ViewGroup; | ||
+import android.widget.FrameLayout; | ||
+import android.widget.ImageView; | ||
+import android.widget.LinearLayout; | ||
+import android.widget.TextView; | ||
+ | ||
+import java.util.ArrayList; | ||
+ | ||
+/** | ||
+ * AHBottomNavigationLayout | ||
+ * Material Design guidelines : https://www.google.com/design/spec/components/bottom-navigation.html | ||
+ */ | ||
+public class AHBottomNavigation extends FrameLayout { | ||
+ | ||
+ // Static | ||
+ private static String TAG = "AHBottomNavigation"; | ||
+ private static final int MIN_ITEMS = 3; | ||
+ private static final int MAX_ITEMS = 5; | ||
+ | ||
+ // Listener | ||
+ private AHBottomNavigationListener listener; | ||
+ | ||
+ // Variables | ||
+ private Context context; | ||
+ private ArrayList<AHBottomNavigationItem> items = new ArrayList<>(); | ||
+ private ArrayList<View> views = new ArrayList<>(); | ||
+ private View backgroundColorView; | ||
+ private boolean colored = false; | ||
+ | ||
+ private int defaultBackgroundColor = Color.WHITE; | ||
+ private int accentColor = Color.WHITE; | ||
+ private int inactiveColor = Color.WHITE; | ||
+ | ||
+ private int currentItem = 0; | ||
+ private int currentColor = 0; | ||
+ private float selectedItemWidth, notSelectedItemWidth; | ||
+ | ||
+ | ||
+ /** | ||
+ * Constructor | ||
+ * | ||
+ * @param context | ||
+ */ | ||
+ public AHBottomNavigation(Context context) { | ||
+ super(context); | ||
+ this.context = context; | ||
+ initColors(); | ||
+ } | ||
+ | ||
+ public AHBottomNavigation(Context context, AttributeSet attrs) { | ||
+ super(context, attrs); | ||
+ this.context = context; | ||
+ initColors(); | ||
+ } | ||
+ | ||
+ public AHBottomNavigation(Context context, AttributeSet attrs, int defStyleAttr) { | ||
+ super(context, attrs, defStyleAttr); | ||
+ this.context = context; | ||
+ initColors(); | ||
+ } | ||
+ | ||
+ | ||
+ @Override | ||
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | ||
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec); | ||
+ initBottomNavigation(); | ||
+ } | ||
+ | ||
+ @Override | ||
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) { | ||
+ super.onSizeChanged(w, h, oldw, oldh); | ||
+ createItems(); | ||
+ } | ||
+ | ||
+ | ||
+ ///////////// | ||
+ // PRIVATE // | ||
+ ///////////// | ||
+ | ||
+ /** | ||
+ * Init the default colors | ||
+ */ | ||
+ private void initColors() { | ||
+ accentColor = ContextCompat.getColor(context, R.color.colorAccent); | ||
+ inactiveColor = ContextCompat.getColor(context, R.color.colorInactive); | ||
+ } | ||
+ | ||
+ /** | ||
+ * Init | ||
+ */ | ||
+ private void initBottomNavigation() { | ||
+ | ||
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { | ||
+ setElevation(context.getResources().getDimension(R.dimen.bottom_navigation_elevation)); | ||
+ setClipToPadding(false); | ||
+ } | ||
+ | ||
+ ViewGroup.LayoutParams params = getLayoutParams(); | ||
+ params.width = ViewGroup.LayoutParams.MATCH_PARENT; | ||
+ params.height = (int) context.getResources().getDimension(R.dimen.bottom_navigation_height); | ||
+ setLayoutParams(params); | ||
+ | ||
+ if (items.size() < MIN_ITEMS) { | ||
+ Log.w(TAG, "The items list should have at least 3 items"); | ||
+ } else if (items.size() > MAX_ITEMS) { | ||
+ Log.w(TAG, "The items list should not have more than 5 items"); | ||
+ } | ||
+ } | ||
+ | ||
+ /** | ||
+ * Create the items in the bottom navigation | ||
+ */ | ||
+ private void createItems() { | ||
+ | ||
+ currentItem = 0; | ||
+ removeAllViews(); | ||
+ views.clear(); | ||
+ | ||
+ backgroundColorView = new View(context); | ||
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && colored) { | ||
+ LayoutParams backgroundLayoutParams = new LayoutParams( | ||
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); | ||
+ addView(backgroundColorView, backgroundLayoutParams); | ||
+ } | ||
+ | ||
+ LinearLayout linearLayout = new LinearLayout(context); | ||
+ linearLayout.setOrientation(LinearLayout.HORIZONTAL); | ||
+ linearLayout.setGravity(Gravity.CENTER); | ||
+ | ||
+ int layoutHeight = (int) context.getResources().getDimension(R.dimen.bottom_navigation_height); | ||
+ LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, layoutHeight); | ||
+ addView(linearLayout, layoutParams); | ||
+ | ||
+ if (items.size() == MIN_ITEMS) { | ||
+ createClassicItems(linearLayout); | ||
+ } else { | ||
+ createSmallItems(linearLayout); | ||
+ } | ||
+ } | ||
+ | ||
+ /** | ||
+ * Create classic items (only 3 items in the bottom navigation) | ||
+ * | ||
+ * @param linearLayout The layout where the items are added | ||
+ */ | ||
+ private void createClassicItems(LinearLayout linearLayout) { | ||
+ | ||
+ LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); | ||
+ | ||
+ float height = context.getResources().getDimension(R.dimen.bottom_navigation_height); | ||
+ float minWidth = context.getResources().getDimension(R.dimen.bottom_navigation_min_width); | ||
+ float maxWidth = context.getResources().getDimension(R.dimen.bottom_navigation_max_width); | ||
+ | ||
+ int layoutWidth = getWidth(); | ||
+ if (layoutWidth == 0 || items.size() == 0) { | ||
+ return; | ||
+ } | ||
+ | ||
+ float itemWidth = layoutWidth / items.size(); | ||
+ if (itemWidth < minWidth) { | ||
+ itemWidth = minWidth; | ||
+ } else if (itemWidth > maxWidth) { | ||
+ itemWidth = maxWidth; | ||
+ } | ||
+ | ||
+ for (int i = 0; i < items.size(); i++) { | ||
+ | ||
+ final int itemIndex = i; | ||
+ AHBottomNavigationItem item = items.get(itemIndex); | ||
+ | ||
+ View view = inflater.inflate(R.layout.bottom_navigation_item, this, false); | ||
+ ImageView icon = (ImageView) view.findViewById(R.id.bottom_navigation_item_icon); | ||
+ TextView title = (TextView) view.findViewById(R.id.bottom_navigation_item_title); | ||
+ icon.setImageResource(item.getResource()); | ||
+ title.setText(item.getTitle()); | ||
+ | ||
+ if (i == currentItem) { | ||
+ int activePaddingTop = (int) context.getResources() | ||
+ .getDimension(R.dimen.bottom_navigation_padding_top_active); | ||
+ view.setPadding(view.getPaddingLeft(), activePaddingTop, view.getPaddingRight(), | ||
+ view.getPaddingBottom()); | ||
+ } | ||
+ | ||
+ if (colored) { | ||
+ if (i == currentItem) { | ||
+ setBackgroundColor(item.getColor()); | ||
+ currentColor = item.getColor(); | ||
+ } | ||
+ | ||
+ icon.setImageDrawable(AHHelper.getTintDrawable(context, items.get(i).getResource(), | ||
+ currentItem == i ? ContextCompat.getColor(context, R.color.colorActiveSmall) : | ||
+ ContextCompat.getColor(context, R.color.colorInactiveSmall))); | ||
+ title.setTextColor(currentItem == i ? | ||
+ ContextCompat.getColor(context, R.color.colorActiveSmall) : | ||
+ ContextCompat.getColor(context, R.color.colorInactiveSmall)); | ||
+ | ||
+ } else { | ||
+ setBackgroundColor(defaultBackgroundColor); | ||
+ icon.setImageDrawable(AHHelper.getTintDrawable(context, items.get(i).getResource(), | ||
+ currentItem == i ? accentColor : inactiveColor)); | ||
+ title.setTextColor(currentItem == i ? accentColor : | ||
+ ContextCompat.getColor(context, R.color.colorInactive)); | ||
+ } | ||
+ | ||
+ title.setTextSize(TypedValue.COMPLEX_UNIT_PX, currentItem == i ? | ||
+ context.getResources().getDimension(R.dimen.bottom_navigation_text_size_active) : | ||
+ context.getResources().getDimension(R.dimen.bottom_navigation_text_size_inactive)); | ||
+ | ||
+ view.setOnClickListener(new OnClickListener() { | ||
+ @Override | ||
+ public void onClick(View v) { | ||
+ updateItems(itemIndex); | ||
+ } | ||
+ }); | ||
+ | ||
+ LayoutParams params = new LayoutParams((int) itemWidth, (int) height); | ||
+ linearLayout.addView(view, params); | ||
+ views.add(view); | ||
+ } | ||
+ } | ||
+ | ||
+ /** | ||
+ * Create small items (more than 3 items in the bottom navigation) | ||
+ * | ||
+ * @param linearLayout The layout where the items are added | ||
+ */ | ||
+ private void createSmallItems(LinearLayout linearLayout) { | ||
+ | ||
+ LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); | ||
+ | ||
+ float height = context.getResources().getDimension(R.dimen.bottom_navigation_height); | ||
+ float minWidth = context.getResources().getDimension(R.dimen.bottom_navigation_small_inactive_min_width); | ||
+ float maxWidth = context.getResources().getDimension(R.dimen.bottom_navigation_small_inactive_max_width); | ||
+ | ||
+ int layoutWidth = getWidth(); | ||
+ if (layoutWidth == 0 || items.size() == 0) { | ||
+ return; | ||
+ } | ||
+ | ||
+ float itemWidth = layoutWidth / items.size(); | ||
+ | ||
+ if (itemWidth < minWidth) { | ||
+ itemWidth = minWidth; | ||
+ } else if (itemWidth > maxWidth) { | ||
+ itemWidth = maxWidth; | ||
+ } | ||
+ | ||
+ float difference = context.getResources().getDimension(R.dimen.bottom_navigation_small_selected_width_difference); | ||
+ selectedItemWidth = itemWidth + items.size() * difference; | ||
+ itemWidth -= difference; | ||
+ notSelectedItemWidth = itemWidth; | ||
+ | ||
+ for (int i = 0; i < items.size(); i++) { | ||
+ | ||
+ final int itemIndex = i; | ||
+ AHBottomNavigationItem item = items.get(itemIndex); | ||
+ | ||
+ View view = inflater.inflate(R.layout.bottom_navigation_small_item, this, false); | ||
+ ImageView icon = (ImageView) view.findViewById(R.id.bottom_navigation_small_item_icon); | ||
+ TextView title = (TextView) view.findViewById(R.id.bottom_navigation_small_item_title); | ||
+ icon.setImageResource(item.getResource()); | ||
+ title.setText(item.getTitle()); | ||
+ | ||
+ if (i == currentItem) { | ||
+ int activePaddingTop = (int) context.getResources() | ||
+ .getDimension(R.dimen.bottom_navigation_small_padding_top_active); | ||
+ int activePaddingBottom = (int) context.getResources() | ||
+ .getDimension(R.dimen.bottom_navigation_padding_bottom); | ||
+ view.setPadding(view.getPaddingLeft(), activePaddingTop, view.getPaddingRight(), | ||
+ activePaddingBottom); | ||
+ } | ||
+ | ||
+ if (colored) { | ||
+ if (i == currentItem) { | ||
+ setBackgroundColor(item.getColor()); | ||
+ currentColor = item.getColor(); | ||
+ } | ||
+ | ||
+ icon.setImageDrawable(AHHelper.getTintDrawable(context, items.get(i).getResource(), | ||
+ currentItem == i ? ContextCompat.getColor(context, R.color.colorActiveSmall) : | ||
+ ContextCompat.getColor(context, R.color.colorInactiveSmall))); | ||
+ title.setTextColor(currentItem == i ? | ||
+ ContextCompat.getColor(context, R.color.colorActiveSmall) : | ||
+ ContextCompat.getColor(context, R.color.colorInactiveSmall)); | ||
+ } else { | ||
+ | ||
+ setBackgroundColor(defaultBackgroundColor); | ||
+ | ||
+ Log.d(TAG, items.get(i).getTitle() + " / " + i + " / " + currentItem); | ||
+ icon.setImageDrawable(AHHelper.getTintDrawable(context, items.get(i).getResource(), | ||
+ currentItem == i ? accentColor : inactiveColor)); | ||
+ title.setTextColor(currentItem == i ? accentColor : inactiveColor); | ||
+ } | ||
+ | ||
+ title.setAlpha(currentItem == i ? 1 : 0); | ||
+ view.setOnClickListener(new OnClickListener() { | ||
+ @Override | ||
+ public void onClick(View v) { | ||
+ updateSmallItems(itemIndex); | ||
+ } | ||
+ }); | ||
+ | ||
+ LayoutParams params = new LayoutParams( | ||
+ i == currentItem ? (int) selectedItemWidth : (int) itemWidth, (int) height); | ||
+ linearLayout.addView(view, params); | ||
+ views.add(view); | ||
+ } | ||
+ } | ||
+ | ||
+ | ||
+ /** | ||
+ * Update Items UI | ||
+ */ | ||
+ private void updateItems(final int itemIndex) { | ||
+ | ||
+ if (currentItem == itemIndex) { | ||
+ return; | ||
+ } | ||
+ | ||
+ int activePaddingTop = (int) context.getResources().getDimension(R.dimen.bottom_navigation_padding_top_active); | ||
+ int inactivePaddingTop = (int) context.getResources().getDimension(R.dimen.bottom_navigation_padding_top_inactive); | ||
+ float activeSize = context.getResources().getDimension(R.dimen.bottom_navigation_text_size_active); | ||
+ float inactiveSize = context.getResources().getDimension(R.dimen.bottom_navigation_text_size_inactive); | ||
+ int itemActiveColor = colored ? ContextCompat.getColor(context, R.color.colorActiveSmall) : | ||
+ accentColor; | ||
+ int itemInactiveColor = colored ? ContextCompat.getColor(context, R.color.colorInactiveSmall) : | ||
+ inactiveColor; | ||
+ | ||
+ for (int i = 0; i < views.size(); i++) { | ||
+ | ||
+ if (i == itemIndex) { | ||
+ | ||
+ final View container = views.get(itemIndex).findViewById(R.id.bottom_navigation_container); | ||
+ final TextView title = (TextView) views.get(itemIndex).findViewById(R.id.bottom_navigation_item_title); | ||
+ final ImageView icon = (ImageView) views.get(itemIndex).findViewById(R.id.bottom_navigation_item_icon); | ||
+ | ||
+ AHHelper.updateTopPadding(container, inactivePaddingTop, activePaddingTop); | ||
+ AHHelper.updateTextColor(title, itemInactiveColor, itemActiveColor); | ||
+ AHHelper.updateTextSize(title, inactiveSize, activeSize); | ||
+ AHHelper.updateDrawableColor(context, items.get(itemIndex).getResource(), icon, | ||
+ itemInactiveColor, itemActiveColor); | ||
+ | ||
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && colored) { | ||
+ backgroundColorView.setBackgroundColor(items.get(itemIndex).getColor()); | ||
+ int finalRadius = Math.max(getWidth(), getHeight()); | ||
+ | ||
+ int cx = (int) views.get(itemIndex).getX() + views.get(itemIndex).getWidth() / 2; | ||
+ int cy = views.get(itemIndex).getHeight() / 2; | ||
+ Animator anim = ViewAnimationUtils.createCircularReveal(backgroundColorView, cx, cy, 0, finalRadius); | ||
+ anim.addListener(new Animator.AnimatorListener() { | ||
+ @Override | ||
+ public void onAnimationStart(Animator animation) { | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onAnimationEnd(Animator animation) { | ||
+ setBackgroundColor(items.get(itemIndex).getColor()); | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onAnimationCancel(Animator animation) { | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onAnimationRepeat(Animator animation) { | ||
+ } | ||
+ }); | ||
+ anim.start(); | ||
+ } else if (colored) { | ||
+ AHHelper.updateViewBackgroundColor(this, currentColor, | ||
+ items.get(itemIndex).getColor()); | ||
+ } else { | ||
+ setBackgroundColor(defaultBackgroundColor); | ||
+ } | ||
+ | ||
+ } else if (i == currentItem) { | ||
+ | ||
+ final View container = views.get(currentItem).findViewById(R.id.bottom_navigation_container); | ||
+ final TextView title = (TextView) views.get(currentItem).findViewById(R.id.bottom_navigation_item_title); | ||
+ final ImageView icon = (ImageView) views.get(currentItem).findViewById(R.id.bottom_navigation_item_icon); | ||
+ | ||
+ AHHelper.updateTopPadding(container, activePaddingTop, inactivePaddingTop); | ||
+ AHHelper.updateTextColor(title, itemActiveColor, itemInactiveColor); | ||
+ AHHelper.updateTextSize(title, activeSize, inactiveSize); | ||
+ AHHelper.updateDrawableColor(context, items.get(currentItem).getResource(), icon, | ||
+ itemActiveColor, itemInactiveColor); | ||
+ } | ||
+ } | ||
+ | ||
+ currentItem = itemIndex; | ||
+ currentColor = items.get(currentItem).getColor(); | ||
+ | ||
+ if (listener != null) { | ||
+ listener.onTabSelected(itemIndex); | ||
+ } | ||
+ } | ||
+ | ||
+ /** | ||
+ * Update Small items UI | ||
+ */ | ||
+ private void updateSmallItems(final int itemIndex) { | ||
+ | ||
+ if (currentItem == itemIndex) { | ||
+ return; | ||
+ } | ||
+ | ||
+ int activePaddingTop = (int) context.getResources().getDimension(R.dimen.bottom_navigation_small_padding_top_active); | ||
+ int inactivePadding = (int) context.getResources().getDimension(R.dimen.bottom_navigation_small_padding_top); | ||
+ int itemActiveColor = colored ? ContextCompat.getColor(context, R.color.colorActiveSmall) : | ||
+ accentColor; | ||
+ int itemInactiveColor = colored ? ContextCompat.getColor(context, R.color.colorInactiveSmall) : | ||
+ inactiveColor; | ||
+ | ||
+ for (int i = 0; i < views.size(); i++) { | ||
+ | ||
+ if (i == itemIndex) { | ||
+ | ||
+ final View container = views.get(itemIndex).findViewById(R.id.bottom_navigation_small_container); | ||
+ final TextView title = (TextView) views.get(itemIndex).findViewById(R.id.bottom_navigation_small_item_title); | ||
+ final ImageView icon = (ImageView) views.get(itemIndex).findViewById(R.id.bottom_navigation_small_item_icon); | ||
+ | ||
+ AHHelper.updateTopPadding(container, inactivePadding, activePaddingTop); | ||
+ AHHelper.updateTextColor(title, itemInactiveColor, itemActiveColor); | ||
+ AHHelper.updateAlpha(title, 0, 1); | ||
+ AHHelper.updateWidth(container, notSelectedItemWidth, selectedItemWidth); | ||
+ AHHelper.updateDrawableColor(context, items.get(itemIndex).getResource(), icon, | ||
+ itemInactiveColor, itemActiveColor); | ||
+ | ||
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && colored) { | ||
+ backgroundColorView.setBackgroundColor(items.get(itemIndex).getColor()); | ||
+ int finalRadius = Math.max(getWidth(), getHeight()); | ||
+ int cx = (int) views.get(itemIndex).getX() + views.get(itemIndex).getWidth() / 2; | ||
+ int cy = views.get(itemIndex).getHeight() / 2; | ||
+ Animator anim = ViewAnimationUtils.createCircularReveal(backgroundColorView, cx, cy, 0, finalRadius); | ||
+ anim.addListener(new Animator.AnimatorListener() { | ||
+ @Override | ||
+ public void onAnimationStart(Animator animation) { | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onAnimationEnd(Animator animation) { | ||
+ setBackgroundColor(items.get(itemIndex).getColor()); | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onAnimationCancel(Animator animation) { | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onAnimationRepeat(Animator animation) { | ||
+ } | ||
+ }); | ||
+ anim.start(); | ||
+ } else if (colored) { | ||
+ AHHelper.updateViewBackgroundColor(this, currentColor, | ||
+ items.get(itemIndex).getColor()); | ||
+ } else { | ||
+ setBackgroundColor(defaultBackgroundColor); | ||
+ } | ||
+ | ||
+ } else if (i == currentItem) { | ||
+ | ||
+ final View container = views.get(currentItem).findViewById(R.id.bottom_navigation_small_container); | ||
+ final TextView title = (TextView) views.get(currentItem).findViewById(R.id.bottom_navigation_small_item_title); | ||
+ final ImageView icon = (ImageView) views.get(currentItem).findViewById(R.id.bottom_navigation_small_item_icon); | ||
+ | ||
+ AHHelper.updateTopPadding(container, activePaddingTop, inactivePadding); | ||
+ AHHelper.updateTextColor(title, itemActiveColor, itemInactiveColor); | ||
+ AHHelper.updateAlpha(title, 1, 0); | ||
+ AHHelper.updateWidth(container, selectedItemWidth, notSelectedItemWidth); | ||
+ AHHelper.updateDrawableColor(context, items.get(currentItem).getResource(), icon, | ||
+ itemActiveColor, itemInactiveColor); | ||
+ } | ||
+ } | ||
+ | ||
+ | ||
+ currentItem = itemIndex; | ||
+ currentColor = items.get(currentItem).getColor(); | ||
+ | ||
+ if (listener != null) { | ||
+ listener.onTabSelected(itemIndex); | ||
+ } | ||
+ } | ||
+ | ||
+ | ||
+ //////////// | ||
+ // PUBLIC // | ||
+ //////////// | ||
+ | ||
+ /** | ||
+ * Add an item | ||
+ */ | ||
+ public void addItem(AHBottomNavigationItem item) { | ||
+ if (this.items.size() >= MAX_ITEMS) { | ||
+ Log.w(TAG, "The items list should not have more than 5 items"); | ||
+ } | ||
+ items.add(item); | ||
+ createItems(); | ||
+ } | ||
+ | ||
+ /** | ||
+ * Add all items | ||
+ */ | ||
+ public void addItems(ArrayList<AHBottomNavigationItem> items) { | ||
+ if (items.size() >= MAX_ITEMS || (this.items.size() + items.size()) > MAX_ITEMS) { | ||
+ Log.w(TAG, "The items list should not have more than 5 items"); | ||
+ } | ||
+ this.items.addAll(items); | ||
+ createItems(); | ||
+ } | ||
+ | ||
+ /** | ||
+ * Remove an item at the given index | ||
+ */ | ||
+ public void removeItemAtIndex(int index) { | ||
+ if (index < items.size()) { | ||
+ this.items.remove(index); | ||
+ createItems(); | ||
+ } | ||
+ } | ||
+ | ||
+ /** | ||
+ * Remove all items | ||
+ */ | ||
+ public void removeAllItems() { | ||
+ this.items.clear(); | ||
+ createItems(); | ||
+ } | ||
+ | ||
+ /** | ||
+ * Return if the Bottom Navigation is colored | ||
+ */ | ||
+ public boolean isColored() { | ||
+ return colored; | ||
+ } | ||
+ | ||
+ /** | ||
+ * Set if the Bottom Navigation is colored | ||
+ */ | ||
+ public void setColored(boolean colored) { | ||
+ this.colored = colored; | ||
+ createItems(); | ||
+ } | ||
+ | ||
+ | ||
+ /** | ||
+ * Set the GraphView listener | ||
+ */ | ||
+ public void setAHBottomNavigationListener(AHBottomNavigationListener listener) { | ||
+ this.listener = listener; | ||
+ } | ||
+ | ||
+ /** | ||
+ * Remove the GraphView listener | ||
+ */ | ||
+ public void removeAHBottomNavigationListener() { | ||
+ this.listener = null; | ||
+ } | ||
+ | ||
+ /** | ||
+ * Return the bottom navigation background color | ||
+ * | ||
+ * @return The bottom navigation background color | ||
+ */ | ||
+ public int getDefaultBackgroundColor() { | ||
+ return defaultBackgroundColor; | ||
+ } | ||
+ | ||
+ /** | ||
+ * Set the bottom navigation background color | ||
+ * | ||
+ * @param defaultBackgroundColor The bottom navigation background color | ||
+ */ | ||
+ public void setDefaultBackgroundColor(int defaultBackgroundColor) { | ||
+ this.defaultBackgroundColor = defaultBackgroundColor; | ||
+ } | ||
+ | ||
+ /** | ||
+ * Get the accent color (used when the view contains 3 items) | ||
+ * | ||
+ * @return The default accent color | ||
+ */ | ||
+ public int getAccentColor() { | ||
+ return accentColor; | ||
+ } | ||
+ | ||
+ /** | ||
+ * Set the accent color (used when the view contains 3 items) | ||
+ * | ||
+ * @param accentColor The new accent color | ||
+ */ | ||
+ public void setAccentColor(int accentColor) { | ||
+ this.accentColor = accentColor; | ||
+ } | ||
+ | ||
+ /** | ||
+ * Get the inactive color (used when the view contains 3 items) | ||
+ * | ||
+ * @return The inactive color | ||
+ */ | ||
+ public int getInactiveColor() { | ||
+ return inactiveColor; | ||
+ } | ||
+ | ||
+ /** | ||
+ * Set the inactive color (used when the view contains 3 items) | ||
+ * | ||
+ * @param inactiveColor The inactive color | ||
+ */ | ||
+ public void setInactiveColor(int inactiveColor) { | ||
+ this.inactiveColor = inactiveColor; | ||
+ } | ||
+ | ||
+ /** | ||
+ * Get the current item | ||
+ * | ||
+ * @return The current item position | ||
+ */ | ||
+ public int getCurrentItem() { | ||
+ return currentItem; | ||
+ } | ||
+ | ||
+ /** | ||
+ * Set the current item | ||
+ * | ||
+ * @param position The new position | ||
+ */ | ||
+ public void setCurrentItem(int position) { | ||
+ if (position >= items.size()) { | ||
+ Log.w(TAG, "The position is out of bounds of the items (" + items.size() + " elements)"); | ||
+ return; | ||
+ } | ||
+ if (items.size() == MIN_ITEMS) { | ||
+ updateItems(position); | ||
+ } else { | ||
+ updateSmallItems(position); | ||
+ } | ||
+ } | ||
+ | ||
+ //////////////// | ||
+ // INTERFACES // | ||
+ //////////////// | ||
+ | ||
+ /** | ||
+ * Interface for Bottom Navigation | ||
+ */ | ||
+ public interface AHBottomNavigationListener { | ||
+ void onTabSelected(int position); | ||
+ } | ||
+ | ||
+} |
66
...omnavigation/src/main/java/com/aurelhubert/ahbottomnavigation/AHBottomNavigationItem.java
@@ -0,0 +1,66 @@ | ||
+package com.aurelhubert.ahbottomnavigation; | ||
+ | ||
+import android.graphics.Color; | ||
+ | ||
+/** | ||
+ * AHBottomNavigationItem | ||
+ * The item is display in the AHBottomNavigation layout | ||
+ */ | ||
+public class AHBottomNavigationItem { | ||
+ | ||
+ private String title = ""; | ||
+ private int color = Color.GRAY; | ||
+ private int resource = 0; | ||
+ | ||
+ /** | ||
+ * Constructor | ||
+ */ | ||
+ public AHBottomNavigationItem() { | ||
+ } | ||
+ | ||
+ /** | ||
+ * Constructor | ||
+ * | ||
+ * @param title Title | ||
+ * @param resource Drawable resource | ||
+ */ | ||
+ public AHBottomNavigationItem(String title, int resource) { | ||
+ this.title = title; | ||
+ this.resource = resource; | ||
+ } | ||
+ | ||
+ /** | ||
+ * @param title Title | ||
+ * @param resource Drawable resource | ||
+ * @param color Background color | ||
+ */ | ||
+ public AHBottomNavigationItem(String title, int resource, int color) { | ||
+ this.title = title; | ||
+ this.resource = resource; | ||
+ this.color = color; | ||
+ } | ||
+ | ||
+ public String getTitle() { | ||
+ return title; | ||
+ } | ||
+ | ||
+ public void setTitle(String title) { | ||
+ this.title = title; | ||
+ } | ||
+ | ||
+ public int getColor() { | ||
+ return color; | ||
+ } | ||
+ | ||
+ public void setColor(int color) { | ||
+ this.color = color; | ||
+ } | ||
+ | ||
+ public int getResource() { | ||
+ return resource; | ||
+ } | ||
+ | ||
+ public void setResource(int resource) { | ||
+ this.resource = resource; | ||
+ } | ||
+} |
185
ahbottomnavigation/src/main/java/com/aurelhubert/ahbottomnavigation/AHHelper.java
@@ -0,0 +1,185 @@ | ||
+package com.aurelhubert.ahbottomnavigation; | ||
+ | ||
+import android.animation.ArgbEvaluator; | ||
+import android.animation.ValueAnimator; | ||
+import android.app.Activity; | ||
+import android.content.Context; | ||
+import android.graphics.drawable.Drawable; | ||
+import android.os.Build; | ||
+import android.support.v4.content.ContextCompat; | ||
+import android.support.v4.graphics.drawable.DrawableCompat; | ||
+import android.util.DisplayMetrics; | ||
+import android.util.TypedValue; | ||
+import android.view.View; | ||
+import android.view.ViewGroup; | ||
+import android.view.Window; | ||
+import android.view.WindowManager; | ||
+import android.widget.ImageView; | ||
+import android.widget.TextView; | ||
+ | ||
+/** | ||
+ * | ||
+ */ | ||
+public class AHHelper { | ||
+ | ||
+ /** | ||
+ * Return a tint drawable | ||
+ * | ||
+ * @param context | ||
+ * @param drawableResource | ||
+ * @param color | ||
+ * @return | ||
+ */ | ||
+ public static Drawable getTintDrawable(Context context, int drawableResource, int color) { | ||
+ Drawable normalDrawable = ContextCompat.getDrawable(context, drawableResource); | ||
+ Drawable wrapDrawable = DrawableCompat.wrap(normalDrawable); | ||
+ DrawableCompat.setTint(wrapDrawable, color); | ||
+ return wrapDrawable; | ||
+ } | ||
+ | ||
+ /** | ||
+ * Update top padding with animation | ||
+ */ | ||
+ public static void updateTopPadding(final View view, int fromPadding, int toPadding) { | ||
+ ValueAnimator animator = ValueAnimator.ofFloat(fromPadding, toPadding); | ||
+ animator.setDuration(150); | ||
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { | ||
+ @Override | ||
+ public void onAnimationUpdate(ValueAnimator valueAnimator) { | ||
+ float animatedValue = (float) valueAnimator.getAnimatedValue(); | ||
+ view.setPadding(view.getPaddingLeft(), | ||
+ (int) animatedValue, | ||
+ view.getPaddingRight(), | ||
+ view.getPaddingBottom()); | ||
+ } | ||
+ }); | ||
+ animator.start(); | ||
+ } | ||
+ | ||
+ /** | ||
+ * Update text size with animation | ||
+ */ | ||
+ public static void updateTextSize(final TextView textView, float fromSize, float toSize) { | ||
+ ValueAnimator animator = ValueAnimator.ofFloat(fromSize, toSize); | ||
+ animator.setDuration(150); | ||
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { | ||
+ @Override | ||
+ public void onAnimationUpdate(ValueAnimator valueAnimator) { | ||
+ float animatedValue = (float) valueAnimator.getAnimatedValue(); | ||
+ textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, animatedValue); | ||
+ } | ||
+ }); | ||
+ animator.start(); | ||
+ } | ||
+ | ||
+ /** | ||
+ * Update alpha | ||
+ */ | ||
+ public static void updateAlpha(final View view, float fromValue, float toValue) { | ||
+ ValueAnimator animator = ValueAnimator.ofFloat(fromValue, toValue); | ||
+ animator.setDuration(150); | ||
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { | ||
+ @Override | ||
+ public void onAnimationUpdate(ValueAnimator valueAnimator) { | ||
+ float animatedValue = (float) valueAnimator.getAnimatedValue(); | ||
+ view.setAlpha(animatedValue); | ||
+ } | ||
+ }); | ||
+ animator.start(); | ||
+ } | ||
+ | ||
+ /** | ||
+ * Update text color with animation | ||
+ */ | ||
+ public static void updateTextColor(final TextView textView, int fromColor, int toColor) { | ||
+ ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), fromColor, toColor); | ||
+ colorAnimation.setDuration(150); | ||
+ colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { | ||
+ @Override | ||
+ public void onAnimationUpdate(ValueAnimator animator) { | ||
+ textView.setTextColor((Integer) animator.getAnimatedValue()); | ||
+ } | ||
+ }); | ||
+ colorAnimation.start(); | ||
+ } | ||
+ | ||
+ /** | ||
+ * Update text color with animation | ||
+ */ | ||
+ public static void updateViewBackgroundColor(final View view, int fromColor, int toColor) { | ||
+ ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), fromColor, toColor); | ||
+ colorAnimation.setDuration(150); | ||
+ colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { | ||
+ @Override | ||
+ public void onAnimationUpdate(ValueAnimator animator) { | ||
+ view.setBackgroundColor((Integer) animator.getAnimatedValue()); | ||
+ } | ||
+ }); | ||
+ colorAnimation.start(); | ||
+ } | ||
+ | ||
+ /** | ||
+ * Update image view color with animation | ||
+ */ | ||
+ public static void updateDrawableColor(final Context context, final int drawable, | ||
+ final ImageView imageView, int fromColor, int toColor) { | ||
+ ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), fromColor, toColor); | ||
+ colorAnimation.setDuration(150); | ||
+ colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { | ||
+ @Override | ||
+ public void onAnimationUpdate(ValueAnimator animator) { | ||
+ imageView.setImageDrawable(AHHelper.getTintDrawable(context, drawable, | ||
+ (Integer) animator.getAnimatedValue())); | ||
+ } | ||
+ }); | ||
+ colorAnimation.start(); | ||
+ } | ||
+ | ||
+ /** | ||
+ * Update width | ||
+ */ | ||
+ public static void updateWidth(final View view, float fromWidth, float toWidth) { | ||
+ ValueAnimator animator = ValueAnimator.ofFloat(fromWidth, toWidth); | ||
+ animator.setDuration(150); | ||
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { | ||
+ @Override | ||
+ public void onAnimationUpdate(ValueAnimator animator) { | ||
+ ViewGroup.LayoutParams params = view.getLayoutParams(); | ||
+ params.width = Math.round((float) animator.getAnimatedValue()); | ||
+ view.setLayoutParams(params); | ||
+ } | ||
+ }); | ||
+ animator.start(); | ||
+ } | ||
+ | ||
+ /** | ||
+ * @param view | ||
+ * @return | ||
+ */ | ||
+ public static boolean isTranslucentStatusBar(View view) { | ||
+ Window w = ((Activity) view.getContext()).getWindow(); | ||
+ WindowManager.LayoutParams lp = w.getAttributes(); | ||
+ int flags = lp.flags; | ||
+ if ((flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) == WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) { | ||
+ return true; | ||
+ } | ||
+ | ||
+ return false; | ||
+ } | ||
+ | ||
+ public static int getSoftButtonsBarSizePort(View view) { | ||
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { | ||
+ DisplayMetrics metrics = new DisplayMetrics(); | ||
+ Window window = ((Activity) view.getContext()).getWindow(); | ||
+ window.getWindowManager().getDefaultDisplay().getMetrics(metrics); | ||
+ int usableHeight = metrics.heightPixels; | ||
+ window.getWindowManager().getDefaultDisplay().getRealMetrics(metrics); | ||
+ int realHeight = metrics.heightPixels; | ||
+ if (realHeight > usableHeight) | ||
+ return realHeight - usableHeight; | ||
+ else | ||
+ return 0; | ||
+ } | ||
+ return 0; | ||
+ } | ||
+} |
34
ahbottomnavigation/src/main/res/layout/bottom_navigation_item.xml
@@ -0,0 +1,34 @@ | ||
+<?xml version="1.0" encoding="utf-8"?> | ||
+<FrameLayout | ||
+ xmlns:android="http://schemas.android.com/apk/res/android" | ||
+ xmlns:tools="http://schemas.android.com/tools" | ||
+ android:id="@+id/bottom_navigation_container" | ||
+ android:layout_width="match_parent" | ||
+ android:layout_height="@dimen/bottom_navigation_height" | ||
+ android:minWidth="@dimen/bottom_navigation_min_width" | ||
+ android:orientation="vertical" | ||
+ android:paddingBottom="@dimen/bottom_navigation_padding_bottom" | ||
+ android:paddingLeft="@dimen/bottom_navigation_padding_left" | ||
+ android:paddingRight="@dimen/bottom_navigation_padding_right" | ||
+ android:background="?selectableItemBackgroundBorderless" | ||
+ android:paddingTop="@dimen/bottom_navigation_padding_top_inactive"> | ||
+ | ||
+ <ImageView | ||
+ android:id="@+id/bottom_navigation_item_icon" | ||
+ android:layout_width="@dimen/bottom_navigation_icon" | ||
+ android:layout_height="@dimen/bottom_navigation_icon" | ||
+ android:layout_gravity="center_horizontal" | ||
+ android:gravity="center" /> | ||
+ | ||
+ <TextView | ||
+ android:id="@+id/bottom_navigation_item_title" | ||
+ android:layout_width="match_parent" | ||
+ android:layout_height="wrap_content" | ||
+ android:layout_gravity="bottom|center_horizontal" | ||
+ android:gravity="center" | ||
+ android:lines="1" | ||
+ android:textColor="@color/colorInactive" | ||
+ android:textSize="@dimen/bottom_navigation_text_size_inactive" | ||
+ tools:text="Label One"/> | ||
+ | ||
+</FrameLayout> |
33
ahbottomnavigation/src/main/res/layout/bottom_navigation_small_item.xml
@@ -0,0 +1,33 @@ | ||
+<?xml version="1.0" encoding="utf-8"?> | ||
+<FrameLayout | ||
+ android:id="@+id/bottom_navigation_small_container" | ||
+ xmlns:android="http://schemas.android.com/apk/res/android" | ||
+ xmlns:tools="http://schemas.android.com/tools" | ||
+ android:layout_width="match_parent" | ||
+ android:layout_height="@dimen/bottom_navigation_height" | ||
+ android:background="?selectableItemBackgroundBorderless" | ||
+ android:minWidth="@dimen/bottom_navigation_min_width" | ||
+ android:orientation="vertical" | ||
+ android:paddingBottom="@dimen/bottom_navigation_padding_bottom" | ||
+ android:paddingTop="@dimen/bottom_navigation_small_padding_top"> | ||
+ | ||
+ <ImageView | ||
+ android:id="@+id/bottom_navigation_small_item_icon" | ||
+ android:layout_width="@dimen/bottom_navigation_icon" | ||
+ android:layout_height="@dimen/bottom_navigation_icon" | ||
+ android:layout_gravity="center_horizontal" | ||
+ android:gravity="center" /> | ||
+ | ||
+ <TextView | ||
+ android:id="@+id/bottom_navigation_small_item_title" | ||
+ android:layout_width="match_parent" | ||
+ android:layout_height="wrap_content" | ||
+ android:layout_gravity="bottom|center_horizontal" | ||
+ android:alpha="1" | ||
+ android:gravity="center" | ||
+ android:lines="1" | ||
+ android:textColor="@color/colorInactive" | ||
+ android:textSize="14sp" | ||
+ tools:text="Label One"/> | ||
+ | ||
+</FrameLayout> |
10
ahbottomnavigation/src/main/res/values/colors.xml
@@ -0,0 +1,10 @@ | ||
+<?xml version="1.0" encoding="utf-8"?> | ||
+<resources> | ||
+ <color name="colorPrimary">#3F51B5</color> | ||
+ <color name="colorPrimaryDark">#303F9F</color> | ||
+ <color name="colorAccent">#FF4081</color> | ||
+ | ||
+ <color name="colorInactive">#747474</color> | ||
+ <color name="colorActiveSmall">#FFFFFF</color> | ||
+ <color name="colorInactiveSmall">#50FFFFFF</color> | ||
+</resources> |
31
ahbottomnavigation/src/main/res/values/dimens.xml
@@ -0,0 +1,31 @@ | ||
+<resources> | ||
+ | ||
+ <dimen name="bottom_navigation_elevation">8dp</dimen> | ||
+ | ||
+ <dimen name="bottom_navigation_min_width">104dp</dimen> | ||
+ <dimen name="bottom_navigation_max_width">168dp</dimen> | ||
+ <dimen name="bottom_navigation_height">56dp</dimen> | ||
+ <dimen name="bottom_navigation_icon">24dp</dimen> | ||
+ | ||
+ <dimen name="bottom_navigation_padding_top_active">6dp</dimen> | ||
+ <dimen name="bottom_navigation_padding_top_inactive">8dp</dimen> | ||
+ <dimen name="bottom_navigation_padding_bottom">7dp</dimen> | ||
+ <dimen name="bottom_navigation_padding_left">12dp</dimen> | ||
+ <dimen name="bottom_navigation_padding_right">12dp</dimen> | ||
+ | ||
+ <dimen name="bottom_navigation_text_size_active">14sp</dimen> | ||
+ <dimen name="bottom_navigation_text_size_inactive">12sp</dimen> | ||
+ | ||
+ <!-- Small --> | ||
+ <dimen name="bottom_navigation_small_active_min_width">96dp</dimen> | ||
+ <dimen name="bottom_navigation_small_active_max_width">168dp</dimen> | ||
+ <dimen name="bottom_navigation_small_inactive_min_width">64dp</dimen> | ||
+ <dimen name="bottom_navigation_small_inactive_max_width">96dp</dimen> | ||
+ | ||
+ <dimen name="bottom_navigation_small_padding_top_active">6dp</dimen> | ||
+ <dimen name="bottom_navigation_small_padding_top">16dp</dimen> | ||
+ <dimen name="bottom_navigation_small_padding_bottom">16dp</dimen> | ||
+ | ||
+ <dimen name="bottom_navigation_small_selected_width_difference">10dp</dimen> | ||
+ | ||
+</resources> |
3
ahbottomnavigation/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@ | ||
+<resources> | ||
+ <string name="app_name">AHBottomNavigation</string> | ||
+</resources> |
15
ahbottomnavigation/src/test/java/com/aurelhubert/ahbottomnavigation/ExampleUnitTest.java
@@ -0,0 +1,15 @@ | ||
+package com.aurelhubert.ahbottomnavigation; | ||
+ | ||
+import org.junit.Test; | ||
+ | ||
+import static org.junit.Assert.*; | ||
+ | ||
+/** | ||
+ * To work on unit tests, switch the Test Artifact in the Build Variants view. | ||
+ */ | ||
+public class ExampleUnitTest { | ||
+ @Test | ||
+ public void addition_isCorrect() throws Exception { | ||
+ assertEquals(4, 2 + 2); | ||
+ } | ||
+} |
1
app/.gitignore
@@ -0,0 +1 @@ | ||
+/build |
27
app/build.gradle
@@ -0,0 +1,27 @@ | ||
+apply plugin: 'com.android.application' | ||
+ | ||
+android { | ||
+ compileSdkVersion 23 | ||
+ buildToolsVersion "23.0.2" | ||
+ | ||
+ defaultConfig { | ||
+ applicationId "aurelhubert.com.ahbottomnavigation" | ||
+ minSdkVersion 16 | ||
+ targetSdkVersion 23 | ||
+ versionCode 1 | ||
+ versionName "1.0" | ||
+ } | ||
+ buildTypes { | ||
+ release { | ||
+ minifyEnabled false | ||
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||
+ } | ||
+ } | ||
+} | ||
+ | ||
+dependencies { | ||
+ compile fileTree(dir: 'libs', include: ['*.jar']) | ||
+ testCompile 'junit:junit:4.12' | ||
+ compile 'com.android.support:appcompat-v7:23.2.1' | ||
+ compile project(':ahbottomnavigation') | ||
+} |
17
app/proguard-rules.pro
@@ -0,0 +1,17 @@ | ||
+# Add project specific ProGuard rules here. | ||
+# By default, the flags in this file are appended to flags specified | ||
+# in /Users/aurelien/Library/Android/sdk/tools/proguard/proguard-android.txt | ||
+# You can edit the include path and order by changing the proguardFiles | ||
+# directive in build.gradle. | ||
+# | ||
+# For more details, see | ||
+# http://developer.android.com/guide/developing/tools/proguard.html | ||
+ | ||
+# Add any project specific keep options here: | ||
+ | ||
+# If your project uses WebView with JS, uncomment the following | ||
+# and specify the fully qualified class name to the JavaScript interface | ||
+# class: | ||
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
+# public *; | ||
+#} |
13
app/src/androidTest/java/aurelhubert/com/ahbottomnavigation/ApplicationTest.java
@@ -0,0 +1,13 @@ | ||
+package aurelhubert.com.ahbottomnavigation; | ||
+ | ||
+import android.app.Application; | ||
+import android.test.ApplicationTestCase; | ||
+ | ||
+/** | ||
+ * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a> | ||
+ */ | ||
+public class ApplicationTest extends ApplicationTestCase<Application> { | ||
+ public ApplicationTest() { | ||
+ super(Application.class); | ||
+ } | ||
+} |
22
app/src/main/AndroidManifest.xml
@@ -0,0 +1,22 @@ | ||
+<?xml version="1.0" encoding="utf-8"?> | ||
+<manifest package="aurelhubert.com.ahbottomnavigation" | ||
+ xmlns:android="http://schemas.android.com/apk/res/android"> | ||
+ | ||
+ <uses-permission android:name="android.permission.INTERNET" /> | ||
+ | ||
+ <application | ||
+ android:allowBackup="true" | ||
+ android:icon="@mipmap/ic_launcher" | ||
+ android:label="@string/app_name" | ||
+ android:supportsRtl="true" | ||
+ android:theme="@style/AppTheme"> | ||
+ <activity android:name=".HomeActivity"> | ||
+ <intent-filter> | ||
+ <action android:name="android.intent.action.MAIN"/> | ||
+ | ||
+ <category android:name="android.intent.category.LAUNCHER"/> | ||
+ </intent-filter> | ||
+ </activity> | ||
+ </application> | ||
+ | ||
+</manifest> |
74
app/src/main/java/aurelhubert/com/ahbottomnavigation/HomeActivity.java
@@ -0,0 +1,74 @@ | ||
+package aurelhubert.com.ahbottomnavigation; | ||
+ | ||
+import android.graphics.Color; | ||
+import android.os.Bundle; | ||
+import android.support.v7.app.AppCompatActivity; | ||
+import android.support.v7.widget.SwitchCompat; | ||
+import android.widget.CompoundButton; | ||
+ | ||
+import com.aurelhubert.ahbottomnavigation.AHBottomNavigation; | ||
+import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem; | ||
+ | ||
+import java.util.ArrayList; | ||
+ | ||
+public class HomeActivity extends AppCompatActivity { | ||
+ | ||
+ @Override | ||
+ protected void onCreate(Bundle savedInstanceState) { | ||
+ super.onCreate(savedInstanceState); | ||
+ setContentView(R.layout.activity_home); | ||
+ initUI(); | ||
+ } | ||
+ | ||
+ /** | ||
+ * Init UI | ||
+ */ | ||
+ private void initUI() { | ||
+ | ||
+ final SwitchCompat switchColored = (SwitchCompat) findViewById(R.id.home_switch_colored); | ||
+ final SwitchCompat switchFourItems = (SwitchCompat) findViewById(R.id.home_switch_four_items); | ||
+ final AHBottomNavigation bottomNavigation = (AHBottomNavigation) findViewById(R.id.bottom_navigation); | ||
+ final ArrayList<AHBottomNavigationItem> items = new ArrayList<>(); | ||
+ | ||
+ AHBottomNavigationItem item1 = new AHBottomNavigationItem("Label One", R.drawable.ic_maps_place, Color.parseColor("#455C65")); | ||
+ AHBottomNavigationItem item2 = new AHBottomNavigationItem("Label Two", R.drawable.ic_maps_local_bar, Color.parseColor("#00886A")); | ||
+ AHBottomNavigationItem item3 = new AHBottomNavigationItem("Label Three", R.drawable.ic_maps_local_restaurant, Color.parseColor("#8B6B62")); | ||
+ final AHBottomNavigationItem item4 = new AHBottomNavigationItem("Label Four", R.drawable.ic_maps_local_bar, Color.parseColor("#6C4A42")); | ||
+ final AHBottomNavigationItem item5 = new AHBottomNavigationItem("Label Five", R.drawable.ic_maps_place, Color.parseColor("#8B6B62")); | ||
+ | ||
+ items.add(item1); | ||
+ items.add(item2); | ||
+ items.add(item3); | ||
+ | ||
+ bottomNavigation.addItems(items); | ||
+ bottomNavigation.setAccentColor(Color.parseColor("#00E676")); | ||
+ bottomNavigation.setAHBottomNavigationListener(new AHBottomNavigation.AHBottomNavigationListener() { | ||
+ @Override | ||
+ public void onTabSelected(int position) { | ||
+ //Toast.makeText(HomeActivity.this, "Select: " + position, Toast.LENGTH_SHORT).show(); | ||
+ } | ||
+ }); | ||
+ | ||
+ switchColored.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { | ||
+ @Override | ||
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { | ||
+ bottomNavigation.setColored(isChecked); | ||
+ } | ||
+ }); | ||
+ | ||
+ switchFourItems.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { | ||
+ @Override | ||
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { | ||
+ if (isChecked) { | ||
+ bottomNavigation.addItem(item4); | ||
+ bottomNavigation.addItem(item5); | ||
+ } else { | ||
+ bottomNavigation.removeAllItems(); | ||
+ bottomNavigation.addItems(items); | ||
+ } | ||
+ } | ||
+ }); | ||
+ | ||
+ } | ||
+ | ||
+} |
BIN
app/src/main/res/drawable-hdpi/ic_maps_local_attraction.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/drawable-hdpi/ic_maps_local_bar.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/drawable-hdpi/ic_maps_local_restaurant.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/drawable-hdpi/ic_maps_place.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/drawable-mdpi/ic_maps_local_attraction.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/drawable-mdpi/ic_maps_local_bar.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/drawable-mdpi/ic_maps_local_restaurant.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/drawable-mdpi/ic_maps_place.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/drawable-xhdpi/ic_maps_local_attraction.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/drawable-xhdpi/ic_maps_local_bar.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/drawable-xhdpi/ic_maps_local_restaurant.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/drawable-xhdpi/ic_maps_place.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/drawable-xxhdpi/ic_maps_local_attraction.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/drawable-xxhdpi/ic_maps_local_bar.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/drawable-xxhdpi/ic_maps_local_restaurant.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/drawable-xxhdpi/ic_maps_place.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/drawable-xxxhdpi/ic_maps_local_attraction.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/drawable-xxxhdpi/ic_maps_local_bar.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/drawable-xxxhdpi/ic_maps_local_restaurant.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/drawable-xxxhdpi/ic_maps_place.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61
app/src/main/res/layout/activity_home.xml
@@ -0,0 +1,61 @@ | ||
+<?xml version="1.0" encoding="utf-8"?> | ||
+<LinearLayout | ||
+ xmlns:android="http://schemas.android.com/apk/res/android" | ||
+ android:layout_width="match_parent" | ||
+ android:layout_height="match_parent" | ||
+ android:orientation="vertical"> | ||
+ | ||
+ <LinearLayout | ||
+ android:layout_width="match_parent" | ||
+ android:layout_height="0dp" | ||
+ android:layout_weight="1" | ||
+ android:padding="24dp" | ||
+ android:orientation="vertical"> | ||
+ | ||
+ <LinearLayout | ||
+ android:layout_width="match_parent" | ||
+ android:layout_height="wrap_content" | ||
+ android:orientation="horizontal"> | ||
+ | ||
+ <TextView | ||
+ android:layout_width="0dp" | ||
+ android:layout_height="wrap_content" | ||
+ android:layout_weight="1" | ||
+ android:text="Colored" | ||
+ android:textSize="18sp"/> | ||
+ | ||
+ <android.support.v7.widget.SwitchCompat | ||
+ android:id="@+id/home_switch_colored" | ||
+ android:layout_width="wrap_content" | ||
+ android:layout_height="wrap_content"/> | ||
+ | ||
+ </LinearLayout> | ||
+ | ||
+ <LinearLayout | ||
+ android:layout_width="match_parent" | ||
+ android:layout_height="wrap_content" | ||
+ android:layout_marginTop="24dp" | ||
+ android:orientation="horizontal"> | ||
+ | ||
+ <TextView | ||
+ android:layout_width="0dp" | ||
+ android:layout_height="wrap_content" | ||
+ android:layout_weight="1" | ||
+ android:text="5 items ?" | ||
+ android:textSize="18sp"/> | ||
+ | ||
+ <android.support.v7.widget.SwitchCompat | ||
+ android:id="@+id/home_switch_four_items" | ||
+ android:layout_width="wrap_content" | ||
+ android:layout_height="wrap_content"/> | ||
+ | ||
+ </LinearLayout> | ||
+ | ||
+ </LinearLayout> | ||
+ | ||
+ <com.aurelhubert.ahbottomnavigation.AHBottomNavigation | ||
+ android:id="@+id/bottom_navigation" | ||
+ android:layout_width="match_parent" | ||
+ android:layout_height="wrap_content"/> | ||
+ | ||
+</LinearLayout> |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11
app/src/main/res/values-v19/styles.xml
@@ -0,0 +1,11 @@ | ||
+<resources> | ||
+ | ||
+ <!-- Base application theme. --> | ||
+ <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> | ||
+ <!-- Customize your theme here. --> | ||
+ <item name="colorPrimary">@color/colorPrimary</item> | ||
+ <item name="colorPrimaryDark">@color/colorPrimaryDark</item> | ||
+ <item name="colorAccent">@color/colorAccent</item> | ||
+ </style> | ||
+ | ||
+</resources> |
6
app/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,6 @@ | ||
+<resources> | ||
+ <!-- Example customization of dimensions originally defined in res/values/dimens.xml | ||
+ (such as screen margins) for screens with more than 820dp of available width. This | ||
+ would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). --> | ||
+ <dimen name="activity_horizontal_margin">64dp</dimen> | ||
+</resources> |
9
app/src/main/res/values/colors.xml
@@ -0,0 +1,9 @@ | ||
+<?xml version="1.0" encoding="utf-8"?> | ||
+<resources> | ||
+ <color name="colorPrimary">#3F51B5</color> | ||
+ <color name="colorPrimaryDark">#303F9F</color> | ||
+ <color name="colorAccent">#FF4081</color> | ||
+ <color name="colorInactive">#747474</color> | ||
+ <color name="colorActiveSmall">#FFFFFF</color> | ||
+ <color name="colorInactiveSmall">#50FFFFFF</color> | ||
+</resources> |
31
app/src/main/res/values/dimens.xml
@@ -0,0 +1,31 @@ | ||
+<resources> | ||
+ | ||
+ <dimen name="bottom_navigation_elevation">8dp</dimen> | ||
+ | ||
+ <dimen name="bottom_navigation_min_width">104dp</dimen> | ||
+ <dimen name="bottom_navigation_max_width">168dp</dimen> | ||
+ <dimen name="bottom_navigation_height">56dp</dimen> | ||
+ <dimen name="bottom_navigation_icon">24dp</dimen> | ||
+ | ||
+ <dimen name="bottom_navigation_padding_top_active">6dp</dimen> | ||
+ <dimen name="bottom_navigation_padding_top_inactive">8dp</dimen> | ||
+ <dimen name="bottom_navigation_padding_bottom">7dp</dimen> | ||
+ <dimen name="bottom_navigation_padding_left">12dp</dimen> | ||
+ <dimen name="bottom_navigation_padding_right">12dp</dimen> | ||
+ | ||
+ <dimen name="bottom_navigation_text_size_active">14sp</dimen> | ||
+ <dimen name="bottom_navigation_text_size_inactive">12sp</dimen> | ||
+ | ||
+ <!-- Small --> | ||
+ <dimen name="bottom_navigation_small_active_min_width">96dp</dimen> | ||
+ <dimen name="bottom_navigation_small_active_max_width">168dp</dimen> | ||
+ <dimen name="bottom_navigation_small_inactive_min_width">64dp</dimen> | ||
+ <dimen name="bottom_navigation_small_inactive_max_width">96dp</dimen> | ||
+ | ||
+ <dimen name="bottom_navigation_small_padding_top_active">6dp</dimen> | ||
+ <dimen name="bottom_navigation_small_padding_top">16dp</dimen> | ||
+ <dimen name="bottom_navigation_small_padding_bottom">16dp</dimen> | ||
+ | ||
+ <dimen name="bottom_navigation_small_selected_width_difference">10dp</dimen> | ||
+ | ||
+</resources> |
3
app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@ | ||
+<resources> | ||
+ <string name="app_name">AHBottomNavigation</string> | ||
+</resources> |
11
app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@ | ||
+<resources> | ||
+ | ||
+ <!-- Base application theme. --> | ||
+ <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> | ||
+ <!-- Customize your theme here. --> | ||
+ <item name="colorPrimary">@color/colorPrimary</item> | ||
+ <item name="colorPrimaryDark">@color/colorPrimaryDark</item> | ||
+ <item name="colorAccent">@color/colorAccent</item> | ||
+ </style> | ||
+ | ||
+</resources> |
15
app/src/test/java/aurelhubert/com/ahbottomnavigation/ExampleUnitTest.java
@@ -0,0 +1,15 @@ | ||
+package aurelhubert.com.ahbottomnavigation; | ||
+ | ||
+import org.junit.Test; | ||
+ | ||
+import static org.junit.Assert.*; | ||
+ | ||
+/** | ||
+ * To work on unit tests, switch the Test Artifact in the Build Variants view. | ||
+ */ | ||
+public class ExampleUnitTest { | ||
+ @Test | ||
+ public void addition_isCorrect() throws Exception { | ||
+ assertEquals(4, 2 + 2); | ||
+ } | ||
+} |
23
build.gradle
@@ -0,0 +1,23 @@ | ||
+// Top-level build file where you can add configuration options common to all sub-projects/modules. | ||
+ | ||
+buildscript { | ||
+ repositories { | ||
+ jcenter() | ||
+ } | ||
+ dependencies { | ||
+ classpath 'com.android.tools.build:gradle:1.5.0' | ||
+ | ||
+ // NOTE: Do not place your application dependencies here; they belong | ||
+ // in the individual module build.gradle files | ||
+ } | ||
+} | ||
+ | ||
+allprojects { | ||
+ repositories { | ||
+ jcenter() | ||
+ } | ||
+} | ||
+ | ||
+task clean(type: Delete) { | ||
+ delete rootProject.buildDir | ||
+} |
18
gradle.properties
@@ -0,0 +1,18 @@ | ||
+# Project-wide Gradle settings. | ||
+ | ||
+# IDE (e.g. Android Studio) users: | ||
+# Gradle settings configured through the IDE *will override* | ||
+# any settings specified in this file. | ||
+ | ||
+# For more details on how to configure your build environment visit | ||
+# http://www.gradle.org/docs/current/userguide/build_environment.html | ||
+ | ||
+# Specifies the JVM arguments used for the daemon process. | ||
+# The setting is particularly useful for tweaking memory settings. | ||
+# Default value: -Xmx10248m -XX:MaxPermSize=256m | ||
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 | ||
+ | ||
+# When configured, Gradle will run in incubating parallel mode. | ||
+# This option should only be used with decoupled projects. More details, visit | ||
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects | ||
+# org.gradle.parallel=true |
BIN
gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@ | ||
+#Wed Oct 21 11:34:03 PDT 2015 | ||
+distributionBase=GRADLE_USER_HOME | ||
+distributionPath=wrapper/dists | ||
+zipStoreBase=GRADLE_USER_HOME | ||
+zipStorePath=wrapper/dists | ||
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip |
160
gradlew
@@ -0,0 +1,160 @@ | ||
+#!/usr/bin/env bash | ||
+ | ||
+############################################################################## | ||
+## | ||
+## Gradle start up script for UN*X | ||
+## | ||
+############################################################################## | ||
+ | ||
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||
+DEFAULT_JVM_OPTS="" | ||
+ | ||
+APP_NAME="Gradle" | ||
+APP_BASE_NAME=`basename "$0"` | ||
+ | ||
+# Use the maximum available, or set MAX_FD != -1 to use that value. | ||
+MAX_FD="maximum" | ||
+ | ||
+warn ( ) { | ||
+ echo "$*" | ||
+} | ||
+ | ||
+die ( ) { | ||
+ echo | ||
+ echo "$*" | ||
+ echo | ||
+ exit 1 | ||
+} | ||
+ | ||
+# OS specific support (must be 'true' or 'false'). | ||
+cygwin=false | ||
+msys=false | ||
+darwin=false | ||
+case "`uname`" in | ||
+ CYGWIN* ) | ||
+ cygwin=true | ||
+ ;; | ||
+ Darwin* ) | ||
+ darwin=true | ||
+ ;; | ||
+ MINGW* ) | ||
+ msys=true | ||
+ ;; | ||
+esac | ||
+ | ||
+# Attempt to set APP_HOME | ||
+# Resolve links: $0 may be a link | ||
+PRG="$0" | ||
+# Need this for relative symlinks. | ||
+while [ -h "$PRG" ] ; do | ||
+ ls=`ls -ld "$PRG"` | ||
+ link=`expr "$ls" : '.*-> \(.*\)$'` | ||
+ if expr "$link" : '/.*' > /dev/null; then | ||
+ PRG="$link" | ||
+ else | ||
+ PRG=`dirname "$PRG"`"/$link" | ||
+ fi | ||
+done | ||
+SAVED="`pwd`" | ||
+cd "`dirname \"$PRG\"`/" >/dev/null | ||
+APP_HOME="`pwd -P`" | ||
+cd "$SAVED" >/dev/null | ||
+ | ||
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar | ||
+ | ||
+# Determine the Java command to use to start the JVM. | ||
+if [ -n "$JAVA_HOME" ] ; then | ||
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then | ||
+ # IBM's JDK on AIX uses strange locations for the executables | ||
+ JAVACMD="$JAVA_HOME/jre/sh/java" | ||
+ else | ||
+ JAVACMD="$JAVA_HOME/bin/java" | ||
+ fi | ||
+ if [ ! -x "$JAVACMD" ] ; then | ||
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME | ||
+ | ||
+Please set the JAVA_HOME variable in your environment to match the | ||
+location of your Java installation." | ||
+ fi | ||
+else | ||
+ JAVACMD="java" | ||
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||
+ | ||
+Please set the JAVA_HOME variable in your environment to match the | ||
+location of your Java installation." | ||
+fi | ||
+ | ||
+# Increase the maximum file descriptors if we can. | ||
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then | ||
+ MAX_FD_LIMIT=`ulimit -H -n` | ||
+ if [ $? -eq 0 ] ; then | ||
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then | ||
+ MAX_FD="$MAX_FD_LIMIT" | ||
+ fi | ||
+ ulimit -n $MAX_FD | ||
+ if [ $? -ne 0 ] ; then | ||
+ warn "Could not set maximum file descriptor limit: $MAX_FD" | ||
+ fi | ||
+ else | ||
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" | ||
+ fi | ||
+fi | ||
+ | ||
+# For Darwin, add options to specify how the application appears in the dock | ||
+if $darwin; then | ||
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" | ||
+fi | ||
+ | ||
+# For Cygwin, switch paths to Windows format before running java | ||
+if $cygwin ; then | ||
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"` | ||
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` | ||
+ JAVACMD=`cygpath --unix "$JAVACMD"` | ||
+ | ||
+ # We build the pattern for arguments to be converted via cygpath | ||
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` | ||
+ SEP="" | ||
+ for dir in $ROOTDIRSRAW ; do | ||
+ ROOTDIRS="$ROOTDIRS$SEP$dir" | ||
+ SEP="|" | ||
+ done | ||
+ OURCYGPATTERN="(^($ROOTDIRS))" | ||
+ # Add a user-defined pattern to the cygpath arguments | ||
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then | ||
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" | ||
+ fi | ||
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh | ||
+ i=0 | ||
+ for arg in "$@" ; do | ||
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` | ||
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option | ||
+ | ||
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition | ||
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` | ||
+ else | ||
+ eval `echo args$i`="\"$arg\"" | ||
+ fi | ||
+ i=$((i+1)) | ||
+ done | ||
+ case $i in | ||
+ (0) set -- ;; | ||
+ (1) set -- "$args0" ;; | ||
+ (2) set -- "$args0" "$args1" ;; | ||
+ (3) set -- "$args0" "$args1" "$args2" ;; | ||
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;; | ||
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; | ||
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; | ||
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; | ||
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; | ||
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; | ||
+ esac | ||
+fi | ||
+ | ||
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules | ||
+function splitJvmOpts() { | ||
+ JVM_OPTS=("$@") | ||
+} | ||
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS | ||
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" | ||
+ | ||
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" |
90
gradlew.bat
@@ -0,0 +1,90 @@ | ||
+@if "%DEBUG%" == "" @echo off | ||
+@rem ########################################################################## | ||
+@rem | ||
+@rem Gradle startup script for Windows | ||
+@rem | ||
+@rem ########################################################################## | ||
+ | ||
+@rem Set local scope for the variables with windows NT shell | ||
+if "%OS%"=="Windows_NT" setlocal | ||
+ | ||
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||
+set DEFAULT_JVM_OPTS= | ||
+ | ||
+set DIRNAME=%~dp0 | ||
+if "%DIRNAME%" == "" set DIRNAME=. | ||
+set APP_BASE_NAME=%~n0 | ||
+set APP_HOME=%DIRNAME% | ||
+ | ||
+@rem Find java.exe | ||
+if defined JAVA_HOME goto findJavaFromJavaHome | ||
+ | ||
+set JAVA_EXE=java.exe | ||
+%JAVA_EXE% -version >NUL 2>&1 | ||
+if "%ERRORLEVEL%" == "0" goto init | ||
+ | ||
+echo. | ||
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||
+echo. | ||
+echo Please set the JAVA_HOME variable in your environment to match the | ||
+echo location of your Java installation. | ||
+ | ||
+goto fail | ||
+ | ||
+:findJavaFromJavaHome | ||
+set JAVA_HOME=%JAVA_HOME:"=% | ||
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe | ||
+ | ||
+if exist "%JAVA_EXE%" goto init | ||
+ | ||
+echo. | ||
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% | ||
+echo. | ||
+echo Please set the JAVA_HOME variable in your environment to match the | ||
+echo location of your Java installation. | ||
+ | ||
+goto fail | ||
+ | ||
+:init | ||
+@rem Get command-line arguments, handling Windowz variants | ||
+ | ||
+if not "%OS%" == "Windows_NT" goto win9xME_args | ||
+if "%@eval[2+2]" == "4" goto 4NT_args | ||
+ | ||
+:win9xME_args | ||
+@rem Slurp the command line arguments. | ||
+set CMD_LINE_ARGS= | ||
+set _SKIP=2 | ||
+ | ||
+:win9xME_args_slurp | ||
+if "x%~1" == "x" goto execute | ||
+ | ||
+set CMD_LINE_ARGS=%* | ||
+goto execute | ||
+ | ||
+:4NT_args | ||
+@rem Get arguments from the 4NT Shell from JP Software | ||
+set CMD_LINE_ARGS=%$ | ||
+ | ||
+:execute | ||
+@rem Setup the command line | ||
+ | ||
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | ||
+ | ||
+@rem Execute Gradle | ||
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% | ||
+ | ||
+:end | ||
+@rem End local scope for the variables with windows NT shell | ||
+if "%ERRORLEVEL%"=="0" goto mainEnd | ||
+ | ||
+:fail | ||
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | ||
+rem the _cmd.exe /c_ return code! | ||
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 | ||
+exit /b 1 | ||
+ | ||
+:mainEnd | ||
+if "%OS%"=="Windows_NT" endlocal | ||
+ | ||
+:omega |
1
settings.gradle
@@ -0,0 +1 @@ | ||
+include ':app', ':ahbottomnavigation' |
0 comments on commit
e0caaef