Reputation: 7114
Edit
I have followed these tutorials to fix this problem.
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/
But its annoying that problem still persists after trying several solutions. Here is demo for the problem i am facing.Its been weeks since i am stuck on this problem.
Link for demo.
Devices i am using for the testing are Nexus 4 and Nexus 5.
TabLayout
with ViewPager
isn't scrolling smooth. I need to swipe twice to shift on next tap. I have looked around the web but couldn't find any solution.
I am using latest support design library.
Here is gradle file
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'
}
Here is Activity code.
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;
}
}
And xml file
<?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>
Here is the screenshot you can see the indicator is partially divided.
Any solution?
Upvotes: 40
Views: 25636
Reputation: 131
If You are going to create TabLayout within a fragments then use getChildFragmentManager()
instead of getSupportFragmentManager()
as a parameter.
ViewPagerAdapter adapter = new ViewPagerAdapter(getChildFragmentManager());
Upvotes: 6
Reputation: 527
Change this line in your Activity:
ViewPagerAdapter adapter = new ViewPagerAdapter(getChildFragmentManager());
Upvotes: 18
Reputation: 5375
I just went through your code. The problem is that you are not providing any layout to inflate inside ContentFragment.java.
I changed your method to
@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);
}
After making these changes your tabs were scrolling smoothly. I don't know the reason behind this behaviour but this thing made it work
Upvotes: 38
Reputation: 1091
Please Set viewPager.setOffscreenPageLimit(1); to viewPager.setOffscreenPageLimit(5);
Upvotes: 4
Reputation: 2606
First of all, to make all smooth don't do heavy operations on main thread, use async tasks (don't touch views in async task), and all will be smooth in anyway :)
Try my way to do this:
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;
}
}
}
And how to use:
<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>
Toolbar as 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>
In 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;
}
}
And Setup Tabs
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>
Final notes: not posted here init of all variables, don't be lazy try to learn a bit ;)
Upvotes: 1
Reputation: 126
This is nothing new with android's coordinate layout and appBar layout; I am sure you won't be able to make it smoother no matter what you do. However
https://github.com/henrytao-me/smooth-app-bar-layout
this could fulfill your requirements; However firstly download the sample app from
https://play.google.com/store/apps/details?id=me.henrytao.smoothappbarlayout
to see if it fits your need.(just to be sure)
Upvotes: 1
Reputation: 178
In your Android manifest file add this line in <Application>
tag
android:largeHeap="true"
Upvotes: 0
Reputation: 11245
I think you need to use
override
methodsetUserVisibleHint
.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.
Read more about setUserVisibleHint
here.
Upvotes: 4
Reputation: 2181
Enable all the StrictMode policies on you app to detect any lengthy operations you may be inadvertently performing on the main thread, causing the lag, so that you can take the further required corrective measures.
StrictMode is a developer tool which detects things you might be doing by accident and brings them to your attention so you can fix them. StrictMode is most commonly used to catch accidental disk or network access on the application's main thread, where UI operations are received and animations take place.
Please see https://developer.android.com/reference/android/os/StrictMode.html for details.
// 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);
Upvotes: 2