29

EditTabLayout с ViewPager не гладкой прокрутки

Я следовал за эти учебники, чтобы исправить эту проблему.

http://www.truiton.com/2015/06/android-tabs-example-fragments-viewpager/ https://guides.codepath.com/android/google-play-style-tabs-using-tablayout http://www.voidynullness.net/blog/2015/08/16/android-tablayout-design-support-library-tutorial/

Но его раздражает, что проблема все еще сохраняется после попытки несколько решений. Вот демо для проблемы, с которой я столкнулся. Это были недели с тех пор, как я застрял в этой проблеме.

Link для демонстрации.

устройства я использую для тестирования в Nexus 4 и Nexus 5.

TabLayout с ViewPager не прокрутка гладко. Мне нужно дважды проскользнуть, чтобы перейти дальше. Я просмотрел сеть, но не нашел решения. Я использую новейшую библиотеку дизайна поддержки. Вот Gradle файлу

apply plugin: 'com.android.application' 

android { 
compileSdkVersion 23 
buildToolsVersion "23.0.3" 

defaultConfig { 
    applicationId "com.softoven.ultron" 
    minSdkVersion 15 
    targetSdkVersion 23 
    versionCode 1 
    versionName "1.0" 
} 
buildTypes { 
    release { 
     minifyEnabled false 
     proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 
    } 
} 
} 

dependencies { 
compile fileTree(dir: 'libs', include: ['*.jar']) 
testCompile 'junit:junit:4.12' 
compile 'com.android.support:appcompat-v7:23.3.0' 
compile 'com.android.support:design:23.3.0' 
compile 'org.jsoup:jsoup:1.6.1' 
compile 'com.mikhaellopez:circularimageview:3.0.0' 
compile 'com.android.support:recyclerview-v7:23.3.0' 
compile 'com.mcxiaoke.volley:library:1.0.19' 
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' 
compile 'com.google.code.gson:gson:2.5' 
} 

Вот код активности.

private DrawerLayout drawerLayout; 
private ViewPager viewPager; 
private TabLayout tabLayout; 
private NavigationView navigationView; 
private CategoriesDTO categoriesDTO; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    initToolbar(); 
    initUi(); 
    loadCategories(); 
} 

private void initToolbar() { 
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 
    setSupportActionBar(toolbar); 
    getSupportActionBar().setDisplayHomeAsUpEnabled(true); 
    getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_action_menu); 
} 

private void initUi() { 
    drawerLayout = (DrawerLayout) findViewById(R.id.drawer); 
    navigationView = (NavigationView) findViewById(R.id.navigation); 
    viewPager = (ViewPager) findViewById(R.id.viewPager); 
    tabLayout = (TabLayout) findViewById(R.id.tab); 

} 

private void loadCategories() { 
    StringRequest request = new StringRequest(Constants.URL_GET_CATEGORIES, new Response.Listener<String>() { 
     @Override 
     public void onResponse(String response) { 
      categoriesDTO = Constants.gson.fromJson(response, CategoriesDTO.class); 
      ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager()); 
      viewPager.setOffscreenPageLimit(1); 
      viewPager.setAdapter(adapter); 
      setTabLayout(); 
     } 
    }, new Response.ErrorListener() { 
     @Override 
     public void onErrorResponse(VolleyError error) { 

     } 
    }); 

    ApplicationController.getmInstance().addToRequestQueue(request); 
} 

private void setTabLayout() { 

    tabLayout.setupWithViewPager(viewPager); 

} 


@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    MenuInflater menuInflater = getMenuInflater(); 
    menuInflater.inflate(R.menu.home_side_menu, menu); 
    return true; 
} 

@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
    int id = item.getItemId(); 
    switch (id) { 
     case android.R.id.home: 
      drawerLayout.openDrawer(GravityCompat.START); 
      return true; 
    } 
    return super.onOptionsItemSelected(item); 
} 

