Permalink
Please sign in to comment.
Showing
with
324 additions
and 9 deletions.
- +2 −0 bottom-bar/bottom-bar.iml
- +1 −0 bottom-bar/build.gradle
- +74 −7 bottom-bar/src/main/java/com/roughike/bottombar/BottomBar.java
- +68 −0 bottom-bar/src/main/java/com/roughike/bottombar/scrollsweetness/BottomNavigationBehavior.java
- +148 −0 bottom-bar/src/main/java/com/roughike/bottombar/scrollsweetness/VerticalScrollingBehavior.java
- +1 −2 bottom-bar/src/main/res/layout/bb_bottom_bar_item_container.xml
- +30 −0 bottom-bar/src/main/res/layout/bb_bottom_bar_item_container_shy.xml
2
bottom-bar/bottom-bar.iml
1
bottom-bar/build.gradle
81
bottom-bar/src/main/java/com/roughike/bottombar/BottomBar.java
68
...om-bar/src/main/java/com/roughike/bottombar/scrollsweetness/BottomNavigationBehavior.java
@@ -0,0 +1,68 @@ | ||
+package com.roughike.bottombar.scrollsweetness; | ||
+ | ||
+import android.support.design.widget.CoordinatorLayout; | ||
+import android.support.v4.view.ViewCompat; | ||
+import android.support.v4.view.ViewPropertyAnimatorCompat; | ||
+import android.support.v4.view.animation.LinearOutSlowInInterpolator; | ||
+import android.view.View; | ||
+import android.view.animation.Interpolator; | ||
+ | ||
+/** | ||
+ * Created by Nikola D. on 3/15/2016. | ||
+ * | ||
+ * Credit goes to Nikola Despotoski: | ||
+ * https://github.com/NikolaDespotoski | ||
+ */ | ||
+public class BottomNavigationBehavior<V extends View> extends VerticalScrollingBehavior<V> { | ||
+ private static final Interpolator INTERPOLATOR = new LinearOutSlowInInterpolator(); | ||
+ private final int mBottomNavHeight; | ||
+ private final int mDefaultOffset; | ||
+ | ||
+ private ViewPropertyAnimatorCompat mTranslationAnimator; | ||
+ private boolean hidden = false; | ||
+ | ||
+ public BottomNavigationBehavior(int bottomNavHeight, int defaultOffset) { | ||
+ mBottomNavHeight = bottomNavHeight; | ||
+ mDefaultOffset = defaultOffset; | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onNestedVerticalOverScroll(CoordinatorLayout coordinatorLayout, V child, @ScrollDirection int direction, int currentOverScroll, int totalOverScroll) { | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onDirectionNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed, @ScrollDirection int scrollDirection) { | ||
+ handleDirection(child, scrollDirection); | ||
+ } | ||
+ | ||
+ private void handleDirection(V child, int scrollDirection) { | ||
+ if (scrollDirection == ScrollDirection.SCROLL_DIRECTION_DOWN && hidden) { | ||
+ hidden = false; | ||
+ animateOffset(child, mDefaultOffset); | ||
+ } else if (scrollDirection == ScrollDirection.SCROLL_DIRECTION_UP && !hidden) { | ||
+ hidden = true; | ||
+ animateOffset(child, mBottomNavHeight + mDefaultOffset); | ||
+ } | ||
+ } | ||
+ | ||
+ @Override | ||
+ protected boolean onNestedDirectionFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY, @ScrollDirection int scrollDirection) { | ||
+ handleDirection(child, scrollDirection); | ||
+ return true; | ||
+ } | ||
+ | ||
+ private void animateOffset(final V child, final int offset) { | ||
+ ensureOrCancelAnimator(child); | ||
+ mTranslationAnimator.translationY(offset).start(); | ||
+ } | ||
+ | ||
+ private void ensureOrCancelAnimator(V child) { | ||
+ if (mTranslationAnimator == null) { | ||
+ mTranslationAnimator = ViewCompat.animate(child); | ||
+ mTranslationAnimator.setDuration(300); | ||
+ mTranslationAnimator.setInterpolator(INTERPOLATOR); | ||
+ } else { | ||
+ mTranslationAnimator.cancel(); | ||
+ } | ||
+ } | ||
+} |
148
...m-bar/src/main/java/com/roughike/bottombar/scrollsweetness/VerticalScrollingBehavior.java
@@ -0,0 +1,148 @@ | ||
+package com.roughike.bottombar.scrollsweetness; | ||
+ | ||
+import android.content.Context; | ||
+import android.os.Parcelable; | ||
+import android.support.annotation.IntDef; | ||
+import android.support.design.widget.CoordinatorLayout; | ||
+import android.support.v4.view.WindowInsetsCompat; | ||
+import android.util.AttributeSet; | ||
+import android.view.View; | ||
+ | ||
+import java.lang.annotation.Retention; | ||
+import java.lang.annotation.RetentionPolicy; | ||
+ | ||
+/** | ||
+ * Created by Nikola D. on 11/22/2015. | ||
+ * | ||
+ * Credit goes to Nikola Despotoski: | ||
+ * https://github.com/NikolaDespotoski | ||
+ */ | ||
+public abstract class VerticalScrollingBehavior<V extends View> extends CoordinatorLayout.Behavior<V> { | ||
+ | ||
+ private int mTotalDyUnconsumed = 0; | ||
+ private int mTotalDy = 0; | ||
+ @ScrollDirection | ||
+ private int mOverScrollDirection = ScrollDirection.SCROLL_NONE; | ||
+ @ScrollDirection | ||
+ private int mScrollDirection = ScrollDirection.SCROLL_NONE; | ||
+ | ||
+ public VerticalScrollingBehavior(Context context, AttributeSet attrs) { | ||
+ super(context, attrs); | ||
+ } | ||
+ | ||
+ public VerticalScrollingBehavior() { | ||
+ super(); | ||
+ } | ||
+ | ||
+ @Retention(RetentionPolicy.SOURCE) | ||
+ @IntDef({ScrollDirection.SCROLL_DIRECTION_UP, ScrollDirection.SCROLL_DIRECTION_DOWN}) | ||
+ public @interface ScrollDirection { | ||
+ int SCROLL_DIRECTION_UP = 1; | ||
+ int SCROLL_DIRECTION_DOWN = -1; | ||
+ int SCROLL_NONE = 0; | ||
+ } | ||
+ | ||
+ | ||
+ /* | ||
+ @return Overscroll direction: SCROLL_DIRECTION_UP, CROLL_DIRECTION_DOWN, SCROLL_NONE | ||
+ */ | ||
+ @ScrollDirection | ||
+ public int getOverScrollDirection() { | ||
+ return mOverScrollDirection; | ||
+ } | ||
+ | ||
+ | ||
+ /** | ||
+ * @return Scroll direction: SCROLL_DIRECTION_UP, SCROLL_DIRECTION_DOWN, SCROLL_NONE | ||
+ */ | ||
+ | ||
+ @ScrollDirection | ||
+ public int getScrollDirection() { | ||
+ return mScrollDirection; | ||
+ } | ||
+ | ||
+ | ||
+ /** | ||
+ * @param coordinatorLayout | ||
+ * @param child | ||
+ * @param direction Direction of the overscroll: SCROLL_DIRECTION_UP, SCROLL_DIRECTION_DOWN | ||
+ * @param currentOverScroll Unconsumed value, negative or positive based on the direction; | ||
+ * @param totalOverScroll Cumulative value for current direction | ||
+ */ | ||
+ public abstract void onNestedVerticalOverScroll(CoordinatorLayout coordinatorLayout, V child, @ScrollDirection int direction, int currentOverScroll, int totalOverScroll); | ||
+ | ||
+ /** | ||
+ * @param scrollDirection Direction of the overscroll: SCROLL_DIRECTION_UP, SCROLL_DIRECTION_DOWN | ||
+ */ | ||
+ public abstract void onDirectionNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed, @ScrollDirection int scrollDirection); | ||
+ | ||
+ @Override | ||
+ public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child, View directTargetChild, View target, int nestedScrollAxes) { | ||
+ return (nestedScrollAxes & View.SCROLL_AXIS_VERTICAL) != 0; | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, V child, View directTargetChild, View target, int nestedScrollAxes) { | ||
+ super.onNestedScrollAccepted(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes); | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) { | ||
+ super.onStopNestedScroll(coordinatorLayout, child, target); | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { | ||
+ super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed); | ||
+ if (dyUnconsumed > 0 && mTotalDyUnconsumed < 0) { | ||
+ mTotalDyUnconsumed = 0; | ||
+ mOverScrollDirection = ScrollDirection.SCROLL_DIRECTION_UP; | ||
+ } else if (dyUnconsumed < 0 && mTotalDyUnconsumed > 0) { | ||
+ mTotalDyUnconsumed = 0; | ||
+ mOverScrollDirection = ScrollDirection.SCROLL_DIRECTION_DOWN; | ||
+ } | ||
+ mTotalDyUnconsumed += dyUnconsumed; | ||
+ onNestedVerticalOverScroll(coordinatorLayout, child, mOverScrollDirection, dyConsumed, mTotalDyUnconsumed); | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed) { | ||
+ super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed); | ||
+ if (dy > 0 && mTotalDy < 0) { | ||
+ mTotalDy = 0; | ||
+ mScrollDirection = ScrollDirection.SCROLL_DIRECTION_UP; | ||
+ } else if (dy < 0 && mTotalDy > 0) { | ||
+ mTotalDy = 0; | ||
+ mScrollDirection = ScrollDirection.SCROLL_DIRECTION_DOWN; | ||
+ } | ||
+ mTotalDy += dy; | ||
+ onDirectionNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, mScrollDirection); | ||
+ } | ||
+ | ||
+ | ||
+ @Override | ||
+ public boolean onNestedFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY, boolean consumed) { | ||
+ super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed); | ||
+ mScrollDirection = velocityY > 0 ? ScrollDirection.SCROLL_DIRECTION_UP : ScrollDirection.SCROLL_DIRECTION_DOWN; | ||
+ return onNestedDirectionFling(coordinatorLayout, child, target, velocityX, velocityY, mScrollDirection); | ||
+ } | ||
+ | ||
+ protected abstract boolean onNestedDirectionFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY, @ScrollDirection int scrollDirection); | ||
+ | ||
+ @Override | ||
+ public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY) { | ||
+ return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY); | ||
+ } | ||
+ | ||
+ @Override | ||
+ public WindowInsetsCompat onApplyWindowInsets(CoordinatorLayout coordinatorLayout, V child, WindowInsetsCompat insets) { | ||
+ | ||
+ return super.onApplyWindowInsets(coordinatorLayout, child, insets); | ||
+ } | ||
+ | ||
+ @Override | ||
+ public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) { | ||
+ return super.onSaveInstanceState(parent, child); | ||
+ } | ||
+ | ||
+} |
3
bottom-bar/src/main/res/layout/bb_bottom_bar_item_container.xml
30
bottom-bar/src/main/res/layout/bb_bottom_bar_item_container_shy.xml
@@ -0,0 +1,30 @@ | ||
+<?xml version="1.0" encoding="utf-8"?> | ||
+<FrameLayout | ||
+ xmlns:android="http://schemas.android.com/apk/res/android" | ||
+ android:id="@+id/bb_bottom_bar_outer_container" | ||
+ android:layout_width="match_parent" | ||
+ android:layout_height="wrap_content" | ||
+ android:layout_gravity="bottom"> | ||
+ | ||
+ <FrameLayout | ||
+ android:id="@+id/bb_bottom_bar_background_view" | ||
+ android:layout_width="match_parent" | ||
+ android:layout_height="match_parent" | ||
+ android:background="#FFFFFF" /> | ||
+ | ||
+ <FrameLayout | ||
+ android:id="@+id/bb_bottom_bar_background_overlay" | ||
+ android:layout_width="match_parent" | ||
+ android:layout_height="match_parent" | ||
+ android:src="@drawable/bb_bottom_bar_top_shadow" | ||
+ android:visibility="invisible" /> | ||
+ | ||
+ <LinearLayout | ||
+ android:id="@+id/bb_bottom_bar_item_container" | ||
+ android:layout_width="match_parent" | ||
+ android:layout_height="wrap_content" | ||
+ android:background="#00000000" | ||
+ android:gravity="center_horizontal" | ||
+ android:orientation="horizontal" /> | ||
+ | ||
+</FrameLayout> |
0 comments on commit
bf66264