Skip to content

fix(tabs): correctly calculate sizing and animation positions #385

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 9, 2022
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ class TabStrip extends LinearLayout {

private final int mDefaultBottomBorderColor;

// selected tab position (final)
private int mSelectedPosition;
// current tab position for when the view is animating (scrolling)
private int mSelectionTabPosition;
// scrolling offset in relation to the current tab position
private float mSelectionOffset;

private final SimpleTabColorizer mDefaultTabColorizer;
Expand Down Expand Up @@ -173,6 +177,7 @@ private void updateTabsTextFontSize(){


void onTabsViewPagerPageChanged(int position, float positionOffset) {
mSelectionTabPosition = position;
mSelectionOffset = positionOffset;
invalidate();
}
Expand Down Expand Up @@ -206,24 +211,30 @@ protected void dispatchDraw(Canvas canvas) {
final SimpleTabColorizer tabColorizer = mDefaultTabColorizer;

// Thick colored underline below the current selection
if (childCount > 0 && mSelectedPosition < childCount) {
View selectedTitle = getChildAt(mSelectedPosition);
if (childCount > 0 && mSelectionTabPosition < childCount) {
View selectedTitle = getChildAt(mSelectionTabPosition);
int left = selectedTitle.getLeft();
int width = selectedTitle.getWidth();
int right = selectedTitle.getRight();
int color = tabColorizer.getIndicatorColor(mSelectedPosition);

if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) {
int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1);
int color = tabColorizer.getIndicatorColor(mSelectionTabPosition);
int nextTab = mSelectionTabPosition + 1;

// we're always at mSelectionTabPosition + mSelectionOffset (ex: 1 + 0.5)
// if we mSelectionOffset > 0f then we need to mutate the position, width and color of the selection
// if we're on the last tab, nextTab will be getChildCount() + 1 so it won't enter as there's nothing to animate
if (mSelectionOffset > 0f && nextTab >= 0 && nextTab < getChildCount()) {
int nextColor = tabColorizer.getIndicatorColor(nextTab);
if (color != nextColor) {
color = blendColors(nextColor, color, mSelectionOffset);
}

// Draw the selection partway between the tabs
View nextTitle = getChildAt(mSelectedPosition + 1);
left = (int) (mSelectionOffset * nextTitle.getLeft() +
(1.0f - mSelectionOffset) * left);
right = (int) (mSelectionOffset * nextTitle.getRight() +
(1.0f - mSelectionOffset) * right);
View nextTitle = getChildAt(nextTab);
// left is the current tab left + it's width * mSelectionOffset ex: 0 + (100 * 0.5) = 50, halfway through the current cell
left = (int) (left + mSelectionOffset * width);
// right is the tab right + the next tab's width * mSelectionOffset ex: 100 + (200 * 0.5) = 200, halfway through the next cell
// this ensures that the width mutates smoothly as we move between cells
right = (int) (right + mSelectionOffset * nextTitle.getWidth());
}

mSelectedIndicatorPaint.setColor(color);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ public void setCustomTabColorizer(TabColorizer tabColorizer) {

public void setDistributeEvenly(boolean distributeEvenly) {
mDistributeEvenly = distributeEvenly;
mTabStrip.setMeasureWithLargestChildEnabled(distributeEvenly);
refreshTabStrip();
}

/**
Expand Down Expand Up @@ -300,10 +302,13 @@ private void setupItem(LinearLayout ll, TextView textView,ImageView imgView, Tab
ll.setMinimumHeight((int) (SMALL_MIN_HEIGHT * density));
}

LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) ll.getLayoutParams();
if (mDistributeEvenly) {
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) ll.getLayoutParams();
lp.width = 0;
lp.weight = 1;
} else {
lp.width = ViewGroup.LayoutParams.WRAP_CONTENT;
lp.weight = 0;
}
}

Expand Down Expand Up @@ -355,6 +360,21 @@ private void populateTabStrip() {
}
}

private void refreshTabStrip() {
final FragmentStateAdapter adapter = (FragmentStateAdapter)mViewPager.getAdapter();
for (int i = 0; i < adapter.getItemCount(); i++) {
TabItemSpec tabItem;
if (this.mTabItems != null && this.mTabItems.length > i) {
tabItem = this.mTabItems[i];
} else {
tabItem = new TabItemSpec();
}
if (i < mTabStrip.getChildCount()) {
this.updateItemAt(i, tabItem);
}
}
}

public void setContentDescription(int i, String desc) {
mContentDescriptions.put(i, desc);
}
Expand Down