private class ViewPagerAdapter extends FragmentPagerAdapter { 

    public ViewPagerAdapter(FragmentManager fm) { 
     super(fm); 
    } 

    @Override 
    public Fragment getItem(int position) { 
     return new ContentFragment(); 
    } 

    @Override 
    public int getCount() { 
     return 10; 
    } 

    @Override 
    public CharSequence getPageTitle(int position) { 
     String title = categoriesDTO.getCategories().get(position).getTitle(); 
     return (CharSequence) title; 
    } 
} 

И XML файл

<?xml version="1.0" encoding="utf-8"?> 

<android.support.design.widget.CoordinatorLayout 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 


    <android.support.design.widget.AppBarLayout 
     android:id="@+id/app_bar" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content"> 

     <include 
      android:id="@+id/toolbar" 
      layout="@layout/toolbar" 
      app:layout_scrollFlags="scroll|enterAlways" 
      app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> 

     <android.support.design.widget.TabLayout 
      android:id="@+id/tab" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      app:tabTextColor="#fff" 
      app:tabGravity="fill" 
      app:tabMode="scrollable" 
      > 

     </android.support.design.widget.TabLayout> 
    </android.support.design.widget.AppBarLayout> 

    <android.support.v4.view.ViewPager 
     android:id="@+id/viewPager" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     app:layout_behavior="@string/appbar_scrolling_view_behavior"> 

    </android.support.v4.view.ViewPager> 
</android.support.design.widget.CoordinatorLayout> 

<android.support.design.widget.NavigationView 
    android:id="@+id/navigation" 
    android:layout_width="wrap_content" 
    android:layout_height="match_parent" 
    android:layout_gravity="start" 
    app:menu="@menu/home_drawer_menu"> 

</android.support.design.widget.NavigationView> 

Вот скриншот можно увидеть индикатор частично разделена.

enter image description here

Любое решение?

+0

Выполняете ли вы работу над основной нитью при изменении вкладки? – Ritesh

+0

Нет. У меня есть только один фрагмент, статичный прямо сейчас. –

+0

@ ZeeshanShabbir Возможно, это связано с тем, что у вас есть запрос сервера волейбола. –

ответ

20

Я просто просмотрел ваш код. Проблема в том, что вы не предоставляете макет для раздувания внутри ContentFragment.java.

Я изменил свой метод

@Nullable 
    @Override 
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 
     //return super.onCreateView(inflater, container, savedInstanceState); 
     return inflater.inflate(R.layout.feed_item, container, false); 

    } 

После внесения этих изменений ваших вкладок были прокрутка гладко.Я не знаю причину такого поведения, но это дело сделало работу

+0

В моем случае я не переопределил onCreateView из своего фрагмента (попробовав пример приложения), поэтому я столкнулся с проблемой с прокруткой. После возвращения представления из onCreateView фрагмента проблема была решена. – Prashant

0

В вашем файле манифеста Android добавить эту строку в <Application> теге

android:largeHeap="true" 
+0

, что этот тег будет делать? –

+0

Увеличивает размер кучи. и может быть ваш просмотрщик быстрее прокручивается ... – Krupa

+0

нет, он не работает –

1

Включить все политики StrictMode на вас приложение, чтобы обнаружить какие-либо длительные операции, которые могут быть непреднамеренно выступать на главном потоке, вызывая задержку , чтобы вы могли предпринять дальнейшие необходимые корректирующие меры.

StrictMode - инструмент разработчика, который обнаруживает, что вы случайно делаете, и привлекает их к себе, чтобы вы могли их исправить. StrictMode чаще всего используется для обнаружения случайного доступа к диску или сети в основном потоке приложения, где выполняются операции пользовательского интерфейса и происходят анимации.

Подробнее см. https://developer.android.com/reference/android/os/StrictMode.html.

