android TabLayout Indicator Width Problem

  • 2021-08-31 09:13:09
  • OfStack

Recently encountered a demand, because I am more interested in TabLayout, so record 1.

Product requirements: I hope the width of the indicator in the upper navigation bar is slightly larger than the width of the text; Technical scheme: TabLayout cooperates with ViewPager;; Problem analysis: The indicator width of the native TabLayout is equal to the width of each tab, which is much larger than the width of the text title in tab.

Cause analysis:

TabLayout (TL) inherits from HorizontalScrollView, and can only add one child control. This child control is the private class SlidingTabStrip inside TL, which inherits from LinearLayout. How did you add the indicator? It is in the onDraw method of this class:


 @Override
public void draw(Canvas canvas) {
 super.draw(canvas);
 // Thick colored underline below the current selection
 if (mIndicatorLeft >= 0 && 
 mIndicatorRight > mIndicatorLeft) {
  canvas.drawRect(mIndicatorLeft, 
 mIndicatorRight, getHeight(), 
 mSelectedIndicatorPaint);
 }
}

That is, the indicator exists with this SlidingTabStrip container, Its width is determined by mIndicatorLeft and mIndicatorRight, And these two, Depending on the width of tab, Because this article will not describe the source code of TL in detail, Therefore, the conclusion is directly reported here: The width setting of this indicator is determined by the width of tab, while tab is controlled by weight in linearLayout under the condition of mode=fix. Therefore, it is impossible to influence the width of the indicator through the width of tab. By comparison, the source code does not set an Margin for tab. In addition, the source code does not expose set and other methods to change the width of the indicator, otherwise it will not have this problem.

Solution 1:

Baidu's scheme basically focuses on reflection, which is troublesome to use and sometimes difficult to use.

This idea comes from stackoverflow. The general process is that TL gets its only 1 subclass, that is, SlidingTabStrip, then traverses and gets its sub-View, and then sets Margin for each sub-View, which is equivalent to setting margin for each tab, so the width of the indicator naturally changes accordingly. show code:


public static void reduceMarginsInTabs(TabLayout tabLayout, int marginOffset) {
  View tabStrip = tabLayout.getChildAt(0);
  if (tabStrip instanceof ViewGroup) {
   ViewGroup tabStripGroup = (ViewGroup) tabStrip;
   for (int i = 0; i < ((ViewGroup) tabStrip).getChildCount(); i++) {
    View tabView = tabStripGroup.getChildAt(i);
    if (tabView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
     ((ViewGroup.MarginLayoutParams) tabView.getLayoutParams()).leftMargin = marginOffset;
     ((ViewGroup.MarginLayoutParams) tabView.getLayoutParams()).rightMargin = marginOffset;
    }
   }
  tabLayout.requestLayout();
  }
 }

The limitation of this method is that the indicator can only be as wide as tab at most, and the width of the indicator cannot be continuously reduced.

Solution 2:

This scheme belongs to custom indicator display, which is relatively flexible and can solve the problem of tab equal width in scheme 1, but its disadvantage is that it cannot keep the animation of indicator. Specific process:

Custom view can be set for tab in TL by setCustomView (@ Nullable View view), that is to say, the layout can be customized directly without the set in TL. In the tab source code update method has such a sentence:


 mCustomTextView = (TextView) custom.findViewById(android.R.id.text1);
 if (mCustomTextView != null) {
  mDefaultMaxLines = TextViewCompat.getMaxLines(mCustomTextView);
 }
 mCustomIconView = (ImageView) custom.findViewById(android.R.id.icon);

android. R. id. text1 and android. R. id. icon in TL are id of two view that can change their state with sliding. When we customize, we can make the corresponding view set id in the same way. The indicator, which can shield the native TL, can be directly placed at the appropriate position of the custom layout, and just add an view.


Related articles: