喜马拉雅效果图:

 

我的效果图:

 

 

 

 //以下代码实现: 

//第一步:新建CustomTabLayout类继承HorizontalScrollView,自定义实现TabLayout需要的效果,注意将本类里com.gang.app.myceshi.customtab,是我项目里的包名,全部替换成你自己的。整体代码:

 

 

/** Copyright (C) 2015 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.gang.app.myceshi.customtab;import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.annotation.DrawableRes;
import android.support.annotation.IntDef;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.Px;
import android.support.annotation.RestrictTo;
import android.support.annotation.StringRes;
import android.support.v4.util.Pools;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.PointerIconCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPager;
import android.support.v4.widget.TextViewCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.content.res.AppCompatResources;
import android.support.v7.widget.TooltipCompat;
import android.text.Layout;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.SoundEffectConstants;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
import static android.support.v4.view.ViewPager.SCROLL_STATE_DRAGGING;
import static android.support.v4.view.ViewPager.SCROLL_STATE_IDLE;
import static android.support.v4.view.ViewPager.SCROLL_STATE_SETTLING;/*** TabLayout provides a horizontal layout to display tabs.** <p>Population of the tabs to display is* done through {@link Tab} instances. You create tabs via {@link #newTab()}. From there you can* change the tab's label or icon via {@link Tab#setText(int)} and {@link Tab#setIcon(int)}* respectively. To display the tab, you need to add it to the layout via one of the* {@link #addTab(Tab)} methods. For example:* <pre>* TabLayout tabLayout = ...;* tabLayout.addTab(tabLayout.newTab().setText("Tab 1"));* tabLayout.addTab(tabLayout.newTab().setText("Tab 2"));* tabLayout.addTab(tabLayout.newTab().setText("Tab 3"));* </pre>* You should set a listener via {@link #setOnTabSelectedListener(OnTabSelectedListener)} to be* notified when any tab's selection state has been changed.** <p>You can also add items to TabLayout in your layout through the use of {@link TabItem}.* An example usage is like so:</p>** <pre>* &lt;android.support.design.widget.TabLayout*         android:layout_height=&quot;wrap_content&quot;*         android:layout_width=&quot;match_parent&quot;&gt;**     &lt;android.support.design.widget.TabItem*             android:text=&quot;@string/tab_text&quot;/&gt;**     &lt;android.support.design.widget.TabItem*             android:icon=&quot;@drawable/ic_android&quot;/&gt;** &lt;/android.support.design.widget.TabLayout&gt;* </pre>** <h3>ViewPager integration</h3>* <p>* If you're using a {@link ViewPager} together* with this layout, you can call {@link #setupWithViewPager(ViewPager)} to link the two together.* This layout will be automatically populated from the {@link PagerAdapter}'s page titles.</p>** <p>* This view also supports being used as part of a ViewPager's decor, and can be added* directly to the ViewPager in a layout resource file like so:</p>** <pre>* &lt;android.support.v4.view.ViewPager*     android:layout_width=&quot;match_parent&quot;*     android:layout_height=&quot;match_parent&quot;&gt;**     &lt;android.support.design.widget.TabLayout*         android:layout_width=&quot;match_parent&quot;*         android:layout_height=&quot;wrap_content&quot;*         android:layout_gravity=&quot;top&quot; /&gt;** &lt;/android.support.v4.view.ViewPager&gt;* </pre>** @attr ref android.support.design.R.styleable#TabLayout_tabPadding* @attr ref android.support.design.R.styleable#TabLayout_tabPaddingStart* @attr ref android.support.design.R.styleable#TabLayout_tabPaddingTop* @attr ref android.support.design.R.styleable#TabLayout_tabPaddingEnd* @attr ref android.support.design.R.styleable#TabLayout_tabPaddingBottom* @attr ref android.support.design.R.styleable#TabLayout_tabContentStart* @attr ref android.support.design.R.styleable#TabLayout_tabBackground* @attr ref android.support.design.R.styleable#TabLayout_tabMinWidth* @attr ref android.support.design.R.styleable#TabLayout_tabMaxWidth* @attr ref android.support.design.R.styleable#TabLayout_tabTextAppearance* @see <a href="http://www.google.com/design/spec/components/tabs.html">Tabs</a>*/
@ViewPager.DecorView
public class CustomTabLayout extends HorizontalScrollView {private static final int DEFAULT_HEIGHT_WITH_TEXT_ICON = 72; // dpsstatic final int DEFAULT_GAP_TEXT_ICON = 8; // dpsprivate static final int INVALID_WIDTH = -1;private static final int DEFAULT_HEIGHT = 48; // dpsprivate static final int TAB_MIN_WIDTH_MARGIN = 56; //dpsstatic final int FIXED_WRAP_GUTTER_MIN = 16; //dpsstatic final int MOTION_NON_ADJACENT_OFFSET = 24;private static final int ANIMATION_DURATION = 300;private static final Pools.Pool<Tab> sTabPool = new Pools.SynchronizedPool<>(16);/*** Scrollable tabs display a subset of tabs at any given moment, and can contain longer tab* labels and a larger number of tabs. They are best used for browsing contexts in touch* interfaces when users don’t need to directly compare the tab labels.** @see #setTabMode(int)* @see #getTabMode()*/public static final int MODE_SCROLLABLE = 0;/*** Fixed tabs display all tabs concurrently and are best used with content that benefits from* quick pivots between tabs. The maximum number of tabs is limited by the view’s width.* Fixed tabs have equal width, based on the widest tab label.** @see #setTabMode(int)* @see #getTabMode()*/public static final int MODE_FIXED = 1;/*** @hide*/@RestrictTo(LIBRARY_GROUP)@IntDef(value = {MODE_SCROLLABLE, MODE_FIXED})@Retention(RetentionPolicy.SOURCE)public @interface Mode {}/*** Gravity used to fill the {@link CustomTabLayout} as much as possible. This option only takes effect* when used with {@link #MODE_FIXED}.** @see #setTabGravity(int)* @see #getTabGravity()*/public static final int GRAVITY_FILL = 0;/*** Gravity used to lay out the tabs in the center of the {@link CustomTabLayout}.** @see #setTabGravity(int)* @see #getTabGravity()*/public static final int GRAVITY_CENTER = 1;/*** @hide*/@RestrictTo(LIBRARY_GROUP)@IntDef(flag = true, value = {GRAVITY_FILL, GRAVITY_CENTER})@Retention(RetentionPolicy.SOURCE)public @interface TabGravity {}/*** Callback interface invoked when a tab's selection state changes.*/public interface OnTabSelectedListener {/*** Called when a tab enters the selected state.** @param tab The tab that was selected*/public void onTabSelected(Tab tab);/*** Called when a tab exits the selected state.** @param tab The tab that was unselected*/public void onTabUnselected(Tab tab);/*** Called when a tab that is already selected is chosen again by the user. Some applications* may use this action to return to the top level of a category.** @param tab The tab that was reselected.*/public void onTabReselected(Tab tab);}private final ArrayList<Tab> mTabs = new ArrayList<>();private Tab mSelectedTab;private final SlidingTabStrip mTabStrip;int mTabPaddingStart;int mTabPaddingTop;int mTabPaddingEnd;int mTabPaddingBottom;int mTabTextAppearance;ColorStateList mTabTextColors;float mTabTextSize;float mTabTextMultiLineSize;final int mTabBackgroundResId;int mTabMaxWidth = Integer.MAX_VALUE;private final int mRequestedTabMinWidth;private final int mRequestedTabMaxWidth;private final int mScrollableTabMinWidth;private int mContentInsetStart;int mTabGravity;int mMode;private OnTabSelectedListener mSelectedListener;private final ArrayList<OnTabSelectedListener> mSelectedListeners = new ArrayList<>();private OnTabSelectedListener mCurrentVpSelectedListener;private ValueAnimator mScrollAnimator;ViewPager mViewPager;private PagerAdapter mPagerAdapter;private DataSetObserver mPagerAdapterObserver;private TabLayoutOnPageChangeListener mPageChangeListener;private AdapterChangeListener mAdapterChangeListener;private boolean mSetupViewPagerImplicitly;// Pool we use as a simple RecyclerBinprivate final Pools.Pool<TabView> mTabViewPool = new Pools.SimplePool<>(12);public CustomTabLayout(Context context) {this(context, null);}public CustomTabLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public CustomTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);ThemeUtils.checkAppCompatTheme(context);// Disable the Scroll BarsetHorizontalScrollBarEnabled(false);// Add the TabStripmTabStrip = new SlidingTabStrip(context);super.addView(mTabStrip, 0, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));TypedArray a = context.obtainStyledAttributes(attrs, android.support.design.R.styleable.TabLayout,defStyleAttr, android.support.design.R.style.Widget_Design_TabLayout);mTabStrip.setSelectedIndicatorHeight(a.getDimensionPixelSize(android.support.design.R.styleable.TabLayout_tabIndicatorHeight, 0));mTabPaddingStart = mTabPaddingTop = mTabPaddingEnd = mTabPaddingBottom = a.getDimensionPixelSize(android.support.design.R.styleable.TabLayout_tabPadding, 0);mTabPaddingStart = a.getDimensionPixelSize(android.support.design.R.styleable.TabLayout_tabPaddingStart,mTabPaddingStart);mTabPaddingTop = a.getDimensionPixelSize(android.support.design.R.styleable.TabLayout_tabPaddingTop,mTabPaddingTop);mTabPaddingEnd = a.getDimensionPixelSize(android.support.design.R.styleable.TabLayout_tabPaddingEnd,mTabPaddingEnd);mTabPaddingBottom = a.getDimensionPixelSize(android.support.design.R.styleable.TabLayout_tabPaddingBottom,mTabPaddingBottom);mTabTextAppearance = a.getResourceId(android.support.design.R.styleable.TabLayout_tabTextAppearance,android.support.design.R.style.TextAppearance_Design_Tab);// Text colors/sizes come from the text appearance firstfinal TypedArray ta = context.obtainStyledAttributes(mTabTextAppearance,android.support.v7.appcompat.R.styleable.TextAppearance);try {mTabTextSize = ta.getDimensionPixelSize(android.support.v7.appcompat.R.styleable.TextAppearance_android_textSize, 0);mTabTextColors = ta.getColorStateList(android.support.v7.appcompat.R.styleable.TextAppearance_android_textColor);} finally {ta.recycle();}if (a.hasValue(android.support.design.R.styleable.TabLayout_tabTextColor)) {// If we have an explicit text color set, use it insteadmTabTextColors = a.getColorStateList(android.support.design.R.styleable.TabLayout_tabTextColor);}if (a.hasValue(android.support.design.R.styleable.TabLayout_tabSelectedTextColor)) {// We have an explicit selected text color set, so we need to make merge it with the// current colors. This is exposed so that developers can use theme attributes to set// this (theme attrs in ColorStateLists are Lollipop+)final int selected = a.getColor(android.support.design.R.styleable.TabLayout_tabSelectedTextColor, 0);mTabTextColors = createColorStateList(mTabTextColors.getDefaultColor(), selected);}mRequestedTabMinWidth = a.getDimensionPixelSize(android.support.design.R.styleable.TabLayout_tabMinWidth,INVALID_WIDTH);mRequestedTabMaxWidth = a.getDimensionPixelSize(android.support.design.R.styleable.TabLayout_tabMaxWidth,INVALID_WIDTH);mTabBackgroundResId = a.getResourceId(android.support.design.R.styleable.TabLayout_tabBackground, 0);mContentInsetStart = a.getDimensionPixelSize(android.support.design.R.styleable.TabLayout_tabContentStart, 0);mMode = a.getInt(android.support.design.R.styleable.TabLayout_tabMode, MODE_FIXED);mTabGravity = a.getInt(android.support.design.R.styleable.TabLayout_tabGravity, GRAVITY_FILL);a.recycle();TypedArray ma = context.obtainStyledAttributes(attrs,com.gang.app.myceshi.R.styleable.CustomTabLayout);int indicatorMarginStart = ma.getDimensionPixelSize(com.gang.app.myceshi.R.styleable.CustomTabLayout_indicatorMarginStart, 0);int indicatorMarginEnd = ma.getDimensionPixelSize(com.gang.app.myceshi.R.styleable.CustomTabLayout_indicatorMarginEnd, 0);int indicatorMarginBottom = ma.getDimensionPixelSize(com.gang.app.myceshi.R.styleable.CustomTabLayout_indicatorMarginBottom, 0);int indicatorStartColor = ma.getColor(com.gang.app.myceshi.R.styleable.CustomTabLayout_indicatorStartColor, 0);int indicatorEndColor = ma.getColor(com.gang.app.myceshi.R.styleable.CustomTabLayout_indicatorEndColor, 0);//设置tablayout左右滑动渐变色mTabStrip.setSelectedIndicatorColor(indicatorStartColor, indicatorEndColor);//设置tablayout下划线指示器距离左边与距离右边,剩下的就是tablayout下划线指示器的宽度mTabStrip.setSelectedIndicatorMargin(indicatorMarginStart, indicatorMarginEnd);//设置tablayout下划线指示器距离下边mTabStrip.setSelectedIndicatorMarginBottom(indicatorMarginBottom);ma.recycle();// TODO add attr for thesefinal Resources res = getResources();mTabTextMultiLineSize = res.getDimensionPixelSize(android.support.design.R.dimen.design_tab_text_size_2line);mScrollableTabMinWidth = res.getDimensionPixelSize(android.support.design.R.dimen.design_tab_scrollable_min_width);// Now apply the tab mode and gravityapplyModeAndGravity();}/*** Sets the tab indicator's color for the currently selected tab.** @param color color to use for the indicator* @attr ref android.support.design.R.styleable#TabLayout_tabIndicatorColor*/public void setSelectedTabIndicatorColor(@ColorInt int color) {mTabStrip.setSelectedIndicatorColor(color);}public void setSelectedTabIndicatorColor(@ColorInt int startColor, @ColorInt int endColor) {mTabStrip.setSelectedIndicatorColor(startColor, endColor);}/*** Sets the tab indicator's height for the currently selected tab.** @param height height to use for the indicator in pixels* @attr ref android.support.design.R.styleable#TabLayout_tabIndicatorHeight*/public void setSelectedTabIndicatorHeight(int height) {mTabStrip.setSelectedIndicatorHeight(height);}/*** Set the scroll position of the tabs. This is useful for when the tabs are being displayed as* part of a scrolling container such as {@link ViewPager}.* <p>* Calling this method does not update the selected tab, it is only used for drawing purposes.** @param position           current scroll position* @param positionOffset     Value from [0, 1) indicating the offset from {@code position}.* @param updateSelectedText Whether to update the text's selected state.*/public void setScrollPosition(int position, float positionOffset, boolean updateSelectedText) {setScrollPosition(position, positionOffset, updateSelectedText, true);}void setScrollPosition(int position, float positionOffset, boolean updateSelectedText,boolean updateIndicatorPosition) {final int roundedPosition = Math.round(position + positionOffset);if (roundedPosition < 0 || roundedPosition >= mTabStrip.getChildCount()) {return;}// Set the indicator position, if enabledif (updateIndicatorPosition) {mTabStrip.setIndicatorPositionFromTabPosition(position, positionOffset);}// Now update the scroll position, canceling any running animationif (mScrollAnimator != null && mScrollAnimator.isRunning()) {mScrollAnimator.cancel();}scrollTo(calculateScrollXForTab(position, positionOffset), 0);// Update the 'selected state' view as we scroll, if enabledif (updateSelectedText) {setSelectedTabView(roundedPosition);}}private float getScrollPosition() {return mTabStrip.getIndicatorPosition();}/*** Add a tab to this layout. The tab will be added at the end of the list.* If this is the first tab to be added it will become the selected tab.** @param tab Tab to add*/public void addTab(@NonNull Tab tab) {addTab(tab, mTabs.isEmpty());}/*** Add a tab to this layout. The tab will be inserted at <code>position</code>.* If this is the first tab to be added it will become the selected tab.** @param tab      The tab to add* @param position The new position of the tab*/public void addTab(@NonNull Tab tab, int position) {addTab(tab, position, mTabs.isEmpty());}/*** Add a tab to this layout. The tab will be added at the end of the list.** @param tab         Tab to add* @param setSelected True if the added tab should become the selected tab.*/public void addTab(@NonNull Tab tab, boolean setSelected) {addTab(tab, mTabs.size(), setSelected);}/*** Add a tab to this layout. The tab will be inserted at <code>position</code>.** @param tab         The tab to add* @param position    The new position of the tab* @param setSelected True if the added tab should become the selected tab.*/public void addTab(@NonNull Tab tab, int position, boolean setSelected) {if (tab.mParent != this) {throw new IllegalArgumentException("Tab belongs to a different TabLayout.");}configureTab(tab, position);addTabView(tab);if (setSelected) {tab.select();}}private void addTabFromItemView(@NonNull TabItem item) {final Tab tab = newTab();if (item.mText != null) {tab.setText(item.mText);}if (item.mIcon != null) {tab.setIcon(item.mIcon);}if (item.mCustomLayout != 0) {tab.setCustomView(item.mCustomLayout);}if (!TextUtils.isEmpty(item.getContentDescription())) {tab.setContentDescription(item.getContentDescription());}addTab(tab);}/*** @deprecated Use {@link #addOnTabSelectedListener(OnTabSelectedListener)} and* {@link #removeOnTabSelectedListener(OnTabSelectedListener)}.*/@Deprecatedpublic void setOnTabSelectedListener(@Nullable OnTabSelectedListener listener) {// The logic in this method emulates what we had before support for multiple// registered listeners.if (mSelectedListener != null) {removeOnTabSelectedListener(mSelectedListener);}// Update the deprecated field so that we can remove the passed listener the next// time we're calledmSelectedListener = listener;if (listener != null) {addOnTabSelectedListener(listener);}}/*** Add a {@link OnTabSelectedListener} that will be invoked when tab selection* changes.** <p>Components that add a listener should take care to remove it when finished via* {@link #removeOnTabSelectedListener(OnTabSelectedListener)}.</p>** @param listener listener to add*/public void addOnTabSelectedListener(@NonNull OnTabSelectedListener listener) {if (!mSelectedListeners.contains(listener)) {mSelectedListeners.add(listener);}}/*** Remove the given {@link OnTabSelectedListener} that was previously added via* {@link #addOnTabSelectedListener(OnTabSelectedListener)}.** @param listener listener to remove*/public void removeOnTabSelectedListener(@NonNull OnTabSelectedListener listener) {mSelectedListeners.remove(listener);}/*** Remove all previously added {@link OnTabSelectedListener}s.*/public void clearOnTabSelectedListeners() {mSelectedListeners.clear();}/*** Create and return a new {@link Tab}. You need to manually add this using* {@link #addTab(Tab)} or a related method.** @return A new Tab* @see #addTab(Tab)*/@NonNullpublic Tab newTab() {Tab tab = sTabPool.acquire();if (tab == null) {tab = new Tab();}tab.mParent = this;tab.mView = createTabView(tab);return tab;}/*** Returns the number of tabs currently registered with the action bar.** @return Tab count*/public int getTabCount() {return mTabs.size();}/*** Returns the tab at the specified index.*/@Nullablepublic Tab getTabAt(int index) {return (index < 0 || index >= getTabCount()) ? null : mTabs.get(index);}/*** Returns the position of the current selected tab.** @return selected tab position, or {@code -1} if there isn't a selected tab.*/public int getSelectedTabPosition() {return mSelectedTab != null ? mSelectedTab.getPosition() : -1;}/*** Remove a tab from the layout. If the removed tab was selected it will be deselected* and another tab will be selected if present.** @param tab The tab to remove*/public void removeTab(Tab tab) {if (tab.mParent != this) {throw new IllegalArgumentException("Tab does not belong to this TabLayout.");}removeTabAt(tab.getPosition());}/*** Remove a tab from the layout. If the removed tab was selected it will be deselected* and another tab will be selected if present.** @param position Position of the tab to remove*/public void removeTabAt(int position) {final int selectedTabPosition = mSelectedTab != null ? mSelectedTab.getPosition() : 0;removeTabViewAt(position);final Tab removedTab = mTabs.remove(position);if (removedTab != null) {removedTab.reset();sTabPool.release(removedTab);}final int newTabCount = mTabs.size();for (int i = position; i < newTabCount; i++) {mTabs.get(i).setPosition(i);}if (selectedTabPosition == position) {selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1)));}}/*** Remove all tabs from the action bar and deselect the current tab.*/public void removeAllTabs() {// Remove all the viewsfor (int i = mTabStrip.getChildCount() - 1; i >= 0; i--) {removeTabViewAt(i);}for (final Iterator<Tab> i = mTabs.iterator(); i.hasNext(); ) {final Tab tab = i.next();i.remove();tab.reset();sTabPool.release(tab);}mSelectedTab = null;}/*** Set the behavior mode for the Tabs in this layout. The valid input options are:* <ul>* <li>{@link #MODE_FIXED}: Fixed tabs display all tabs concurrently and are best used* with content that benefits from quick pivots between tabs.</li>* <li>{@link #MODE_SCROLLABLE}: Scrollable tabs display a subset of tabs at any given moment,* and can contain longer tab labels and a larger number of tabs. They are best used for* browsing contexts in touch interfaces when users don’t need to directly compare the tab* labels. This mode is commonly used with a {@link ViewPager}.</li>* </ul>** @param mode one of {@link #MODE_FIXED} or {@link #MODE_SCROLLABLE}.* @attr ref android.support.design.R.styleable#TabLayout_tabMode*/public void setTabMode(@Mode int mode) {if (mode != mMode) {mMode = mode;applyModeAndGravity();}}/*** Returns the current mode used by this {@link CustomTabLayout}.** @see #setTabMode(int)*/@Modepublic int getTabMode() {return mMode;}/*** Set the gravity to use when laying out the tabs.** @param gravity one of {@link #GRAVITY_CENTER} or {@link #GRAVITY_FILL}.* @attr ref android.support.design.R.styleable#TabLayout_tabGravity*/public void setTabGravity(@TabGravity int gravity) {if (mTabGravity != gravity) {mTabGravity = gravity;applyModeAndGravity();}}/*** The current gravity used for laying out tabs.** @return one of {@link #GRAVITY_CENTER} or {@link #GRAVITY_FILL}.*/@TabGravitypublic int getTabGravity() {return mTabGravity;}/*** Sets the text colors for the different states (normal, selected) used for the tabs.** @see #getTabTextColors()*/public void setTabTextColors(@Nullable ColorStateList textColor) {if (mTabTextColors != textColor) {mTabTextColors = textColor;updateAllTabs();}}/*** Gets the text colors for the different states (normal, selected) used for the tabs.*/@Nullablepublic ColorStateList getTabTextColors() {return mTabTextColors;}/*** Sets the text colors for the different states (normal, selected) used for the tabs.** @attr ref android.support.design.R.styleable#TabLayout_tabTextColor* @attr ref android.support.design.R.styleable#TabLayout_tabSelectedTextColor*/public void setTabTextColors(int normalColor, int selectedColor) {setTabTextColors(createColorStateList(normalColor, selectedColor));}/*** The one-stop shop for setting up this {@link CustomTabLayout} with a {@link ViewPager}.** <p>This is the same as calling {@link #setupWithViewPager(ViewPager, boolean)} with* auto-refresh enabled.</p>** @param viewPager the ViewPager to link to, or {@code null} to clear any previous link*/public void setupWithViewPager(@Nullable ViewPager viewPager) {setupWithViewPager(viewPager, true);}/*** The one-stop shop for setting up this {@link CustomTabLayout} with a {@link ViewPager}.** <p>This method will link the given ViewPager and this TabLayout together so that* changes in one are automatically reflected in the other. This includes scroll state changes* and clicks. The tabs displayed in this layout will be populated* from the ViewPager adapter's page titles.</p>** <p>If {@code autoRefresh} is {@code true}, any changes in the {@link PagerAdapter} will* trigger this layout to re-populate itself from the adapter's titles.</p>** <p>If the given ViewPager is non-null, it needs to already have a* {@link PagerAdapter} set.</p>** @param viewPager   the ViewPager to link to, or {@code null} to clear any previous link* @param autoRefresh whether this layout should refresh its contents if the given ViewPager's*                    content changes*/public void setupWithViewPager(@Nullable final ViewPager viewPager, boolean autoRefresh) {setupWithViewPager(viewPager, autoRefresh, false);}private void setupWithViewPager(@Nullable final ViewPager viewPager, boolean autoRefresh,boolean implicitSetup) {if (mViewPager != null) {// If we've already been setup with a ViewPager, remove us from itif (mPageChangeListener != null) {mViewPager.removeOnPageChangeListener(mPageChangeListener);}if (mAdapterChangeListener != null) {mViewPager.removeOnAdapterChangeListener(mAdapterChangeListener);}}if (mCurrentVpSelectedListener != null) {// If we already have a tab selected listener for the ViewPager, remove itremoveOnTabSelectedListener(mCurrentVpSelectedListener);mCurrentVpSelectedListener = null;}if (viewPager != null) {mViewPager = viewPager;// Add our custom OnPageChangeListener to the ViewPagerif (mPageChangeListener == null) {mPageChangeListener = new TabLayoutOnPageChangeListener(this);}mPageChangeListener.reset();viewPager.addOnPageChangeListener(mPageChangeListener);// Now we'll add a tab selected listener to set ViewPager's current itemmCurrentVpSelectedListener = new ViewPagerOnTabSelectedListener(viewPager);addOnTabSelectedListener(mCurrentVpSelectedListener);final PagerAdapter adapter = viewPager.getAdapter();if (adapter != null) {// Now we'll populate ourselves from the pager adapter, adding an observer if// autoRefresh is enabledsetPagerAdapter(adapter, autoRefresh);}// Add a listener so that we're notified of any adapter changesif (mAdapterChangeListener == null) {mAdapterChangeListener = new AdapterChangeListener();}mAdapterChangeListener.setAutoRefresh(autoRefresh);viewPager.addOnAdapterChangeListener(mAdapterChangeListener);// Now update the scroll position to match the ViewPager's current itemsetScrollPosition(viewPager.getCurrentItem(), 0f, true);} else {// We've been given a null ViewPager so we need to clear out the internal state,// listeners and observersmViewPager = null;setPagerAdapter(null, false);}mSetupViewPagerImplicitly = implicitSetup;}/*** @deprecated Use {@link #setupWithViewPager(ViewPager)} to link a TabLayout with a ViewPager* together. When that method is used, the TabLayout will be automatically updated* when the {@link PagerAdapter} is changed.*/@Deprecatedpublic void setTabsFromPagerAdapter(@Nullable final PagerAdapter adapter) {setPagerAdapter(adapter, false);}@Overridepublic boolean shouldDelayChildPressedState() {// Only delay the pressed state if the tabs can scrollreturn getTabScrollRange() > 0;}@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow();if (mViewPager == null) {// If we don't have a ViewPager already, check if our parent is a ViewPager to// setup with it automaticallyfinal ViewParent vp = getParent();if (vp instanceof ViewPager) {// If we have a ViewPager parent and we've been added as part of its decor, let's// assume that we should automatically setup to display any titlessetupWithViewPager((ViewPager) vp, true, true);}}}@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();if (mSetupViewPagerImplicitly) {// If we've been setup with a ViewPager implicitly, let's clear out any listeners, etcsetupWithViewPager(null);mSetupViewPagerImplicitly = false;}}private int getTabScrollRange() {return Math.max(0, mTabStrip.getWidth() - getWidth() - getPaddingLeft()- getPaddingRight());}void setPagerAdapter(@Nullable final PagerAdapter adapter, final boolean addObserver) {if (mPagerAdapter != null && mPagerAdapterObserver != null) {// If we already have a PagerAdapter, unregister our observermPagerAdapter.unregisterDataSetObserver(mPagerAdapterObserver);}mPagerAdapter = adapter;if (addObserver && adapter != null) {// Register our observer on the new adapterif (mPagerAdapterObserver == null) {mPagerAdapterObserver = new PagerAdapterObserver();}adapter.registerDataSetObserver(mPagerAdapterObserver);}// Finally make sure we reflect the new adapterpopulateFromPagerAdapter();}void populateFromPagerAdapter() {removeAllTabs();if (mPagerAdapter != null) {final int adapterCount = mPagerAdapter.getCount();for (int i = 0; i < adapterCount; i++) {addTab(newTab().setText(mPagerAdapter.getPageTitle(i)), false);}// Make sure we reflect the currently set ViewPager itemif (mViewPager != null && adapterCount > 0) {final int curItem = mViewPager.getCurrentItem();if (curItem != getSelectedTabPosition() && curItem < getTabCount()) {selectTab(getTabAt(curItem));}}}}private void updateAllTabs() {for (int i = 0, z = mTabs.size(); i < z; i++) {mTabs.get(i).updateView();}}private TabView createTabView(@NonNull final Tab tab) {TabView tabView = mTabViewPool != null ? mTabViewPool.acquire() : null;if (tabView == null) {tabView = new TabView(getContext());}tabView.setTab(tab);tabView.setFocusable(true);tabView.setMinimumWidth(getTabMinWidth());return tabView;}private void configureTab(Tab tab, int position) {tab.setPosition(position);mTabs.add(position, tab);final int count = mTabs.size();for (int i = position + 1; i < count; i++) {mTabs.get(i).setPosition(i);}}private void addTabView(Tab tab) {final TabView tabView = tab.mView;mTabStrip.addView(tabView, tab.getPosition(), createLayoutParamsForTabs());}@Overridepublic void addView(View child) {addViewInternal(child);}@Overridepublic void addView(View child, int index) {addViewInternal(child);}@Overridepublic void addView(View child, ViewGroup.LayoutParams params) {addViewInternal(child);}@Overridepublic void addView(View child, int index, ViewGroup.LayoutParams params) {addViewInternal(child);}private void addViewInternal(final View child) {if (child instanceof TabItem) {addTabFromItemView((TabItem) child);} else {throw new IllegalArgumentException("Only TabItem instances can be added to TabLayout");}}private LinearLayout.LayoutParams createLayoutParamsForTabs() {final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);updateTabViewLayoutParams(lp);return lp;}private void updateTabViewLayoutParams(LinearLayout.LayoutParams lp) {if (mMode == MODE_FIXED && mTabGravity == GRAVITY_FILL) {lp.width = 0;lp.weight = 1;} else {lp.width = LinearLayout.LayoutParams.WRAP_CONTENT;lp.weight = 0;}}int dpToPx(int dps) {return Math.round(getResources().getDisplayMetrics().density * dps);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// If we have a MeasureSpec which allows us to decide our height, try and use the default// heightfinal int idealHeight = dpToPx(getDefaultHeight()) + getPaddingTop() + getPaddingBottom();switch (MeasureSpec.getMode(heightMeasureSpec)) {case MeasureSpec.AT_MOST:heightMeasureSpec = MeasureSpec.makeMeasureSpec(Math.min(idealHeight, MeasureSpec.getSize(heightMeasureSpec)),MeasureSpec.EXACTLY);break;case MeasureSpec.UNSPECIFIED:heightMeasureSpec = MeasureSpec.makeMeasureSpec(idealHeight, MeasureSpec.EXACTLY);break;}final int specWidth = MeasureSpec.getSize(widthMeasureSpec);if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) {// If we don't have an unspecified width spec, use the given size to calculate// the max tab widthmTabMaxWidth = mRequestedTabMaxWidth > 0? mRequestedTabMaxWidth: specWidth - dpToPx(TAB_MIN_WIDTH_MARGIN);}// Now super measure itself using the (possibly) modified height specsuper.onMeasure(widthMeasureSpec, heightMeasureSpec);if (getChildCount() == 1) {// If we're in fixed mode then we need to make the tab strip is the same width as us// so we don't scrollfinal View child = getChildAt(0);boolean remeasure = false;switch (mMode) {case MODE_SCROLLABLE:// We only need to resize the child if it's smaller than us. This is similar// to fillViewportremeasure = child.getMeasuredWidth() < getMeasuredWidth();break;case MODE_FIXED:// Resize the child so that it doesn't scrollremeasure = child.getMeasuredWidth() != getMeasuredWidth();break;}if (remeasure) {// Re-measure the child with a widthSpec set to be exactly our measure widthint childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, getPaddingTop()+ getPaddingBottom(), child.getLayoutParams().height);int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY);child.measure(childWidthMeasureSpec, childHeightMeasureSpec);}}}private void removeTabViewAt(int position) {final TabView view = (TabView) mTabStrip.getChildAt(position);mTabStrip.removeViewAt(position);if (view != null) {view.reset();mTabViewPool.release(view);}requestLayout();}private void animateToTab(int newPosition) {if (newPosition == Tab.INVALID_POSITION) {return;}if (getWindowToken() == null || !ViewCompat.isLaidOut(this)|| mTabStrip.childrenNeedLayout()) {// If we don't have a window token, or we haven't been laid out yet just draw the new// position nowsetScrollPosition(newPosition, 0f, true);return;}final int startScrollX = getScrollX();final int targetScrollX = calculateScrollXForTab(newPosition, 0);if (startScrollX != targetScrollX) {ensureScrollAnimator();mScrollAnimator.setIntValues(startScrollX, targetScrollX);mScrollAnimator.start();}// Now animate the indicatormTabStrip.animateIndicatorToPosition(newPosition, ANIMATION_DURATION);}private void ensureScrollAnimator() {if (mScrollAnimator == null) {mScrollAnimator = new ValueAnimator();mScrollAnimator.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);mScrollAnimator.setDuration(ANIMATION_DURATION);mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animator) {scrollTo((int) animator.getAnimatedValue(), 0);}});}}void setScrollAnimatorListener(Animator.AnimatorListener listener) {ensureScrollAnimator();mScrollAnimator.addListener(listener);}private void setSelectedTabView(int position) {final int tabCount = mTabStrip.getChildCount();if (position < tabCount) {for (int i = 0; i < tabCount; i++) {final View child = mTabStrip.getChildAt(i);child.setSelected(i == position);}}}void selectTab(Tab tab) {selectTab(tab, true);}void selectTab(final Tab tab, boolean updateIndicator) {final Tab currentTab = mSelectedTab;if (currentTab == tab) {if (currentTab != null) {dispatchTabReselected(tab);animateToTab(tab.getPosition());}} else {final int newPosition = tab != null ? tab.getPosition() : Tab.INVALID_POSITION;if (updateIndicator) {if ((currentTab == null || currentTab.getPosition() == Tab.INVALID_POSITION)&& newPosition != Tab.INVALID_POSITION) {// If we don't currently have a tab, just draw the indicatorsetScrollPosition(newPosition, 0f, true);} else {animateToTab(newPosition);}if (newPosition != Tab.INVALID_POSITION) {setSelectedTabView(newPosition);}}if (currentTab != null) {dispatchTabUnselected(currentTab);}mSelectedTab = tab;if (tab != null) {dispatchTabSelected(tab);}}}private void dispatchTabSelected(@NonNull final Tab tab) {for (int i = mSelectedListeners.size() - 1; i >= 0; i--) {mSelectedListeners.get(i).onTabSelected(tab);}}private void dispatchTabUnselected(@NonNull final Tab tab) {for (int i = mSelectedListeners.size() - 1; i >= 0; i--) {mSelectedListeners.get(i).onTabUnselected(tab);}}private void dispatchTabReselected(@NonNull final Tab tab) {for (int i = mSelectedListeners.size() - 1; i >= 0; i--) {mSelectedListeners.get(i).onTabReselected(tab);}}private int calculateScrollXForTab(int position, float positionOffset) {if (mMode == MODE_SCROLLABLE) {final View selectedChild = mTabStrip.getChildAt(position);final View nextChild = position + 1 < mTabStrip.getChildCount()? mTabStrip.getChildAt(position + 1): null;final int selectedWidth = selectedChild != null ? selectedChild.getWidth() : 0;final int nextWidth = nextChild != null ? nextChild.getWidth() : 0;// base scroll amount: places center of tab in center of parentint scrollBase = selectedChild.getLeft() + (selectedWidth / 2) - (getWidth() / 2);// offset amount: fraction of the distance between centers of tabsint scrollOffset = (int) ((selectedWidth + nextWidth) * 0.5f * positionOffset);return (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_LTR)? scrollBase + scrollOffset: scrollBase - scrollOffset;}return 0;}private void applyModeAndGravity() {int paddingStart = 0;if (mMode == MODE_SCROLLABLE) {// If we're scrollable, or fixed at start, inset using paddingpaddingStart = Math.max(0, mContentInsetStart - mTabPaddingStart);}ViewCompat.setPaddingRelative(mTabStrip, paddingStart, 0, 0, 0);switch (mMode) {case MODE_FIXED:mTabStrip.setGravity(Gravity.CENTER_HORIZONTAL);break;case MODE_SCROLLABLE:mTabStrip.setGravity(GravityCompat.START);break;}updateTabViews(true);}void updateTabViews(final boolean requestLayout) {for (int i = 0; i < mTabStrip.getChildCount(); i++) {View child = mTabStrip.getChildAt(i);child.setMinimumWidth(getTabMinWidth());updateTabViewLayoutParams((LinearLayout.LayoutParams) child.getLayoutParams());if (requestLayout) {child.requestLayout();}}}/*** A tab in this layout. Instances can be created via {@link #newTab()}.*/public static final class Tab {/*** An invalid position for a tab.** @see #getPosition()*/public static final int INVALID_POSITION = -1;private Object mTag;private Drawable mIcon;private CharSequence mText;private CharSequence mContentDesc;private int mPosition = INVALID_POSITION;private View mCustomView;CustomTabLayout mParent;TabView mView;Tab() {// Private constructor}/*** @return This Tab's tag object.*/@Nullablepublic Object getTag() {return mTag;}/*** Give this Tab an arbitrary object to hold for later use.** @param tag Object to store* @return The current instance for call chaining*/@NonNullpublic Tab setTag(@Nullable Object tag) {mTag = tag;return this;}/*** Returns the custom view used for this tab.** @see #setCustomView(View)* @see #setCustomView(int)*/@Nullablepublic View getCustomView() {return mCustomView;}/*** Set a custom view to be used for this tab.* <p>* If the provided view contains a {@link TextView} with an ID of* {@link android.R.id#text1} then that will be updated with the value given* to {@link #setText(CharSequence)}. Similarly, if this layout contains an* {@link ImageView} with ID {@link android.R.id#icon} then it will be updated with* the value given to {@link #setIcon(Drawable)}.* </p>** @param view Custom view to be used as a tab.* @return The current instance for call chaining*/@NonNullpublic Tab setCustomView(@Nullable View view) {mCustomView = view;updateView();return this;}/*** Set a custom view to be used for this tab.* <p>* If the inflated layout contains a {@link TextView} with an ID of* {@link android.R.id#text1} then that will be updated with the value given* to {@link #setText(CharSequence)}. Similarly, if this layout contains an* {@link ImageView} with ID {@link android.R.id#icon} then it will be updated with* the value given to {@link #setIcon(Drawable)}.* </p>** @param resId A layout resource to inflate and use as a custom tab view* @return The current instance for call chaining*/@NonNullpublic Tab setCustomView(@LayoutRes int resId) {final LayoutInflater inflater = LayoutInflater.from(mView.getContext());return setCustomView(inflater.inflate(resId, mView, false));}/*** Return the icon associated with this tab.** @return The tab's icon*/@Nullablepublic Drawable getIcon() {return mIcon;}/*** Return the current position of this tab in the action bar.** @return Current position, or {@link #INVALID_POSITION} if this tab is not currently in* the action bar.*/public int getPosition() {return mPosition;}void setPosition(int position) {mPosition = position;}/*** Return the text of this tab.** @return The tab's text*/@Nullablepublic CharSequence getText() {return mText;}/*** Set the icon displayed on this tab.** @param icon The drawable to use as an icon* @return The current instance for call chaining*/@NonNullpublic Tab setIcon(@Nullable Drawable icon) {mIcon = icon;updateView();return this;}/*** Set the icon displayed on this tab.** @param resId A resource ID referring to the icon that should be displayed* @return The current instance for call chaining*/@NonNullpublic Tab setIcon(@DrawableRes int resId) {if (mParent == null) {throw new IllegalArgumentException("Tab not attached to a TabLayout");}return setIcon(AppCompatResources.getDrawable(mParent.getContext(), resId));}/*** Set the text displayed on this tab. Text may be truncated if there is not room to display* the entire string.** @param text The text to display* @return The current instance for call chaining*/@NonNullpublic Tab setText(@Nullable CharSequence text) {mText = text;updateView();return this;}/*** Set the text displayed on this tab. Text may be truncated if there is not room to display* the entire string.** @param resId A resource ID referring to the text that should be displayed* @return The current instance for call chaining*/@NonNullpublic Tab setText(@StringRes int resId) {if (mParent == null) {throw new IllegalArgumentException("Tab not attached to a TabLayout");}return setText(mParent.getResources().getText(resId));}/*** Select this tab. Only valid if the tab has been added to the action bar.*/public void select() {if (mParent == null) {throw new IllegalArgumentException("Tab not attached to a TabLayout");}mParent.selectTab(this);}/*** Returns true if this tab is currently selected.*/public boolean isSelected() {if (mParent == null) {throw new IllegalArgumentException("Tab not attached to a TabLayout");}return mParent.getSelectedTabPosition() == mPosition;}/*** Set a description of this tab's content for use in accessibility support. If no content* description is provided the title will be used.** @param resId A resource ID referring to the description text* @return The current instance for call chaining* @see #setContentDescription(CharSequence)* @see #getContentDescription()*/@NonNullpublic Tab setContentDescription(@StringRes int resId) {if (mParent == null) {throw new IllegalArgumentException("Tab not attached to a TabLayout");}return setContentDescription(mParent.getResources().getText(resId));}/*** Set a description of this tab's content for use in accessibility support. If no content* description is provided the title will be used.** @param contentDesc Description of this tab's content* @return The current instance for call chaining* @see #setContentDescription(int)* @see #getContentDescription()*/@NonNullpublic Tab setContentDescription(@Nullable CharSequence contentDesc) {mContentDesc = contentDesc;updateView();return this;}/*** Gets a brief description of this tab's content for use in accessibility support.** @return Description of this tab's content* @see #setContentDescription(CharSequence)* @see #setContentDescription(int)*/@Nullablepublic CharSequence getContentDescription() {return mContentDesc;}void updateView() {if (mView != null) {mView.update();}}void reset() {mParent = null;mView = null;mTag = null;mIcon = null;mText = null;mContentDesc = null;mPosition = INVALID_POSITION;mCustomView = null;}}class TabView extends LinearLayout {private Tab mTab;private TextView mTextView;private ImageView mIconView;private View mCustomView;private TextView mCustomTextView;private ImageView mCustomIconView;private int mDefaultMaxLines = 2;public TabView(Context context) {super(context);if (mTabBackgroundResId != 0) {ViewCompat.setBackground(this, AppCompatResources.getDrawable(context, mTabBackgroundResId));}ViewCompat.setPaddingRelative(this, mTabPaddingStart, mTabPaddingTop,mTabPaddingEnd, mTabPaddingBottom);setGravity(Gravity.CENTER);setOrientation(VERTICAL);setClickable(true);ViewCompat.setPointerIcon(this,PointerIconCompat.getSystemIcon(getContext(), PointerIconCompat.TYPE_HAND));}@Overridepublic boolean performClick() {final boolean handled = super.performClick();if (mTab != null) {if (!handled) {playSoundEffect(SoundEffectConstants.CLICK);}mTab.select();return true;} else {return handled;}}@Overridepublic void setSelected(final boolean selected) {final boolean changed = isSelected() != selected;super.setSelected(selected);if (changed && selected && Build.VERSION.SDK_INT < 16) {// Pre-JB we need to manually send the TYPE_VIEW_SELECTED eventsendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);}// Always dispatch this to the child views, regardless of whether the value has// changedif (mTextView != null) {mTextView.setSelected(selected);}if (mIconView != null) {mIconView.setSelected(selected);}if (mCustomView != null) {mCustomView.setSelected(selected);}}@Overridepublic void onInitializeAccessibilityEvent(AccessibilityEvent event) {super.onInitializeAccessibilityEvent(event);// This view masquerades as an action bar tab.event.setClassName(ActionBar.Tab.class.getName());}@Overridepublic void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {super.onInitializeAccessibilityNodeInfo(info);// This view masquerades as an action bar tab.info.setClassName(ActionBar.Tab.class.getName());}@Overridepublic void onMeasure(final int origWidthMeasureSpec, final int origHeightMeasureSpec) {final int specWidthSize = MeasureSpec.getSize(origWidthMeasureSpec);final int specWidthMode = MeasureSpec.getMode(origWidthMeasureSpec);final int maxWidth = getTabMaxWidth();final int widthMeasureSpec;final int heightMeasureSpec = origHeightMeasureSpec;if (maxWidth > 0 && (specWidthMode == MeasureSpec.UNSPECIFIED|| specWidthSize > maxWidth)) {// If we have a max width and a given spec which is either unspecified or// larger than the max width, update the width spec using the same modewidthMeasureSpec = MeasureSpec.makeMeasureSpec(mTabMaxWidth, MeasureSpec.AT_MOST);} else {// Else, use the original width specwidthMeasureSpec = origWidthMeasureSpec;}// Now lets measuresuper.onMeasure(widthMeasureSpec, heightMeasureSpec);// We need to switch the text size based on whether the text is spanning 2 lines or notif (mTextView != null) {final Resources res = getResources();float textSize = mTabTextSize;int maxLines = mDefaultMaxLines;if (mIconView != null && mIconView.getVisibility() == VISIBLE) {// If the icon view is being displayed, we limit the text to 1 linemaxLines = 1;} else if (mTextView != null && mTextView.getLineCount() > 1) {// Otherwise when we have text which wraps we reduce the text sizetextSize = mTabTextMultiLineSize;}final float curTextSize = mTextView.getTextSize();final int curLineCount = mTextView.getLineCount();final int curMaxLines = TextViewCompat.getMaxLines(mTextView);if (textSize != curTextSize || (curMaxLines >= 0 && maxLines != curMaxLines)) {// We've got a new text size and/or max lines...boolean updateTextView = true;if (mMode == MODE_FIXED && textSize > curTextSize && curLineCount == 1) {// If we're in fixed mode, going up in text size and currently have 1 line// then it's very easy to get into an infinite recursion.// To combat that we check to see if the change in text size// will cause a line count change. If so, abort the size change and stick// to the smaller size.final Layout layout = mTextView.getLayout();if (layout == null || approximateLineWidth(layout, 0, textSize)> getMeasuredWidth() - getPaddingLeft() - getPaddingRight()) {updateTextView = false;}}if (updateTextView) {mTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);mTextView.setMaxLines(maxLines);super.onMeasure(widthMeasureSpec, heightMeasureSpec);}}}}void setTab(@Nullable final Tab tab) {if (tab != mTab) {mTab = tab;update();}}void reset() {setTab(null);setSelected(false);}final void update() {final Tab tab = mTab;final View custom = tab != null ? tab.getCustomView() : null;if (custom != null) {final ViewParent customParent = custom.getParent();if (customParent != this) {if (customParent != null) {((ViewGroup) customParent).removeView(custom);}addView(custom);}mCustomView = custom;if (mTextView != null) {mTextView.setVisibility(GONE);}if (mIconView != null) {mIconView.setVisibility(GONE);mIconView.setImageDrawable(null);}mCustomTextView = (TextView) custom.findViewById(android.R.id.text1);if (mCustomTextView != null) {mDefaultMaxLines = TextViewCompat.getMaxLines(mCustomTextView);}mCustomIconView = (ImageView) custom.findViewById(android.R.id.icon);} else {// We do not have a custom view. Remove one if it already existsif (mCustomView != null) {removeView(mCustomView);mCustomView = null;}mCustomTextView = null;mCustomIconView = null;}if (mCustomView == null) {// If there isn't a custom view, we'll us our own in-built layoutsif (mIconView == null) {ImageView iconView = (ImageView) LayoutInflater.from(getContext()).inflate(android.support.design.R.layout.design_layout_tab_icon, this, false);addView(iconView, 0);mIconView = iconView;}if (mTextView == null) {TextView textView = (TextView) LayoutInflater.from(getContext()).inflate(android.support.design.R.layout.design_layout_tab_text, this, false);addView(textView);mTextView = textView;mDefaultMaxLines = TextViewCompat.getMaxLines(mTextView);}TextViewCompat.setTextAppearance(mTextView, mTabTextAppearance);if (mTabTextColors != null) {mTextView.setTextColor(mTabTextColors);}updateTextAndIcon(mTextView, mIconView);} else {// Else, we'll see if there is a TextView or ImageView present and update themif (mCustomTextView != null || mCustomIconView != null) {updateTextAndIcon(mCustomTextView, mCustomIconView);}}// Finally update our selected statesetSelected(tab != null && tab.isSelected());}private void updateTextAndIcon(@Nullable final TextView textView,@Nullable final ImageView iconView) {final Drawable icon = mTab != null ? mTab.getIcon() : null;final CharSequence text = mTab != null ? mTab.getText() : null;final CharSequence contentDesc = mTab != null ? mTab.getContentDescription() : null;if (iconView != null) {if (icon != null) {iconView.setImageDrawable(icon);iconView.setVisibility(VISIBLE);setVisibility(VISIBLE);} else {iconView.setVisibility(GONE);iconView.setImageDrawable(null);}iconView.setContentDescription(contentDesc);}final boolean hasText = !TextUtils.isEmpty(text);if (textView != null) {if (hasText) {textView.setText(text);textView.setVisibility(VISIBLE);setVisibility(VISIBLE);} else {textView.setVisibility(GONE);textView.setText(null);}textView.setContentDescription(contentDesc);}if (iconView != null) {MarginLayoutParams lp = ((MarginLayoutParams) iconView.getLayoutParams());int bottomMargin = 0;if (hasText && iconView.getVisibility() == VISIBLE) {// If we're showing both text and icon, add some margin bottom to the iconbottomMargin = dpToPx(DEFAULT_GAP_TEXT_ICON);}if (bottomMargin != lp.bottomMargin) {lp.bottomMargin = bottomMargin;iconView.requestLayout();}}TooltipCompat.setTooltipText(this, hasText ? null : contentDesc);}public Tab getTab() {return mTab;}/*** Approximates a given lines width with the new provided text size.*/private float approximateLineWidth(Layout layout, int line, float textSize) {return layout.getLineWidth(line) * (textSize / layout.getPaint().getTextSize());}}private class SlidingTabStrip extends LinearLayout {private int mSelectedIndicatorHeight;private final Paint mSelectedIndicatorPaint;int mSelectedPosition = -1;float mSelectionOffset;private int mLayoutDirection = -1;private int mIndicatorLeft = -1;private int mIndicatorRight = -1;private RectF mIndicatorRect = new RectF();private int mIndicatorMarginLeft = 0;private int mIndicatorMarginRight = 0;private int mIndicatorMarginBottom = 0;private ValueAnimator mIndicatorAnimator;private int mStartColor;private int mEndColor;private boolean mIsColorDirty = true;SlidingTabStrip(Context context) {super(context);setWillNotDraw(false);mSelectedIndicatorPaint = new Paint();mSelectedIndicatorPaint.setAntiAlias(true);}void setSelectedIndicatorMarginBottom(@Px int margin) {mIndicatorMarginBottom = margin;}void setSelectedIndicatorMargin(@Px int marginLeft, @Px int marginRight) {mIndicatorMarginLeft = marginLeft;mIndicatorMarginRight = marginRight;}void setSelectedIndicatorColor(int color) {setSelectedIndicatorColor(color, color);}void setSelectedIndicatorColor(int startColor, int endColor) {if (startColor != mStartColor || endColor != mEndColor) {mStartColor = startColor;mEndColor = endColor;mIsColorDirty = true;ViewCompat.postInvalidateOnAnimation(this);}}void setSelectedIndicatorHeight(int height) {if (mSelectedIndicatorHeight != height) {mSelectedIndicatorHeight = height;ViewCompat.postInvalidateOnAnimation(this);}}boolean childrenNeedLayout() {for (int i = 0, z = getChildCount(); i < z; i++) {final View child = getChildAt(i);if (child.getWidth() <= 0) {return true;}}return false;}void setIndicatorPositionFromTabPosition(int position, float positionOffset) {if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) {mIndicatorAnimator.cancel();}mSelectedPosition = position;mSelectionOffset = positionOffset;updateIndicatorPosition();}float getIndicatorPosition() {return mSelectedPosition + mSelectionOffset;}@Overridepublic void onRtlPropertiesChanged(int layoutDirection) {super.onRtlPropertiesChanged(layoutDirection);// Workaround for a bug before Android M where LinearLayout did not relayout itself when// layout direction changed.if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {//noinspection WrongConstantif (mLayoutDirection != layoutDirection) {requestLayout();mLayoutDirection = layoutDirection;}}}@Overrideprotected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY) {// HorizontalScrollView will first measure use with UNSPECIFIED, and then with// EXACTLY. Ignore the first call since anything we do will be overwritten anywayreturn;}if (mMode == MODE_FIXED && mTabGravity == GRAVITY_CENTER) {final int count = getChildCount();// First we'll find the widest tabint largestTabWidth = 0;for (int i = 0, z = count; i < z; i++) {View child = getChildAt(i);if (child.getVisibility() == VISIBLE) {largestTabWidth = Math.max(largestTabWidth, child.getMeasuredWidth());}}if (largestTabWidth <= 0) {// If we don't have a largest child yet, skip until the next measure passreturn;}final int gutter = dpToPx(FIXED_WRAP_GUTTER_MIN);boolean remeasure = false;if (largestTabWidth * count <= getMeasuredWidth() - gutter * 2) {// If the tabs fit within our width minus gutters, we will set all tabs to have// the same widthfor (int i = 0; i < count; i++) {final LayoutParams lp =(LayoutParams) getChildAt(i).getLayoutParams();if (lp.width != largestTabWidth || lp.weight != 0) {lp.width = largestTabWidth;lp.weight = 0;remeasure = true;}}} else {// If the tabs will wrap to be larger than the width minus gutters, we need// to switch to GRAVITY_FILLmTabGravity = GRAVITY_FILL;updateTabViews(false);remeasure = true;}if (remeasure) {// Now re-measure after our changessuper.onMeasure(widthMeasureSpec, heightMeasureSpec);}}}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {super.onLayout(changed, l, t, r, b);if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) {// If we're currently running an animation, lets cancel it and start a// new animation with the remaining durationmIndicatorAnimator.cancel();final long duration = mIndicatorAnimator.getDuration();animateIndicatorToPosition(mSelectedPosition,Math.round((1f - mIndicatorAnimator.getAnimatedFraction()) * duration));} else {// If we've been layed out, update the indicator positionupdateIndicatorPosition();}}private void updateIndicatorPosition() {final View selectedTitle = getChildAt(mSelectedPosition);int left, right;if (selectedTitle != null && selectedTitle.getWidth() > 0) {left = selectedTitle.getLeft();right = selectedTitle.getRight();if (mSelectionOffset > 0f && mSelectedPosition < getChildCount() - 1) {// Draw the selection partway between the tabsView nextTitle = getChildAt(mSelectedPosition + 1);if (mSelectionOffset <= 0.5f) {left = selectedTitle.getLeft();right = AnimationUtils.lerp(right, nextTitle.getRight(), mSelectionOffset * 2);} else {left = AnimationUtils.lerp(left, nextTitle.getLeft(), (mSelectionOffset - 0.5f) * 2);right = nextTitle.getRight();}}} else {left = right = -1;}setIndicatorPosition(left, right);}void setIndicatorPosition(int left, int right) {if (left != mIndicatorLeft || right != mIndicatorRight) {// If the indicator's left/right has changed, invalidatemIndicatorLeft = left + mIndicatorMarginLeft;mIndicatorRight = right - mIndicatorMarginRight;ViewCompat.postInvalidateOnAnimation(this);}}void animateIndicatorToPosition(final int position, int duration) {if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) {mIndicatorAnimator.cancel();}final boolean isRtl = ViewCompat.getLayoutDirection(this)== ViewCompat.LAYOUT_DIRECTION_RTL;final View targetView = getChildAt(position);if (targetView == null) {// If we don't have a view, just update the position now and returnupdateIndicatorPosition();return;}final int targetLeft = targetView.getLeft();final int targetRight = targetView.getRight();final int startLeft;final int startRight;startLeft = mIndicatorLeft;startRight = mIndicatorRight;if (startLeft != targetLeft || startRight != targetRight) {ValueAnimator animator = mIndicatorAnimator = new ValueAnimator();animator.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);animator.setDuration(duration);animator.setFloatValues(0, 1);animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animator) {final float fraction = animator.getAnimatedFraction();int left, right;if (mSelectedPosition < position) {if (fraction <= 0.5f) {left = startLeft;right = AnimationUtils.lerp(startRight, targetRight, fraction * 2);} else {left = AnimationUtils.lerp(startLeft, targetLeft, (fraction - 0.5f) * 2);right = targetRight;}} else {if (fraction <= 0.5f) {left = AnimationUtils.lerp(startLeft, targetLeft, fraction * 2);right = startRight;} else {left = targetLeft;right = AnimationUtils.lerp(startRight, targetRight, (fraction - 0.5f) * 2);}}setIndicatorPosition(left, right);}});animator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animator) {mSelectedPosition = position;mSelectionOffset = 0f;}});animator.start();}}@Overridepublic void draw(Canvas canvas) {super.draw(canvas);int left = mIndicatorLeft;int right = mIndicatorRight;// get edges ofif (mSelectionOffset > 0 && mSelectedPosition < getChildCount() - 1) {View leftView = getChildAt(mSelectedPosition);View rightView = getChildAt(mSelectedPosition + 1);left = leftView.getLeft() + mIndicatorMarginLeft;right = rightView.getRight() - mIndicatorMarginRight;}// ensure color updatedif (mSelectedIndicatorPaint.getShader() == null || mIsColorDirty) {LinearGradient gradient = new LinearGradient(0, 0, getWidth(), 0, mStartColor, mEndColor, Shader.TileMode.CLAMP);mSelectedIndicatorPaint.setShader(gradient);}// visible rectmIndicatorRect.set(mIndicatorLeft, getHeight() - mSelectedIndicatorHeight - mIndicatorMarginBottom,mIndicatorRight, getHeight() - mIndicatorMarginBottom);// show dst round rect only, but with src backgroundint sc = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);// draw dst round rectcanvas.drawRoundRect(mIndicatorRect, mSelectedIndicatorHeight / 2, mSelectedIndicatorHeight / 2, mSelectedIndicatorPaint);mSelectedIndicatorPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));// draw src background oncanvas.drawRect(left, getHeight() - mSelectedIndicatorHeight - mIndicatorMarginBottom,right, getHeight() - mIndicatorMarginBottom, mSelectedIndicatorPaint);mSelectedIndicatorPaint.setXfermode(null);canvas.restoreToCount(sc);}}private static ColorStateList createColorStateList(int defaultColor, int selectedColor) {final int[][] states = new int[2][];final int[] colors = new int[2];int i = 0;states[i] = SELECTED_STATE_SET;colors[i] = selectedColor;i++;// Default enabled statestates[i] = EMPTY_STATE_SET;colors[i] = defaultColor;i++;return new ColorStateList(states, colors);}private int getDefaultHeight() {boolean hasIconAndText = false;for (int i = 0, count = mTabs.size(); i < count; i++) {Tab tab = mTabs.get(i);if (tab != null && tab.getIcon() != null && !TextUtils.isEmpty(tab.getText())) {hasIconAndText = true;break;}}return hasIconAndText ? DEFAULT_HEIGHT_WITH_TEXT_ICON : DEFAULT_HEIGHT;}private int getTabMinWidth() {if (mRequestedTabMinWidth != INVALID_WIDTH) {// If we have been given a min width, use itreturn mRequestedTabMinWidth;}// Else, we'll use the default valuereturn mMode == MODE_SCROLLABLE ? mScrollableTabMinWidth : 0;}@Overridepublic LayoutParams generateLayoutParams(AttributeSet attrs) {// We don't care about the layout params of any views added to us, since we don't actually// add them. The only view we add is the SlidingTabStrip, which is done manually.// We return the default layout params so that we don't blow up if we're given a TabItem// without android:layout_* values.return generateDefaultLayoutParams();}int getTabMaxWidth() {return mTabMaxWidth;}/*** A {@link ViewPager.OnPageChangeListener} class which contains the* necessary calls back to the provided {@link CustomTabLayout} so that the tab position is* kept in sync.** <p>This class stores the provided TabLayout weakly, meaning that you can use* {@link ViewPager#addOnPageChangeListener(ViewPager.OnPageChangeListener)* addOnPageChangeListener(OnPageChangeListener)} without removing the listener and* not cause a leak.*/public static class TabLayoutOnPageChangeListener implements ViewPager.OnPageChangeListener {private final WeakReference<CustomTabLayout> mTabLayoutRef;private int mPreviousScrollState;private int mScrollState;public TabLayoutOnPageChangeListener(CustomTabLayout customTabLayout) {mTabLayoutRef = new WeakReference<>(customTabLayout);}@Overridepublic void onPageScrollStateChanged(final int state) {mPreviousScrollState = mScrollState;mScrollState = state;}@Overridepublic void onPageScrolled(final int position, final float positionOffset,final int positionOffsetPixels) {final CustomTabLayout customTabLayout = mTabLayoutRef.get();if (customTabLayout != null) {// Only update the text selection if we're not settling, or we are settling after// being draggedfinal boolean updateText = mScrollState != SCROLL_STATE_SETTLING ||mPreviousScrollState == SCROLL_STATE_DRAGGING;// Update the indicator if we're not settling after being idle. This is caused// from a setCurrentItem() call and will be handled by an animation from// onPageSelected() instead.final boolean updateIndicator = !(mScrollState == SCROLL_STATE_SETTLING&& mPreviousScrollState == SCROLL_STATE_IDLE);customTabLayout.setScrollPosition(position, positionOffset, updateText, updateIndicator);}}@Overridepublic void onPageSelected(final int position) {final CustomTabLayout customTabLayout = mTabLayoutRef.get();if (customTabLayout != null && customTabLayout.getSelectedTabPosition() != position&& position < customTabLayout.getTabCount()) {// Select the tab, only updating the indicator if we're not being dragged/settled// (since onPageScrolled will handle that).final boolean updateIndicator = mScrollState == SCROLL_STATE_IDLE|| (mScrollState == SCROLL_STATE_SETTLING&& mPreviousScrollState == SCROLL_STATE_IDLE);customTabLayout.selectTab(customTabLayout.getTabAt(position), updateIndicator);}}void reset() {mPreviousScrollState = mScrollState = SCROLL_STATE_IDLE;}}/*** A {@link OnTabSelectedListener} class which contains the necessary calls back* to the provided {@link ViewPager} so that the tab position is kept in sync.*/public static class ViewPagerOnTabSelectedListener implements OnTabSelectedListener {private final ViewPager mViewPager;public ViewPagerOnTabSelectedListener(ViewPager viewPager) {mViewPager = viewPager;}@Overridepublic void onTabSelected(Tab tab) {mViewPager.setCurrentItem(tab.getPosition());}@Overridepublic void onTabUnselected(Tab tab) {// No-op}@Overridepublic void onTabReselected(Tab tab) {// No-op}}private class PagerAdapterObserver extends DataSetObserver {PagerAdapterObserver() {}@Overridepublic void onChanged() {populateFromPagerAdapter();}@Overridepublic void onInvalidated() {populateFromPagerAdapter();}}private class AdapterChangeListener implements ViewPager.OnAdapterChangeListener {private boolean mAutoRefresh;AdapterChangeListener() {}@Overridepublic void onAdapterChanged(@NonNull ViewPager viewPager,@Nullable PagerAdapter oldAdapter, @Nullable PagerAdapter newAdapter) {if (mViewPager == viewPager) {setPagerAdapter(newAdapter, mAutoRefresh);}}void setAutoRefresh(boolean autoRefresh) {mAutoRefresh = autoRefresh;}}
}

 

 //第二步 新建AnimationUtils类,