// Enable all thread strict mode policies 
    StrictMode.ThreadPolicy.Builder threadPolicyBuilder = new StrictMode.ThreadPolicy.Builder(); 

    // Detect everything that's potentially suspect 
    threadPolicyBuilder.detectAll(); 

    // Crash the whole process on violation 
    threadPolicyBuilder.penaltyDeath(); 

    // Log detected violations to the system log 
    threadPolicyBuilder.penaltyLog(); 

    // Crash the whole process on any network usage. 
    threadPolicyBuilder.penaltyDeathOnNetwork(); 


    StrictMode.ThreadPolicy threadPolicy = threadPolicyBuilder.build(); 
    StrictMode.setThreadPolicy(threadPolicy); 

    // Enable all VM strict mode policies 
    StrictMode.VmPolicy.Builder vmPolicyBuilder = new StrictMode.VmPolicy.Builder(); 

    // Detect everything that's potentially suspect 
    vmPolicyBuilder.detectAll(); 

    // Log detected violations to the system log 
    vmPolicyBuilder.penaltyLog(); 

    StrictMode.VmPolicy vmPolicy = vmPolicyBuilder.build(); 
    StrictMode.setVmPolicy(vmPolicy); 
+0

, пожалуйста, объясните, что этот код будет делать? –

+0

Добавлено дополнительное объяснение. Комментарии уже предоставлены для каждой строки кода. – Chebyr

2

Я думаю, вам нужно использовать метод overridesetUserVisibleHint.

Вам необходимо добавить это в ваш Fragment.

@Override 
public void setUserVisibleHint(boolean isVisibleToUser) { 
    super.setUserVisibleHint(isVisibleToUser); 
    if (isVisibleToUser) { 
     // load data here 
    }else{ 
     // fragment is no longer visible 
    } 
} 

Сделайте свой offScreenPageLimit на количество вкладок у вас есть.

Подробнее о setUserVisibleHinthere.

+0

Как это исправить свиток? –

+0

Вы читали ссылку? –

+0

Сделайте свой offScreenPageLimit равным NUMBER TABS. –

1

Это ничего нового с компоновкой координат android и макета appBar; Я уверен, что вы не сможете сделать его более гладким, независимо от того, что вы делаете. Однако

https://github.com/henrytao-me/smooth-app-bar-layout 

это может выполнить ваши требования; Однако во-первых, загрузить приложение образца из

https://play.google.com/store/apps/details?id=me.henrytao.smoothappbarlayout 

, чтобы увидеть, если она соответствует вашим потребностям. (Просто чтобы быть уверенным)

+0

На самом деле использование примера приложения не решает проблему, ее альтернатива и решение от Ankit Aggarwal работают отлично. – Prashant

0

Прежде всего, чтобы сделать все гладко, не делать тяжелые операции на главном потоке , использование асинхронных задач (не трогают представлений в асинхронном задаче), и все будет гладко в любом случае :)

Попробуйте мой способ сделать это:

SlidingTabLayout:

public class SlidingTabLayout extends HorizontalScrollView { 
    /** 
    * Allows complete control over the colors drawn in the tab layout. Set with 
    * {@link #setCustomTabColorizer(TabColorizer)}. 
    */ 
    View oldSelection = null; 

    public interface TabColorizer { 

     /** 
     * @return return the color of the indicator used when {@code position} is selected. 
     */ 
     int getIndicatorColor(int position); 

    } 

    private static final int TITLE_OFFSET_DIPS = 24; 
    private static final int TAB_VIEW_PADDING_DIPS = 8; 
    private static final int TAB_VIEW_TEXT_SIZE_SP = 12; 

    private int mTitleOffset; 

    private int mTabViewLayoutId; 
    private int mTabViewTextViewId; 
    private boolean mDistributeEvenly; 

    private ViewPager mViewPager; 
    private SparseArray<String> mContentDescriptions = new SparseArray<String>(); 
    private ViewPager.OnPageChangeListener mViewPagerPageChangeListener; 

    private final SlidingTabStrip mTabStrip; 

    public SlidingTabLayout(Context context) { 
     this(context, null); 
    } 

    public SlidingTabLayout(Context context, AttributeSet attrs) { 
     this(context, attrs, 0); 
    } 

    public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 

     // Disable the Scroll Bar 
     setHorizontalScrollBarEnabled(false); 
     // Make sure that the Tab Strips fills this View 
     setFillViewport(true); 

     mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density); 

     mTabStrip = new SlidingTabStrip(context); 
     addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 
    } 


    public void hideTab(int tabIndex){ 
     for (int i = 0; i < mTabStrip.getChildCount(); i++) { 
      if(i == tabIndex){ 
       ((TextView)mTabStrip.getChildAt(i)).setVisibility(GONE); 
      } 
     } 


    } 

    /** 
    * Set the custom {@link TabColorizer} to be used. 
    * 
    * If you only require simple custmisation then you can use 
    * {@link #setSelectedIndicatorColors(int...)} to achieve 
    * similar effects. 
    */ 
    public void setCustomTabColorizer(TabColorizer tabColorizer) { 
     mTabStrip.setCustomTabColorizer(tabColorizer); 
    } 

    public void setDistributeEvenly(boolean distributeEvenly) { 
     mDistributeEvenly = distributeEvenly; 
    } 

    /** 
    * Sets the colors to be used for indicating the selected tab. These colors are treated as a 
    * circular array. Providing one color will mean that all tabs are indicated with the same color. 
    */ 
    public void setSelectedIndicatorColors(int... colors) { 
     mTabStrip.setSelectedIndicatorColors(colors); 
    } 

    /** 
    * Set the {@link ViewPager.OnPageChangeListener}. When using {@link SlidingTabLayout} you are 
    * required to set any {@link ViewPager.OnPageChangeListener} through this method. This is so 
    * that the layout can update it's scroll position correctly. 
    * 
    * @see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener) 
    */ 
    public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) { 
     mViewPagerPageChangeListener = listener; 
    } 

    /** 
    * Set the custom layout to be inflated for the tab views. 
    * 
    * @param layoutResId Layout id to be inflated 
    * @param textViewId id of the {@link TextView} in the inflated view 
    */ 
    public void setCustomTabView(int layoutResId, int textViewId) { 
     mTabViewLayoutId = layoutResId; 
     mTabViewTextViewId = textViewId; 
    } 

    /** 
    * Sets the associated view pager. Note that the assumption here is that the pager content 
    * (number of tabs and tab titles) does not change after this call has been made. 
    */ 
    public void setViewPager(ViewPager viewPager) { 
     mTabStrip.removeAllViews(); 

     mViewPager = viewPager; 
     if (viewPager != null) { 
      viewPager.setOnPageChangeListener(new InternalViewPagerListener()); 
      populateTabStrip(); 
     } 
    } 

    /** 
    * Create a default view to be used for tabs. This is called if a custom tab view is not set via 
    * {@link #setCustomTabView(int, int)}. 
    */ 
    protected TextView createDefaultTabView(Context context) { 
     TextView textView = new TextView(context); 
     textView.setGravity(Gravity.CENTER); 
     textView.setTextSize(16); 
     textView.setTypeface(Constants.TYPE_FACE_FONT_MEDIUM); 
     textView.setLayoutParams(new LinearLayout.LayoutParams(
       ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); 

     TypedValue outValue = new TypedValue(); 
     getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, 
       outValue, true); 
     textView.setBackgroundResource(outValue.resourceId); 
     if(Constants.PRODUCT_DETAILS_TAB_BAR_STYLE == 2) { 
      textView.setBackgroundColor(getResources().getColor(R.color.tab_bar_color)); 
      mTabStrip.setBackgroundColor(getResources().getColor(R.color.tab_bar_color)); 
     } 

     textView.setAllCaps(true); 

     int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density); 
     textView.setPadding(padding, padding, padding, padding); 

     return textView; 
    } 

    private void populateTabStrip() { 
     removeOldSelection(); 
     oldSelection = null; 
     final PagerAdapter adapter = mViewPager.getAdapter(); 
     final View.OnClickListener tabClickListener = new TabClickListener(); 

     for (int i = 0; i < adapter.getCount(); i++) { 
      View tabView = null; 
      TextView tabTitleView = null; 

      if (mTabViewLayoutId != 0) { 
       // If there is a custom tab view layout id set, try and inflate it 
       tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip, 
         false); 
       tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId); 
      } 

      if (tabView == null) { 
       tabView = createDefaultTabView(getContext()); 
      } 

      if (tabTitleView == null && TextView.class.isInstance(tabView)) { 
       tabTitleView = (TextView) tabView; 
      } 

      if (mDistributeEvenly) { 
       LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) tabView.getLayoutParams(); 
       lp.width = 0; 
       lp.weight = 1; 
      } 

      tabTitleView.setText(adapter.getPageTitle(i)); 

      tabView.setOnClickListener(tabClickListener); 
      String desc = mContentDescriptions.get(i, null); 
      if (desc != null) { 
       tabView.setContentDescription(desc); 
      } 

      mTabStrip.addView(tabView); 
      if(Constants.PRODUCT_DETAILS_TAB_BAR_STYLE == 1) 
       tabTitleView.setTextColor(getResources().getColorStateList(R.color.primary_ultralight)); 
      else 
       tabTitleView.setTextColor(getResources().getColor(R.color.primary_text)); 
      if (i == mViewPager.getCurrentItem()) { 
       tabView.setSelected(true); 
       tabTitleView.setTextColor(getResources().getColorStateList(R.color.primary_ultralight)); 
      } 

     } 

    } 

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

    @Override 
    protected void onAttachedToWindow() { 
     super.onAttachedToWindow(); 

     if (mViewPager != null) { 
      scrollToTab(mViewPager.getCurrentItem(), 0); 
     } 
    } 

    private void scrollToTab(int tabIndex, int positionOffset) { 
     final int tabStripChildCount = mTabStrip.getChildCount(); 
     if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) { 
      return; 
     } 

     View selectedChild = mTabStrip.getChildAt(tabIndex); 
     if (selectedChild != null) { 

      if(positionOffset == 0 && selectedChild != oldSelection) { // added part 
       selectedChild.setSelected(true); 
       removeOldSelection(); 
       oldSelection = selectedChild; 
      } 

      int targetScrollX = selectedChild.getLeft() + positionOffset; 

      if (tabIndex > 0 || positionOffset > 0) { 
       // If we're not at the first child and are mid-scroll, make sure we obey the offset 
       targetScrollX -= mTitleOffset; 
      } 

      scrollTo(targetScrollX, 0); 
     } 
    } 

    private class InternalViewPagerListener implements ViewPager.OnPageChangeListener { 
     private int mScrollState; 

     @Override 
     public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 
      int tabStripChildCount = mTabStrip.getChildCount(); 
      if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) { 
       return; 
      } 

      mTabStrip.onViewPagerPageChanged(position, positionOffset); 

      View selectedTitle = mTabStrip.getChildAt(position); 
      int extraOffset = (selectedTitle != null) 
        ? (int) (positionOffset * selectedTitle.getWidth()) 
        : 0; 
      scrollToTab(position, extraOffset); 

      if (mViewPagerPageChangeListener != null) { 
       mViewPagerPageChangeListener.onPageScrolled(position, positionOffset, 
         positionOffsetPixels); 
      } 
     } 

     @Override 
     public void onPageScrollStateChanged(int state) { 
      mScrollState = state; 

      if (mViewPagerPageChangeListener != null) { 
       mViewPagerPageChangeListener.onPageScrollStateChanged(state); 
      } 
     } 

     @Override 
     public void onPageSelected(int position) { 
      if (mScrollState == ViewPager.SCROLL_STATE_IDLE) { 
       mTabStrip.onViewPagerPageChanged(position, 0f); 
       scrollToTab(position, 0); 
      } 
      for (int i = 0; i < mTabStrip.getChildCount(); i++) { 
       mTabStrip.getChildAt(i).setSelected(position == i); 

       if(Constants.PRODUCT_DETAILS_TAB_BAR_STYLE == 2){ 
        if(position == i) 
         ((TextView)mTabStrip.getChildAt(i)).setTextColor(getResources().getColorStateList(R.color.primary_ultralight)); 
        else 
         ((TextView)mTabStrip.getChildAt(i)).setTextColor(getResources().getColor(R.color.primary_text)); 
       } 




      } 
      if (mViewPagerPageChangeListener != null) { 
       mViewPagerPageChangeListener.onPageSelected(position); 
      } 
     } 

    } 
    private void removeOldSelection() { 
     if(oldSelection != null) { 
      oldSelection.setSelected(false); 
     } 
    } 
    private class TabClickListener implements View.OnClickListener { 
     @Override 
     public void onClick(View v) { 
      for (int i = 0; i < mTabStrip.getChildCount(); i++) { 
       if (v == mTabStrip.getChildAt(i)) { 
        mViewPager.setCurrentItem(i); 
        return; 
       } 
      } 
     } 
    } 

} 

