From 2fc2e6a167213e7b7f0f1491120b212132972543 Mon Sep 17 00:00:00 2001
From: pekingme <8545955+pekingme@users.noreply.github.com>
Date: Tue, 21 Jun 2022 19:25:23 +0000
Subject: [PATCH] [Tab] Fixed indicator not updating when a tab to the
start/left of the selected tab is removed.
PiperOrigin-RevId: 456322731
---
.../tabs/TabsScrollableDemoFragment.java | 17 +++++--
.../layout/cat_tabs_scrollable_fragment.xml | 16 +++++--
.../catalog/tabs/res/values/strings.xml | 2 +
.../android/material/tabs/TabLayout.java | 45 +++++--------------
4 files changed, 39 insertions(+), 41 deletions(-)
diff --git a/catalog/java/io/material/catalog/tabs/TabsScrollableDemoFragment.java b/catalog/java/io/material/catalog/tabs/TabsScrollableDemoFragment.java
index f011cc7219c..09535d5e324 100644
--- a/catalog/java/io/material/catalog/tabs/TabsScrollableDemoFragment.java
+++ b/catalog/java/io/material/catalog/tabs/TabsScrollableDemoFragment.java
@@ -18,6 +18,8 @@
import io.material.catalog.R;
+import static java.lang.Math.max;
+
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@@ -87,14 +89,23 @@ public View onCreateDemoView(
numTabs++;
});
- Button removeButton = view.findViewById(R.id.remove_tab_button);
- removeButton.setOnClickListener(
+ Button removeFirstButton = view.findViewById(R.id.remove_first_tab_button);
+ removeFirstButton.setOnClickListener(
+ v -> {
+ if (scrollableTabLayout.getTabCount() > 0) {
+ scrollableTabLayout.removeTabAt(0);
+ }
+ numTabs = max(0, numTabs - 1);
+ });
+
+ Button removeLastButton = view.findViewById(R.id.remove_last_tab_button);
+ removeLastButton.setOnClickListener(
v -> {
Tab tab = scrollableTabLayout.getTabAt(scrollableTabLayout.getTabCount() - 1);
if (tab != null) {
scrollableTabLayout.removeTab(tab);
}
- numTabs = Math.max(0, numTabs - 1);
+ numTabs = max(0, numTabs - 1);
});
return view;
}
diff --git a/catalog/java/io/material/catalog/tabs/res/layout/cat_tabs_scrollable_fragment.xml b/catalog/java/io/material/catalog/tabs/res/layout/cat_tabs_scrollable_fragment.xml
index bd7ad4b74af..6c2a5c6e67b 100644
--- a/catalog/java/io/material/catalog/tabs/res/layout/cat_tabs_scrollable_fragment.xml
+++ b/catalog/java/io/material/catalog/tabs/res/layout/cat_tabs_scrollable_fragment.xml
@@ -32,6 +32,14 @@
android:layout_marginBottom="@dimen/cat_tabs_standard_spacing"
android:orientation="vertical">
+
+
+ android:text="@string/cat_tabs_remove_first_tab_button_label" />
+ android:text="@string/cat_tabs_remove_last_tab_button_label" />
diff --git a/catalog/java/io/material/catalog/tabs/res/values/strings.xml b/catalog/java/io/material/catalog/tabs/res/values/strings.xml
index a4f6740e7ec..3c3203e1303 100644
--- a/catalog/java/io/material/catalog/tabs/res/values/strings.xml
+++ b/catalog/java/io/material/catalog/tabs/res/values/strings.xml
@@ -45,6 +45,8 @@
Material Tabs (Secondary)Add TabRemove Tab
+ Remove First Tab
+ Remove Last TabControllable Tabs DemoScrollable Tabs DemoAuto Tabs Demo
diff --git a/lib/java/com/google/android/material/tabs/TabLayout.java b/lib/java/com/google/android/material/tabs/TabLayout.java
index fb08d516c92..7fd5e4bb684 100644
--- a/lib/java/com/google/android/material/tabs/TabLayout.java
+++ b/lib/java/com/google/android/material/tabs/TabLayout.java
@@ -25,8 +25,6 @@
import static com.google.android.material.animation.AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR;
import static com.google.android.material.theme.overlay.MaterialThemeOverlay.wrap;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
@@ -3007,10 +3005,6 @@ private float approximateLineWidth(@NonNull Layout layout, int line, float textS
class SlidingTabIndicator extends LinearLayout {
ValueAnimator indicatorAnimator;
- int selectedPosition = -1;
- // selectionOffset is only used when a tab is being slid due to a viewpager swipe.
- // selectionOffset is always the offset to the right of selectedPosition.
- float selectionOffset;
private int layoutDirection = -1;
@@ -3038,26 +3032,21 @@ boolean childrenNeedLayout() {
/**
* Set the indicator position based on an offset between two adjacent tabs.
*
- * @param position The position from which the offset should be calculated.
- * @param positionOffset The offset to the right of position where the indicator should be
- * drawn. This must be a value between 0.0 and 1.0.
+ * @param position Position index of the first tab (with less index) currently being displayed.
+ * Tab position+1 will be visible if positionOffset is nonzero.
+ * @param positionOffset Value from [0, 1) indicating the offset from the tab at position.
*/
void setIndicatorPositionFromTabPosition(int position, float positionOffset) {
if (indicatorAnimator != null && indicatorAnimator.isRunning()) {
indicatorAnimator.cancel();
}
- selectedPosition = position;
- selectionOffset = positionOffset;
+ // The title view refers to the one indicated when offset is 0.
+ final View firstTitle = getChildAt(position);
+ // The title view refers to the one indicated when offset is 1.
+ final View nextTitle = getChildAt(position + 1);
- final View selectedTitle = getChildAt(selectedPosition);
- final View nextTitle = getChildAt(selectedPosition + 1);
-
- tweenIndicatorPosition(selectedTitle, nextTitle, selectionOffset);
- }
-
- float getIndicatorPosition() {
- return selectedPosition + selectionOffset;
+ tweenIndicatorPosition(firstTitle, nextTitle, positionOffset);
}
@Override
@@ -3144,7 +3133,7 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) {
// position of the indicator, since the tab widths are different. We need to modify the
// animation's updateListener to pick up the new target positions.
updateOrRecreateIndicatorAnimation(
- /* recreateAnimation= */ false, selectedPosition, /* duration= */ -1);
+ /* recreateAnimation= */ false, getSelectedTabPosition(), /* duration= */ -1);
} else {
// If we've been laid out, update the indicator position
jumpIndicatorToSelectedPosition();
@@ -3153,7 +3142,7 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) {
/** Immediately update the indicator position to the currently selected position. */
private void jumpIndicatorToSelectedPosition() {
- final View currentView = getChildAt(selectedPosition);
+ final View currentView = getChildAt(getSelectedTabPosition());
tabIndicatorInterpolator.setIndicatorBoundsForTab(
TabLayout.this, currentView, tabSelectedIndicator);
}
@@ -3214,7 +3203,7 @@ void animateIndicatorToPosition(final int position, int duration) {
*/
private void updateOrRecreateIndicatorAnimation(
boolean recreateAnimation, final int position, int duration) {
- final View currentView = getChildAt(selectedPosition);
+ final View currentView = getChildAt(getSelectedTabPosition());
final View targetView = getChildAt(position);
if (targetView == null) {
// If we don't have a view, just update the position now and return
@@ -3239,18 +3228,6 @@ public void onAnimationUpdate(@NonNull ValueAnimator valueAnimator) {
animator.setDuration(duration);
animator.setFloatValues(0F, 1F);
animator.addUpdateListener(updateListener);
- animator.addListener(
- new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animator) {
- selectedPosition = position;
- }
-
- @Override
- public void onAnimationEnd(Animator animator) {
- selectedPosition = position;
- }
- });
animator.start();
} else {
// Reuse the existing animator. Updating the listener only modifies the target positions.