注意将本类里com.gang.app.myceshi.customtab,是我项目里的包名,全部替换成你自己的。整体代码:

 

/** Copyright (C) 2015 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.gang.app.myceshi.customtab;import android.support.v4.view.animation.FastOutLinearInInterpolator;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.support.v4.view.animation.LinearOutSlowInInterpolator;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;class AnimationUtils {static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();static final Interpolator FAST_OUT_SLOW_IN_INTERPOLATOR = new FastOutSlowInInterpolator();static final Interpolator FAST_OUT_LINEAR_IN_INTERPOLATOR = new FastOutLinearInInterpolator();static final Interpolator LINEAR_OUT_SLOW_IN_INTERPOLATOR = new LinearOutSlowInInterpolator();static final Interpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator();/*** Linear interpolation between {@code startValue} and {@code endValue} by {@code fraction}.*/static float lerp(float startValue, float endValue, float fraction) {return startValue + (fraction * (endValue - startValue));}static int lerp(int startValue, int endValue, float fraction) {return startValue + Math.round(fraction * (endValue - startValue));}static class AnimationListenerAdapter implements Animation.AnimationListener {@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationEnd(Animation animation) {}@Overridepublic void onAnimationRepeat(Animation animation) {}}}

 //第三步 新建TabItem类,

注意将本类里com.gang.app.myceshi.customtab,是我项目里的包名,全部替换成你自己的。整体代码:

/** Copyright (C) 2016 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.gang.app.myceshi.customtab;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;/*** TabItem is a special 'view' which allows you to declare tab items for a {@link CustomTabLayout}* within a layout. This view is not actually added to TabLayout, it is just a dummy which allows* setting of a tab items's text, icon and custom layout. See TabLayout for more information on how* to use it.** @attr ref android.support.design.R.styleable#TabItem_android_icon* @attr ref android.support.design.R.styleable#TabItem_android_text* @attr ref android.support.design.R.styleable#TabItem_android_layout** @see CustomTabLayout*/
public final class TabItem extends View {final CharSequence mText;final Drawable mIcon;final int mCustomLayout;public TabItem(Context context) {this(context, null);}public TabItem(Context context, AttributeSet attrs) {super(context, attrs);final TypedArray a = context.obtainStyledAttributes(attrs,android.support.design.R.styleable.TabItem);mText = a.getText(android.support.design.R.styleable.TabItem_android_text);mIcon = a.getDrawable(android.support.design.R.styleable.TabItem_android_icon);mCustomLayout = a.getResourceId(android.support.design.R.styleable.TabItem_android_layout, 0);a.recycle();}
}

 