SlidingTabStrip:

class SlidingTabStrip extends LinearLayout { 

    private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 0; 
    private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26; 
    private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 3; 
    private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5; 

    private final int mBottomBorderThickness; 
    private final Paint mBottomBorderPaint; 

    private final int mSelectedIndicatorThickness; 
    private final Paint mSelectedIndicatorPaint; 

    private final int mDefaultBottomBorderColor; 

    private int mSelectedPosition; 
    private float mSelectionOffset; 

    private SlidingTabLayout.TabColorizer mCustomTabColorizer; 
    private final SimpleTabColorizer mDefaultTabColorizer; 

    SlidingTabStrip(Context context) { 
     this(context, null); 
    } 

    SlidingTabStrip(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     setWillNotDraw(false); 

     final float density = getResources().getDisplayMetrics().density; 

     TypedValue outValue = new TypedValue(); 
     context.getTheme().resolveAttribute(android.R.attr.colorForeground, outValue, true); 
     final int themeForegroundColor = outValue.data; 

     mDefaultBottomBorderColor = setColorAlpha(themeForegroundColor, 
       DEFAULT_BOTTOM_BORDER_COLOR_ALPHA); 

     mDefaultTabColorizer = new SimpleTabColorizer(); 
     mDefaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR); 

     mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density); 
     mBottomBorderPaint = new Paint(); 
     mBottomBorderPaint.setColor(mDefaultBottomBorderColor); 

     mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density); 
     mSelectedIndicatorPaint = new Paint(); 
    } 

    void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColorizer) { 
     mCustomTabColorizer = customTabColorizer; 
     invalidate(); 
    } 

    void setSelectedIndicatorColors(int... colors) { 
     // Make sure that the custom colorizer is removed 
     mCustomTabColorizer = null; 
     mDefaultTabColorizer.setIndicatorColors(colors); 
     invalidate(); 
    } 

    void onViewPagerPageChanged(int position, float positionOffset) { 
     mSelectedPosition = position; 
     mSelectionOffset = positionOffset; 
     invalidate(); 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 
     final int height = getHeight(); 
     final int childCount = getChildCount(); 
     final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null 
       ? mCustomTabColorizer 
       : mDefaultTabColorizer; 

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

      if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) { 
       int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1); 
       if (color != nextColor) { 
        color = blendColors(nextColor, color, mSelectionOffset); 
       } 

       // Draw the selection partway between the tabs 
       View nextTitle = getChildAt(mSelectedPosition + 1); 
       left = (int) (mSelectionOffset * nextTitle.getLeft() + 
         (1.0f - mSelectionOffset) * left); 
       right = (int) (mSelectionOffset * nextTitle.getRight() + 
         (1.0f - mSelectionOffset) * right); 
      } 

      mSelectedIndicatorPaint.setColor(color); 

      canvas.drawRect(left, height - mSelectedIndicatorThickness, right, 
        height, mSelectedIndicatorPaint); 
     } 

     // Thin underline along the entire bottom edge 
     canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint); 
    } 

    /** 
    * Set the alpha value of the {@code color} to be the given {@code alpha} value. 
    */ 
    private static int setColorAlpha(int color, byte alpha) { 
     return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color)); 
    } 

    /** 
    * Blend {@code color1} and {@code color2} using the given ratio. 
    * 
    * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend, 
    *    0.0 will return {@code color2}. 
    */ 
    private static int blendColors(int color1, int color2, float ratio) { 
     final float inverseRation = 1f - ratio; 
     float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation); 
     float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation); 
     float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation); 
     return Color.rgb((int) r, (int) g, (int) b); 
    } 

    private static class SimpleTabColorizer implements SlidingTabLayout.TabColorizer { 
     private int[] mIndicatorColors; 

     @Override 
     public final int getIndicatorColor(int position) { 
      return mIndicatorColors[position % mIndicatorColors.length]; 
     } 

     void setIndicatorColors(int... colors) { 
      mIndicatorColors = colors; 
     } 
    } 
} 

