Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tranngoclam/3da90a05e1e1c0755fe58f4a735553d9 to your computer and use it in GitHub Desktop.
Save tranngoclam/3da90a05e1e1c0755fe58f4a735553d9 to your computer and use it in GitHub Desktop.
Custom bottom navigation bar
abstract class BaseBottomNavActivity extends BaseActivity { // you can directly extend AppCompatActivity
@Override
@CallSuper
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initOnCreate(savedInstanceState);
getBottomNavigationBar().setOnTabSelectionListener(
new CustomBottomNavigationBar.OnTabSelectionListener() {
@Override
public void onTabSelected(int position) { // start your various top-level activites from here
if (position != getCurrentBottomNavPosition()) {
switch (position) {
case CustomBottomNavigationBar.POSITION_HOME_TAB:
HomeActivity.start(BaseBottomNavActivity.this);
break;
case CustomBottomNavigationBar.POSITION_UPDATES_TAB:
UpdatesActivity.start(BaseBottomNavActivity.this);
break;
case CustomBottomNavigationBar.POSITION_BOOKMARKS_TAB:
BookmarksActivity.start(BaseBottomNavActivity.this);
break;
case CustomBottomNavigationBar.POSITION_PROFILE_TAB:
ProfileActivity.start(BaseBottomNavActivity.this);
break;
case CustomBottomNavigationBar.POSITION_FINISHED_STORIES_TAB:
FinishedStoriesActivity.start(BaseBottomNavActivity.this);
break;
}
} else {
onNavBarReselect();
}
}
});
}
protected abstract void onNavBarReselect(); // child activity should implement how re-selecting the same (current) tab will be handled.
@Override
protected void onResume() {
super.onResume();
getBottomNavigationBar().setSelectedTab(getCurrentBottomNavPosition());
}
// TODO: uncomment if backstack behavior needs to change
// @Override
// public void onBackPressed() {
// ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
// List<ActivityManager.AppTask> appTasks = activityManager.getAppTasks();
// for (ActivityManager.AppTask task : appTasks) {
// task.finishAndRemoveTask();
// }
// }
protected abstract int getCurrentBottomNavPosition(); // e.g. for the switch case above HomeActivity returns CustomBottomNavigationBar.POSITION_HOME_TAB here
protected abstract CustomBottomNavigationBar getBottomNavigationBar(); //e.g. get the bottom nav bar from the child's layout
protected abstract void initOnCreate(Bundle savedInstanceState); //e.g. child activities to call this, initialize layout in this so that bottom nav bar is available when line 8 is called
@NonNull
protected Snackbar showSnackbar(Snackbar snackbar, boolean hasAction) { // used to show the snackbar above the bottom nav bar. This assumes that the parent of each child activity is a coordinator layout.
Typeface font = Typeface.createFromAsset(getAssets(), AppTextView.APP_TEXT_FONT);
TextView tv = (TextView) (snackbar.getView()).findViewById(android.support.design.R.id.snackbar_text);
tv.setTypeface(font);
Button button = (Button) (snackbar.getView()).findViewById(android.support.design.R.id.snackbar_action);
button.setTypeface(font);
CoordinatorLayout.LayoutParams params
= (CoordinatorLayout.LayoutParams) snackbar.getView().getLayoutParams();
params.setMargins(params.leftMargin, params.topMargin, params.rightMargin,
getBottomNavigationBar().getBottomBarHeight());
snackbar.getView().setLayoutParams(params);
snackbar.show();
return snackbar;
}
}
public class CustomBottomNavigationBar extends FrameLayout {
// These would be names and associated positions of the tabs specific to your app
public static final int POSITION_HOME_TAB = 0;
public static final int POSITION_UPDATES_TAB = 2;
public static final int POSITION_FINISHED_STORIES_TAB = 1;
public static final int POSITION_BOOKMARKS_TAB = 3;
public static final int POSITION_PROFILE_TAB = 4;
// Passed in from the activities using this, in the setter below
private OnTabSelectionListener mTabSelectionListener;
// For some first-time arrangements of the layout
private boolean drawn;
private LayoutBottomBarBinding binding;
// To store resource ids of the drawable for the icons, the order of tabs above should be the same
private Integer[] tabResId;
// Used in initial layout
private boolean shadowDrawn;
public CustomBottomNavigationBar(Context context) {
super(context);
initLayout(context);
}
public CustomBottomNavigationBar(Context context, AttributeSet attrs) {
super(context, attrs);
initLayout(context);
}
public CustomBottomNavigationBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initLayout(context);
}
public CustomBottomNavigationBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initLayout(context);
}
private void initLayout(Context context) {
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
binding = DataBindingUtil.inflate(layoutInflater, R.layout.layout_bottom_bar, this, true);
tabResId = new Integer[]{R.id.home_tab_btn, R.id.leaderboard_tab_btn, R.id.activity_tab_btn,
R.id.bookmarks_tab_btn, R.id.profile_tab_btn};
binding.homeTabBtn.setOnClickListener(new InternalTabSelectionListener(POSITION_HOME_TAB));
binding.activityTabBtn.setOnClickListener(new InternalTabSelectionListener(POSITION_UPDATES_TAB));
binding.leaderboardTabBtn.setOnClickListener(new InternalTabSelectionListener(POSITION_FINISHED_STORIES_TAB));
binding.bookmarksTabBtn.setOnClickListener(new InternalTabSelectionListener(POSITION_BOOKMARKS_TAB));
binding.profileTabBtn.setOnClickListener(new InternalTabSelectionListener(POSITION_PROFILE_TAB));
setWillNotDraw(false);
setClipToPadding(false);
setClipToOutline(false);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!drawn) {
drawn = true;
Rect rect = new Rect();
((View) getParent()).getGlobalVisibleRect(rect);
setY(rect.bottom - rect.top - getContext().getResources().getDimension(R.dimen.bottom_bar_with_shadow_height));
invalidate();
} else if (!shadowDrawn) {
shadowDrawn = true;
binding.shadowGradient.draw(canvas);
}
}
public int getBottomBarHeight() {
return binding.bottomBarLayout.getHeight();
}
public void setOnTabSelectionListener(OnTabSelectionListener tabSelectionListener) {
this.mTabSelectionListener = tabSelectionListener;
}
public void setSelectedTab(int position) {
binding.bottomBarLayout.check(tabResId[position]);
}
public interface OnTabSelectionListener {
void onTabSelected(int position);
}
private class InternalTabSelectionListener implements OnClickListener {
private final int mCurrentPosition;
public InternalTabSelectionListener(int currentTabPosition) {
mCurrentPosition = currentTabPosition;
}
@Override
public void onClick(View view) {
if (mTabSelectionListener != null) {
mTabSelectionListener.onTabSelected(mCurrentPosition);
}
}
}
}
public class HomeActivity extends BaseBottomNavActivity { //thinned down sample implementation of the BaseBottomNavActivity above
private ActivityHomeBinding binding;
public static void start(Activity activity) {
Intent intent = new Intent(activity.getApplicationContext(), HomeActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
activity.startActivity(intent);
}
public static Intent getStartIntent(Context context) { // if required in a service etc
Intent intent = new Intent(context, HomeActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
return intent;
}
@Override
protected void initOnCreate(Bundle savedInstanceState) {
binding = DataBindingUtil.setContentView(this, R.layout.activity_home);
}
@Override
protected void onNavBarReselect() {
removeProfileFragmentIfAdded(); // sample method call
}
private boolean removeProfileFragmentIfAdded() {
boolean wasAdded = getSupportFragmentManager().popBackStackImmediate();
if (wasAdded) {
mIsDataFetched.setValue(true);
setupActionBar(binding.layoutToolbar, getString(R.string.title_home), false);
binding.contentSwipeRl.setEnabled(true);
showToolbarIconFor(null);
removeViewProfileFragment();
updateAddStoryFabVisibility(false);
}
return wasAdded;
}
@Override
protected int getCurrentBottomNavPosition() {
return CustomBottomNavigationBar.POSITION_HOME_TAB;
}
@Override
protected CustomBottomNavigationBar getBottomNavigationBar() {
return binding.bottomNavBar;
}
@Override
public void onBackPressed() {
boolean wasAdded = removeProfileFragmentIfAdded();
if (!wasAdded) {
super.onBackPressed();
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_bar_with_shadow_height">
<View
android:id="@+id/shadow_gradient"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_bar_with_shadow_height"
android:background="@drawable/shadow_gradient" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RadioGroup
android:id="@+id/bottom_bar_layout"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_bar_height"
android:layout_alignParentBottom="true"
android:background="@color/colorPrimaryDark"
android:elevation="4dp"
android:gravity="center"
android:orientation="horizontal">
<com.adroitandroid.stitchastory.ui.RadioButtonPlus
android:id="@+id/home_tab_btn"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@null"
android:button="@drawable/ic_home" />
<com.adroitandroid.stitchastory.ui.RadioButtonPlus
android:id="@+id/leaderboard_tab_btn"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@null"
android:button="@drawable/ic_leaderboard" />
<com.adroitandroid.stitchastory.ui.RadioButtonPlus
android:id="@+id/activity_tab_btn"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@null"
android:button="@drawable/ic_activity" />
<com.adroitandroid.stitchastory.ui.RadioButtonPlus
android:id="@+id/bookmarks_tab_btn"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@null"
android:button="@drawable/ic_collection_bookmarks" />
<com.adroitandroid.stitchastory.ui.RadioButtonPlus
android:id="@+id/profile_tab_btn"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@null"
android:button="@drawable/ic_profile" />
</RadioGroup>
</RelativeLayout>
</FrameLayout>
</layout>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment