带有 viewpager 的 TabLayout 滚动不流畅

TabLayout with viewpager not smooth scrolling

编辑

我已经按照这些教程解决了这个问题。

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/

但在尝试了多种解决方案后,问题仍然存在,这很烦人。这是问题的演示,我 facing.Its 已经好几周没被困在这个问题上了。

Link 用于演示。

我用于测试的设备是 Nexus 4 和 Nexus 5。

TabLayoutViewPager 滚动不流畅。我需要滑动两次才能在下次点击时移动。我环顾了网络,但找不到任何解决方案。 我正在使用最新的支持设计库。 这里是 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'
}

这是Activity代码。

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>

这是您可以看到指标被部分分割的屏幕截图。

有什么解决办法吗?

在您的 Android 清单文件 中将此行添加到 <Application> 标签

 android:largeHeap="true" 

在您的应用上启用所有 StrictMode 策略以检测您可能无意中在主线程上执行的任何冗长操作,从而导致延迟,以便您可以采取进一步的必要纠正措施。

StrictMode 是一种开发人员工具,可以检测您可能无意中做的事情并提醒您注意它们,以便您进行修复。 StrictMode 最常用于捕获应用程序主线程上的意外磁盘或网络访问,其中接收 UI 操作并发生动画。

详情请见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);

I think you need to use override method setUserVisibleHint.

You need to add this in your Fragment.

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

Make your offScreenPageLimit to NUMBER OF TABS you have.

详细了解 setUserVisibleHint here

这对于android的坐标布局和appBar布局来说并不是什么新鲜事;我敢肯定,无论您做什么,都无法使它变得更顺畅。 然而

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

这可以满足您的要求; 但是首先从

下载示例应用程序
https://play.google.com/store/apps/details?id=me.henrytao.smoothappbarlayout

看看它是否符合您的需要。(只是为了确定)

首先,为了让一切顺利,不要在主线程上进行大量操作,使用异步任务(不要在异步任务中触摸视图),无论如何都会顺利:)

试试我的方法:

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>

工具栏作为应用栏:

<?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>

在Activity中:

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>

最后说明:这里不贴出所有变量的初始化,大家不要偷懒尝试学习一下;)

请设置viewPager.setOffscreenPageLimit(1);到 viewPager.setOffscreenPageLimit(5);

我刚刚查看了您的代码。问题是您没有提供任何布局以在 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);

    }

进行这些更改后,您的标签页滚动顺畅。我不知道这种行为背后的原因,但这件事让它起作用

在 Activity 中更改此行:

ViewPagerAdapter adapter = new ViewPagerAdapter(getChildFragmentManager());

如果您要在片段中创建 TabLayout,则使用 getChildFragmentManager() 而不是 getSupportFragmentManager() 作为参数。

ViewPagerAdapter adapter = new ViewPagerAdapter(getChildFragmentManager());