И как использовать:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:background="@color/layouts_background" 
    android:layout_height="match_parent"> 

     <LinearLayout 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" 
      android:orientation="vertical"> 
      <RelativeLayout 
       android:id="@+id/page_root_container" 
       android:layout_width="match_parent" 
       android:layout_height="match_parent" 
       android:orientation="vertical"> 
       <include 
        android:id="@+id/app_bar" 
        layout="@layout/app_bar"/> 
       <LinearLayout 
        android:layout_width="match_parent" 
        android:layout_height="match_parent" 
        android:layout_below="@+id/app_bar" 
        android:orientation="vertical"> 
        <com.app.myapp.tab.SlidingTabLayout 
         android:id="@+id/detailsTabs" 
         android:layout_width="match_parent" 
         android:layout_height="wrap_content"> 

        </com.app.myapp.tab.SlidingTabLayout> 
        <android.support.v4.view.ViewPager 
         android:id="@+id/detailsPager" 
         android:layout_width="match_parent" 
         android:layout_height="0dp" 
         android:layout_weight="1"> 
        </android.support.v4.view.ViewPager> 
       </LinearLayout> 
      </RelativeLayout> 
     </LinearLayout> 
</RelativeLayout> 

панель инструментов, как AppBar:

<?xml version="1.0" encoding="utf-8"?> 
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    android:layout_width="match_parent" 
    android:layout_height="?android:attr/actionBarSize" 
    android:background="@color/primary" 
    app:theme="@style/CustomToolbarTheme"> 


