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