//第四步 新建ThemeUtils类,

注意将本类里com.gang.app.myceshi.customtab,是我项目里的包名,全部替换成你自己的。整体代码:

 

/** Copyright (C) 2015 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.gang.app.myceshi.customtab;import android.content.Context;
import android.content.res.TypedArray;class ThemeUtils {private static final int[] APPCOMPAT_CHECK_ATTRS = {android.support.v7.appcompat.R.attr.colorPrimary};static void checkAppCompatTheme(Context context) {TypedArray a = context.obtainStyledAttributes(APPCOMPAT_CHECK_ATTRS);final boolean failed = !a.hasValue(0);if (a != null) {a.recycle();}if (failed) {throw new IllegalArgumentException("You need to use a Theme.AppCompat theme "+ "(or descendant) with the design library.");}}
}

//第五步 在本地res/values下新建attrs.xml文件,在attrs.xml里添加:

<declare-styleable name="CustomTabLayout"><!--指示器渐变色开始颜色--><attr name="indicatorStartColor" format="color|reference" /><!--指示器渐变色结束颜色--><attr name="indicatorEndColor" format="color|reference" /><!--指示器距离开始--><attr name="indicatorMarginStart" format="dimension|reference" /><!--指示器距离结束--><attr name="indicatorMarginEnd" format="dimension|reference" /><!--指示器距离底部--><attr name="indicatorMarginBottom" format="dimension|reference" />
</declare-styleable>

 //第六步 在本地res/values/styles.xml里添加: 

<!--设置Tablayout字体大小-->
<style name="TabLayoutTextSize" parent="TextAppearance.Design.Tab"><item name="android:textSize">14sp</item>
</style><!--设置Tablayout字体加粗-->
<style name="TabLayoutTextStyle"><item name="android:textStyle">bold</item>
</style>

//第七步 好了,现在可以在布局中使用了,布局文件下,CustomTabLayout和ViewPager: 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"xmlns:app="http://schemas.android.com/apk/res-auto"android:orientation="vertical"tools:context=".activity.Main20Activity"><com.gang.app.myceshi.customtab.CustomTabLayoutapp:tabTextAppearance="@style/TabLayoutTextSize"app:tabSelectedTextColor="@color/colorPrimary"app:tabGravity="center"app:tabMode="fixed"app:tabTextColor="@color/colorAccent"android:id="@+id/mCustomTabLayout"app:tabIndicatorHeight="5dp"app:indicatorStartColor="@color/colorAccent"app:indicatorEndColor="@color/colorPrimary"app:indicatorMarginStart="30dp"app:indicatorMarginEnd="30dp"app:indicatorMarginBottom="3dp"android:layout_width="match_parent"android:layout_height="50dp"/><android.support.v4.view.ViewPagerandroid:id="@+id/mViewPager"android:layout_width="match_parent"android:layout_height="match_parent"/></LinearLayout>

 //第八步  在activity中的实现,我的activity实现,关于tab滑动选中字体变大,更换颜色也在其中,FragmentText1和FragmentText2是两个简单的fragment这里就不展示了,整体代码:

 

package com.gang.app.myceshi.activity;import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.util.TypedValue;
import android.view.Gravity;
import android.widget.TextView;import com.gang.app.myceshi.FragmentText1;
import com.gang.app.myceshi.FragmentText2;
import com.gang.app.myceshi.FragmentTextApader;
import com.gang.app.myceshi.R;
import com.gang.app.myceshi.customtab.CustomTabLayout;import java.util.ArrayList;
import java.util.List;public class Main20Activity extends AppCompatActivity {private final String[] mTitles = {"页面一", "页面二"};private List<Fragment> mFragmentList = new ArrayList<>();private CustomTabLayout mCustomTabLayout;private ViewPager mViewPager;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main20);initView();initData();}private void initView() {mCustomTabLayout = (CustomTabLayout) findViewById(R.id.mCustomTabLayout);mViewPager = (ViewPager) findViewById(R.id.mViewPager);mCustomTabLayout.addOnTabSelectedListener(new CustomTabLayout.OnTabSelectedListener() {@Overridepublic void onTabSelected(CustomTabLayout.Tab tab) {setTabTextView(tab, true);}@Overridepublic void onTabUnselected(CustomTabLayout.Tab tab) {setTabTextView(tab, false);}@Overridepublic void onTabReselected(CustomTabLayout.Tab tab) {}});}private void initData() {mFragmentList.add((FragmentText1) Fragment.instantiate(this, FragmentText1.class.getName()));mFragmentList.add((FragmentText2) Fragment.instantiate(this, FragmentText2.class.getName()));FragmentTextApader apader = new FragmentTextApader(getSupportFragmentManager(), mFragmentList, mTitles);mViewPager.setAdapter(apader);mCustomTabLayout.setupWithViewPager(mViewPager);}/*** tab滑动选中字体变大,更换颜色** @param tab* @param selected*/private void setTabTextView(CustomTabLayout.Tab tab, boolean selected) {TextView customView = (TextView) tab.getCustomView();//不为空选中if (null != customView && selected) {float selectedSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 16, getResources().getDisplayMetrics());customView.setTextSize(TypedValue.COMPLEX_UNIT_SP, selectedSize);customView.setTextColor(ContextCompat.getColor(this, R.color.colorPrimary));customView.setGravity(Gravity.CENTER);return;} else if (null != customView) {float selectedSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 14, getResources().getDisplayMetrics());customView.setTextSize(TypedValue.COMPLEX_UNIT_SP, selectedSize);customView.setTextColor(ContextCompat.getColor(this, R.color.colorAccent));customView.setGravity(Gravity.CENTER);return;}//为空选中if (selected) {TextView textView = new TextView(getApplicationContext());float selectedSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 16, getResources().getDisplayMetrics());textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, selectedSize);textView.setTextColor(ContextCompat.getColor(this, R.color.colorPrimary));textView.setText(tab.getText());textView.setGravity(Gravity.CENTER);tab.setCustomView(textView);} else {TextView textView = new TextView(getApplicationContext());float selectedSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 14, getResources().getDisplayMetrics());textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, selectedSize);textView.setTextColor(ContextCompat.getColor(this, R.color.colorAccent));textView.setText(tab.getText());textView.setGravity(Gravity.CENTER);tab.setCustomView(textView);}}}

 //第九步  适配器,整体代码:

 

package com.gang.app.myceshi;import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;import java.util.List;public class FragmentTextApader extends FragmentPagerAdapter {private List<Fragment> mFragmentList;private String[] mTitles;public FragmentTextApader(FragmentManager fm, List<Fragment> mFragmentList, String[] mTitles) {super(fm);this.mFragmentList = mFragmentList;this.mTitles = mTitles;}@Overridepublic Fragment getItem(int position) {return mFragmentList.get(position);}@Overridepublic int getCount() {return mFragmentList.size();}@Overridepublic CharSequence getPageTitle(int position) {return mTitles[position];}}

------------------------------------------------------------------------好了完成---------------------------------------------------------------------------

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 21、【易混淆概念集】-第十三章 相关方参与度评估矩阵 VS 相关方参与计划 相关方登记册 VS 相关方参与计划 相关方立方体 VS 凸显模型 权力/利益方格

    本讲主要介绍PMBOK第十三章中的重要知识点,帮助你进一步理解。本节目录一、相关方参与度评估矩阵 VS 相关方参与计划二、相关方登记册 VS 相关方参与计划三、相关方立方体 VS 凸显模型四、权力/利益方格一、相关方参与度评估矩阵 VS相关方参与计划 【出处】PMBOK P521,13.2.2…...

    2024/4/16 5:30:58
  2. 21、【易混淆概念集】-第十三章 相关方参与度评估矩阵 VS 相关方参与计划 相关方登记册 VS 相关方参与计划 相关方立方体 VS 凸显模型 权力/利益方格

    本讲主要介绍PMBOK第十三章中的重要知识点,帮助你进一步理解。本节目录一、相关方参与度评估矩阵 VS 相关方参与计划二、相关方登记册 VS 相关方参与计划三、相关方立方体 VS 凸显模型四、权力/利益方格一、相关方参与度评估矩阵 VS相关方参与计划 【出处】PMBOK P521,13.2.2…...

    2024/4/16 5:30:43
  3. 计算机网络涉及(stp,pvst,acl,链路聚合,vlan)

    计算机网络综合练习涉及(stp,pvst,acl,链路聚合,vlan)使用华三模拟器题目要求具体步骤连接所有设备配置PC1配置PC2配置SW1交换机(有代码注释)配置SW2交换机(写不详细的部分在SW1中有详细写)配置SW3交换机配置R1路由器配置R2路由器 题目要求需求:内网可以访问外网,外网…...

    2024/5/2 14:07:43
  4. 电容DAC版图布局

    系统误差:包括光刻时带来的电容周长比例不匹配、刻蚀率不同使边长偏离以及外引线的寄生电容引起的偏差等,可以通过合理的版图布局改善或消除这类误差; 随机误差:由电容边长的随机变化、氧化层厚度和介电常数的随机变化等构成,只能通过工艺技术水平的提高来减小这类误差。 …...

    2024/4/16 21:54:20
  5. 19、【易混淆概念集】第十一章3 应急计划 VS 弹回计划 实施风险应对 监督风险

    本讲主要介绍PMBOK第十一章中的重要知识点,帮助你进一步理解。本节目录一、应急计划 VS 弹回计划二、实施风险应对三、监督风险一、应急计划 VS 弹回计划应急计划、弹回计划的区别?应急计划:也是针对的已识别的风险,而且这个风险是有预警的,这个时候可以制定应急计划,在预…...

    2024/5/2 9:31:46
  6. SpringBoot配置本地文件映射

    我用的是yaml配置 我觉得常用的才是最简单的 spring:resources: #访问系统外部资源,将该目录下的文件映射到系统下static-locations: file:D:/1111/images/ #本地文件mvc:static-path-pattern: /zcbimages/**访问方式:IP+端口/文件名 配置成功后,直接访问即可 http://lo…...

    2024/4/20 17:54:42
  7. vertx结合Resteasy实现注解拦截器

    vertx结合Resteasy实现注解拦截器在Verticle中创建JAX-RS controller deployment对象并开启VertxResteasyDeployment deployment = new VertxResteasyDeployment(); deployment.start();将DynamicFeature对象注册到Provider中deployment.getProviderFactory().register(MyDynam…...

    2024/5/2 13:36:55
  8. HZNUOJ2129这是压轴题

    Description给定两个数a,b,输出a+bInput有T组输入对于每组输入有两个非负整数a,b(<=10^210)Output对于每组数据输出a+binput Copy2 1 1 2 2output Copy2 4注意此题的数据范围,所以不可以用int 或者long long int 直接相加;此题要运用到字符串来完成相加将各个位的十进制…...

    2024/4/16 5:31:19
  9. hdu1428漫步校园

    LL最近沉迷于AC不能自拔,每天寝室、机房两点一线。由于长时间坐在电脑边,缺乏运动。他决定充分利用每次从寝室到机房的时间,在校园里散散步。整个HDU校园呈方形布局,可划分为n*n个小方格,代表各个区域。例如LL居住的18号宿舍位于校园的西北角,即方格(1,1)代表的地方,而机…...

    2024/4/19 18:39:17
  10. 【Enthought】【2017.09】MATLAB代码自动转换为Python

    更多精彩文章请关注公众号:...

    2024/4/16 5:31:34
  11. linux修改主机名,用户密码,切换用户

    修改主机名 vim /etc/sysconfig/network输入reboot命令重启需要在root权限下修改用户密码切换用户 切换root用户:su...

    2024/4/18 3:30:45
  12. Linux用户及文件权限管理

    作为root管理员,经常需要增删用户,设置目录的访问权限等。 用户管理Linux中账号相关信息是记录在/etc/passwd下,密码记录在/etc/shadow下,群组记录在/etc/group下。新增:useradd -g init_group -G second_group -s shell username:useradd vbird新建用户vbird,所有参数为…...

    2024/4/19 20:05:01
  13. vue+element ui 列表数据分页显示

    <template><div class="main-middle"><div class="main-site" v-if="currentSiteData"><group-component :style="currentPage.styles" :item="currentPage"></group-component>//显示多少个…...

    2024/4/27 23:58:40
  14. 七牛云CDN使用场景释义

    图片小文件,适用于网页、图片、小文件;下载分发,适用于文件下载,例如安装包,压缩包等二进制大文件;点播平台,适用于需要MP4/FLV等文件按照时间点进行播放;动态加速,适用于电商、社交、社区论坛、金融支付和游戏娱乐等方面,注意动态加速的请求次数也需要收费,参考:h…...

    2024/4/16 8:54:13
  15. JavaWeb:基于MVC的登录页面

    目录MVC介绍代码展示环境登录页面的实现 MVC介绍 MVC模式是一种软件设计模式,是模型(model),视图(view),控制器(controller)的缩写,他将业务模型(M)和用户界面(V)的代码分离了开来。 MVC模式有助于管理复杂的应用程序,简化了分组开发。不同的开发人员可同时开发视图、控制…...

    2024/4/19 15:05:00
  16. 推荐几个c++自学网站

    1、http://snippets.dzone.com/tag/c/ --数以千计的有用的C语言源代码片段 2、http://www.hotscripts.com/category/c-cpp/scripts-programs/ Hotscripts --提供数以百计的C和C++脚本和程序。所有程序都分为不同的类别。3、http://www.planetsourcecode.com/vb/default.asp?ln…...

    2024/4/16 5:31:49
  17. 实验七|Python 企业现金流分析

    实验介绍 1.1. 实验目的 本实验主要介绍企业现金流指标的爬取与可视化。基于网络爬虫,爬取企业连续5年的企业现金流关键财务指标,通过饼图、柱状图、折线图等对相关指标进行可视化展示。1.2. 知识点 •现金净流量介绍 •现金净流量作用 •现金净流量指标 •现金净流量爬取 •…...

    2024/4/16 5:31:39
  18. Python3 封装根据时间戳进行命令的截图函数

    一般截图便于实现,但是怎么保存自动化过程中每个操作步骤的图片呢(要求图片名字不一致,否则会被下一张图片替换),如下:def getScreencapShot(self):#封装根据时间戳来命令的截图time = self.gettamp()filename = E:\\screencaps\\%s.png%timeself.driver.get_screenshot_…...

    2024/4/18 12:55:04
  19. 还在纠结秒杀?看看 MQ 轻松搞定秒杀场景

    ** 本文原创首发于公众号【程序员大帝】,关注获得更多原创精品内容 **前言 相信即使你是第一次听说消息中间件的概念,通过上一篇文章《十分钟入门消息中间件》的介绍,现在应该知道什么是 MQ ,为什么要使用 MQ 了。 我们先简单回顾一下,订单系统是整个电商交易平台的核心,…...

    2024/4/16 5:31:39
  20. MATLAB二维图形绘制

    MATLAB二维图形绘制数据点标记数据点颜色线型曲线图一、plot函数(一)最简单的plot函数调用格式: plot(x)(1)plot函数的参数 X 为普通向量,(2)plot函数的参数 x 是复数向量,(二)plot(x, y)(1)plot(x, y) 的函数参数 (x, y 为 长度相同的向量)(2)plot(x, y)的函…...

    2024/4/21 14:29:02

最新文章

  1. 搜维尔科技:Varjo XR-4客户体验中,在VR体验中获得高层次的视觉保真度和沉浸感。

    Varjo XR-4系列是Varjo的最新一代头戴式显示器&#xff0c;其代表着世界领先的的混合现实技术和图形处理能力。新一代的XR-4更加迎合工业使用案例&#xff0c;在用户在VR体验中获得高层次的视觉保真度和沉浸感。 搜维尔科技&#xff1a;Varjo XR-4客户体验中&#xff0c;在VR…...

    2024/5/2 15:52:39
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 阿里云8核32G云服务器租用优惠价格表,包括腾讯云和京东云

    8核32G云服务器租用优惠价格表&#xff0c;云服务器吧yunfuwuqiba.com整理阿里云8核32G服务器、腾讯云8核32G和京东云8C32G云主机配置报价&#xff0c;腾讯云和京东云是轻量应用服务器&#xff0c;阿里云是云服务器ECS&#xff1a; 阿里云8核32G服务器 阿里云8核32G服务器价格…...

    2024/5/2 3:37:46
  4. C# 构建可定时关闭的异步提示弹窗

    C# 构建可定时关闭的异步提示弹窗 引言1、调用接口的实现2、自动定时窗口的实现 引言 我们在最常用最简单的提示弹框莫过于MessageBox.Show( )的方法了&#xff0c;但是使用久了之后&#xff0c;你会发现这个MessageBox并不是万能的&#xff0c;有事后并不想客户去点击&#x…...

    2024/5/2 6:14:07
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/1 17:30:59
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/30 18:14:14
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/29 2:29:43
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/2 9:28:15
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/27 17:58:04
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/28 1:28:33
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/30 9:43:09
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/27 17:59:30
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/5/2 15:04:34
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/28 1:34:08
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/29 20:46:55
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/30 22:21:04
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/1 4:32:01
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/27 23:24:42
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/28 5:48:52
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/30 9:42:22
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/2 9:07:46
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/30 9:42:49
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57