</android.support.v7.widget.Toolbar> 

В деятельности:

class DetailsTabsAdaptor extends FragmentPagerAdapter { 
     String [] tabsTitlesPrepare = {getString(R.string.details),getString(R.string.features), getString(R.string.spects), getString(R.string.downloads)}; 
     List<String> tabsTitles = new ArrayList<>(); 
     int tabsCount = 0; 
     boolean featuresExist = false; 
     boolean specificationsExist = false; 
     boolean downloadsExist = false; 

     public DetailsTabsAdaptor(FragmentManager fm) { 
      super(fm); 
      tabsTitles.add(tabsTitlesPrepare[0]); 
      tabsCount++; 
      if ((mProductDetails.ProductStructure.Features != null && mProductDetails.ProductStructure.Features.size()>0)) { 
       tabsTitles.add(tabsTitlesPrepare[1]); 
       featuresExist = true; 
       tabsCount++; 
      } 
      if ((mProductDetails.ProductStructure.SpecificationBlocks != null && mProductDetails.ProductStructure.SpecificationBlocks.size()>0)) { 
       tabsTitles.add(tabsTitlesPrepare[2]); 
       specificationsExist = true; 
       tabsCount++; 
      } 
      if ((mProductDetails.ProductStructure.SupportFiles != null && mProductDetails.ProductStructure.SupportFiles.size()>0)) { 
       tabsTitles.add(tabsTitlesPrepare[3]); 
       downloadsExist = true; 
       tabsCount++; 
      } 

     } 

