Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
[![AwesomeAndroid](https://img.shields.io/badge/Awesome_Android-BubbleNavigation-purple.svg?style=flat)](https://android.libhunt.com/bubble-navigation-alternatives)

🎉 A light-weight library to make beautiful Navigation Bar easily with ton of 🎨 customization option.

</br>
**orientation,and first item selected bug and other bugs fixed**
## Demos

| FloatingTopBarActivity | TopBarActivity |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,219 +37,140 @@
@SuppressWarnings("unused")
public class BubbleNavigationLinearView extends LinearLayout implements View.OnClickListener {

//constants
private static final String TAG = "BNLView";
private static final int MIN_ITEMS = 2;
private static final int MAX_ITEMS = 5;

private ArrayList<BubbleToggleView> bubbleNavItems;
private BubbleNavigationChangeListener navigationChangeListener;

private String CURRENT_ACTIVE_VIEW = "x.f";
private int currentActiveItemPosition = 0;
private static final String TAG = "bnlview";
private BubbleNavigationChangeListener navigationChangeListener = null;

/**
* Constructors
*/
public BubbleNavigationLinearView(@NonNull Context context) {
super(context);
init(context, null);
}
public BubbleNavigationLinearView(Context context, AttributeSet attrs) {
super(context,attrs);
init();

public BubbleNavigationLinearView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}

public BubbleNavigationLinearView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}

@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable("superState", super.onSaveInstanceState());
bundle.putInt("current_item", currentActiveItemPosition);
return bundle;
public BubbleNavigationLinearView(Context context) {
super(context);
init();
}

@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
Bundle bundle = (Bundle) state;
currentActiveItemPosition = bundle.getInt("current_item");
state = bundle.getParcelable("superState");
}
super.onRestoreInstanceState(state);
public BubbleNavigationLinearView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}

/////////////////////////////////////////
// PRIVATE METHODS
/////////////////////////////////////////

/**
* Initialize
*
* @param context current context
* @param attrs custom attributes
*/
private void init(Context context, AttributeSet attrs) {

public void init() {
setOrientation(HORIZONTAL);
setGravity(Gravity.CENTER);
}

post(new Runnable() {
@Override
public void run() {
updateChildNavItems();
}
});
}

/**
* Finds Child Elements of type {@link BubbleToggleView} and adds them to {@link #bubbleNavItems}
*/
private void updateChildNavItems() {
bubbleNavItems = new ArrayList<>();
for (int index = 0; index < getChildCount(); ++index) {
View view = getChildAt(index);
if (view instanceof BubbleToggleView)
bubbleNavItems.add((BubbleToggleView) view);
else {
Log.w(TAG, "Cannot have child bubbleNavItems other than BubbleToggleView");
return;
}
}

if (bubbleNavItems.size() < MIN_ITEMS) {
Log.w(TAG, "The bubbleNavItems list should have at least 2 bubbleNavItems of BubbleToggleView");
} else if (bubbleNavItems.size() > MAX_ITEMS) {
Log.w(TAG, "The bubbleNavItems list should not have more than 5 bubbleNavItems of BubbleToggleView");
}

protected void onFinishInflate() {
super.onFinishInflate();
checkViewsAreAllBubble();
setClickListenerForItems();
setInitialActiveState();
refreshActiveState();
updateMeasurementForItems();
}

/**
* Makes sure that ONLY ONE child {@link #bubbleNavItems} is active
*/
private void setInitialActiveState() {
private void refreshActiveState() {
boolean foundActiveElement = false;
for (int i = 0; i < bubbleNavItems.size(); i++) {
if (bubbleNavItems.get(i).isActive() && !foundActiveElement) {
for (int i=0;i<this.getChildCount();++i) {
BubbleToggleView btv = (BubbleToggleView)getChildAt(i);
if (btv.isActive() && !foundActiveElement) {
foundActiveElement = true;
currentActiveItemPosition = i;
this.currentActiveItemPosition = i;
} else {
bubbleNavItems.get(i).setInitialState(false);
btv.setInitialState(false);
}
}

if (!foundActiveElement) {
bubbleNavItems.get(currentActiveItemPosition).setInitialState(true);
((BubbleToggleView)getChildAt(currentActiveItemPosition)).setInitialState(true);
}
}

/**
* Update the measurements of the child components {@link #bubbleNavItems}
*/
private void updateMeasurementForItems() {
int numChildElements = bubbleNavItems.size();
if (numChildElements > 0) {
int calculatedEachItemWidth = (getMeasuredWidth() - (getPaddingRight() + getPaddingLeft())) / numChildElements;
for (BubbleToggleView btv : bubbleNavItems)
btv.updateMeasurements(calculatedEachItemWidth);
int numChildViews = getChildCount();
if(numChildViews > 0) {
int calculatedEachItemWidth = (getMeasuredWidth() - (getPaddingRight() + getPaddingLeft())) / numChildViews;
for(int i=0;i<numChildViews;++i) {
((BubbleToggleView)getChildAt(i)).updateMeasurements(calculatedEachItemWidth);
}
}
}

/**
* Sets {@link android.view.View.OnClickListener} for the child views
*/
private void checkViewsAreAllBubble() {
for( int i=0;i<getChildCount();++i) {
View view = this.getChildAt(i);
final boolean wrongView = !(view instanceof BubbleToggleView);
if(wrongView) {
throw new IllegalStateException("only BubbleToggles are allowed");
}
}
}


private void setClickListenerForItems() {
for (BubbleToggleView btv : bubbleNavItems)
btv.setOnClickListener(this);
for(int i=0;i<getChildCount();++i) {
((BubbleToggleView)getChildAt(i)).setOnClickListener(this);
}
}

/**
* Gets the Position of the Child from {@link #bubbleNavItems} from its id
*
* @param id of view to be searched
* @return position of the Item
*/
private int getItemPositionById(int id) {
for (int i = 0; i < bubbleNavItems.size(); i++)
if (id == bubbleNavItems.get(i).getId())
for(int i=0;i<getChildCount();++i) {
if(id == this.getChildAt(i).getId()) {
return i;
}
}
return -1;
}

///////////////////////////////////////////
// PUBLIC METHODS
///////////////////////////////////////////

/**
* Set the navigation change listener {@link BubbleNavigationChangeListener}
*
* @param navigationChangeListener sets the passed parameters as listener
*/
public void setNavigationChangeListener(BubbleNavigationChangeListener navigationChangeListener) {
this.navigationChangeListener = navigationChangeListener;
public void setNavigationChangeListener(BubbleNavigationChangeListener listener) {
this.navigationChangeListener = listener;
this.navigationChangeListener.onNavigationChanged(this.getChildAt(currentActiveItemPosition),this.currentActiveItemPosition);
}

/**
* Set the {@link Typeface} for the Text Elements of the View
*
* @param typeface to be used
*/
public void setTypeface(Typeface typeface) {
for (BubbleToggleView btv : bubbleNavItems)
btv.setTitleTypeface(typeface);
for(int i=0;i<getChildCount();++i) {
final BubbleToggleView view = (BubbleToggleView)getChildAt(i);
view.setTitleTypeface(typeface);
}
}

/**
* Gets the current active position
*
* @return active item position
*/
public int getCurrentActiveItemPosition() {
return currentActiveItemPosition;
}

/**
* Sets the current active item
*
* @param position current position change
*/
public void setCurrentActiveItem(int position) {
if (currentActiveItemPosition == position) return;
if (position < 0 || position >= bubbleNavItems.size())
return;
BubbleToggleView btv = bubbleNavItems.get(position);
if(currentActiveItemPosition == position) return;
if(position < 0 || position >= this.getChildCount()) {
return ;
}
BubbleToggleView btv = (BubbleToggleView)this.getChildAt(position);
btv.performClick();
}

@Override
public void onClick(View v) {
int changedPosition = getItemPositionById(v.getId());
if (changedPosition >= 0) {
if (changedPosition == currentActiveItemPosition) {
return;
}
BubbleToggleView currentActiveToggleView = bubbleNavItems.get(currentActiveItemPosition);
BubbleToggleView newActiveToggleView = bubbleNavItems.get(changedPosition);
if (currentActiveToggleView != null)
currentActiveToggleView.toggle();
if (newActiveToggleView != null)
newActiveToggleView.toggle();

BubbleToggleView currentActiveToggleView = (BubbleToggleView)this.getChildAt(currentActiveItemPosition);
BubbleToggleView newActiveToggleView = (BubbleToggleView)this.getChildAt(changedPosition);
currentActiveToggleView.toggle();
newActiveToggleView.toggle();
//changed the current active position
currentActiveItemPosition = changedPosition;

if (navigationChangeListener != null)
navigationChangeListener.onNavigationChanged(v, currentActiveItemPosition);
navigationChangeListener.onNavigationChanged(v, currentActiveItemPosition);
} else {
Log.w(TAG, "Selected id not found! Cannot toggle");
}
}

public void onSaveInstanceState(Bundle bundle) {
bundle.putInt(CURRENT_ACTIVE_VIEW,currentActiveItemPosition);
}

public void onRestoreInstanceState(Bundle bundle) {
int currentActiveView = bundle.getInt(CURRENT_ACTIVE_VIEW,0);
setCurrentActiveItem(currentActiveView);
}
}