     @Override 
     public CharSequence getPageTitle(int position) { 
      return tabsTitles.get(position); 
     } 

     @Override 
     public Fragment getItem(int position) { 
      if(position == 0){ 
       ProductDetailsFragment fragment = new ProductDetailsFragment(); 
       return fragment; 
      } 
      if(position == 1 && featuresExist){ 
       ProductFeaturesFragment fragment = new ProductFeaturesFragment(); 
       return fragment; 
      } 
      if((position == 2 && specificationsExist) || (position == 1 && (!featuresExist) && specificationsExist)){ 
       ProductSpectsFragment fragment = new ProductSpectsFragment(); 
       return fragment; 
      } 
      if((position == 3 && downloadsExist) || (position == 1 && (!featuresExist) && (!specificationsExist) && downloadsExist) || 
        (position == 2 && (!specificationsExist) && downloadsExist)){ 
       ProductDownloadsFragment fragment = new ProductDownloadsFragment(); 
       return fragment; 
      } 

      return null; 
     } 

     @Override 
     public int getCount() { 
      return tabsCount; 
     } 
    } 

и настройка Вкладки

public void setupTabs() { 
     mDetailsPager.setAdapter(new DetailsTabsAdaptor(getSupportFragmentManager())); 
     mDetailsTabs.setViewPager(mDetailsPager); 
     mDetailsTabs.setBackgroundResource(R.color.primary); 
     mDetailsTabs.setCustomTabView(R.layout.custom_details_view_tab_layout, R.id.tabText); 
     mDetailsTabs.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() { 
      @Override 
      public int getIndicatorColor(int position) { 
       return getResources().getColor(R.color.primary_light); 
      } 
     }); 


     mDetailsTabs.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { 
      @Override 
      public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 
      } 

      @Override 
      public void onPageSelected(int position) { 

       for (int i = 0; i < mDetailsTabs.getChildCount(); i++) 
        mDetailsTabs.getChildAt(i).setSelected(i == position); 
       if (position == DESCRIPTION_PAGE_ID) 
        mFavoritesButton.setVisibility(View.VISIBLE); 
       else 
        mFavoritesButton.setVisibility(View.GONE); 

      } 

      @Override 
      public void onPageScrollStateChanged(int state) { 
      } 
     }); 

    } 

custom_details_view_tab_layout:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="match_parent" 
    android:background="@color/primary" 
    android:layout_height="match_parent"> 
    <com.avad.avaddroid.customModels.TextViewMedium 
     android:id="@+id/tabText" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:textColor="@color/primary_light" 
     android:layout_gravity="center"/> 

</LinearLayout> 

Заключительные замечания: не писал здесь инициализации всех переменных, не поленитесь пытаются узнать немного;)

1

УСАНОВИТЕ viewPager.setOffscreenPageLimit (1); viewPager.setOffscreenPageLimit (5);

5

Измените эту строку в вашей деятельности:

ViewPagerAdapter adapter = new ViewPagerAdapter(getChildFragmentManager()); 
2

Если Вы собираетесь создать TabLayout в пределах фрагментов используйте getChildFragmentManager() вместо getSupportFragmentManager() как параметр.

ViewPagerAdapter adapter = new ViewPagerAdapter(getChildFragmentManager());