Okay, I decided that using TabHost would be nice in my little app.
However, under Android 6.0+, TabActivity and several others have been deprecated.
So I have written this:
public class TabMain extends Activity{
#Override
protected void onCreate(Bundle bundle){
super.onCreate(bundle);
setContentView(R.layout.tab_main);
TabHost tabHost = (TabHost)findViewById(R.id.tab_main_tabhost);
tabHost.setup();//several lines here....}}
And when I run this code, IDE throws me an RuntimtException:
"java.lang.IllegalStateException: Did you forget to call 'public void setup(LocalActivityManager activityGroup)'?"
And I found out that ActivityGroup is also deprecated.
How should I bypass this?
try this
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabGravity="fill"/>
<android.support.v4.view.ViewPager
android:id="#+id/home_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
in your activity
viewPager = (ViewPager) findViewById(R.id.home_viewpager);
viewPager.setOffscreenPageLimit(4);
if (viewPager != null) {
setupViewPager(viewPager);
}
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
method is
private void setupViewPager(ViewPager viewPager) {
adapter = new Adapter(getSupportFragmentManager());
adapter.addFragment(new Store(), "Store");//fragment class name
adapter.addFragment(new Post(), "GG Connect");//fragment class name
viewPager.setAdapter(adapter);
}
static class Adapter extends FragmentPagerAdapter {
private final List<Fragment> mFragments = new ArrayList<>();
private final List<String> mFragmentTitles = new ArrayList<>();
public Adapter(FragmentManager fm) {
super(fm);
}
public void addFragment(Fragment fragment, String title) {
mFragments.add(fragment);
mFragmentTitles.add(title);
}
#Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
#Override
public int getCount() {
return mFragments.size();
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitles.get(position);
}
}
You should use TabLayout and ViewPager.
Here is an answer I found through hours search on internet Android Tabs with Fragements.
I think it's a viable solution here.
ViewPage and TabLayout are in the android.support package meaning they support the backward versions, that's the main reason why I chose not to use it. It's hard to even study the new version of android, and even harder to make backward-compatible code.
Related
I am developing an app that has a tab layout as the image.
I’d like to use MVVM architecture with data binding library but I am new with this framework.
I can do this without using MVVM by normally setup tab layout using ViewPager as this sample.
Normal tab layout without MVVM and data binding:
activity_main.xml:
<android.support.design.widget.CoordinatorLayout 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="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light" />
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabGravity="fill"/>
</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.design.widget.CoordinatorLayout>
MainActivity.java:
public class MainActivity extends AppCompatActivity {
private Toolbar toolbar;
private TabLayout tabLayout;
private ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
viewPager = (ViewPager) findViewById(R.id.viewpager);
setupViewPager(viewPager);
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new OneFragment(), "ONE");
adapter.addFragment(new TwoFragment(), "TWO");
adapter.addFragment(new ThreeFragment(), "THREE");
viewPager.setAdapter(adapter);
}
class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
}
Tab layout in MVVM:
When using MVVM with data binding library, we will have to use a view model for the tab layout view.
And I don’t know how to setup tab layout in the XML and also in the view model. How to handle events such as “tap on one tab of the layout” using data binding library
Is there any sample of using Tab layout in MVVM with data binding library?
Thanks for your help.
MainActivity -
public class MainActivity extends Activity
{
#Override
protected void onCreate(#Nullable final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
App.get(this).component().inject(this);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setHandler(this);
binding.setManager(getSupportFragmentManager());
}
#BindingAdapter({"bind:handler"})
public static void bindViewPagerAdapter(final ViewPager view, final MainActivity activity)
{
final MainActionsAdapter adapter = new MainActionsAdapter(view.getContext(), activity.getSupportFragmentManager());
view.setAdapter(adapter);
}
#BindingAdapter({"bind:pager"})
public static void bindViewPagerTabs(final TabLayout view, final ViewPager pagerView)
{
view.setupWithViewPager(pagerView, true);
}
}
xml -
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:fresco="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View" />
<variable
name="handler"
type="com.ui.main.MainActivity" />
<variable
name="manager"
type="android.support.v4.app.FragmentManager" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
app:title="#string/app_name"
app:titleMarginStart="8dp" />
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:pager="#{(pager)}">
</android.support.design.widget.TabLayout>
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:handler="#{handler}" />
</LinearLayout>
</layout>
Adapter -
public class MainSectionsAdapter extends FragmentPagerAdapter
{
private static final int CONTACTS = 0;
private static final int CALLS = 1;
private static final int CHATS = 2;
private static final int[] TABS = new int[]{CONTACTS, CALLS, CHATS};
private Context mContext;
public MainSectionsAdapter(final Context context, final FragmentManager fm)
{
super(fm);
mContext = context.getApplicationContext();
}
#Override
public Fragment getItem(int position)
{
switch (TABS[position])
{
case CONTACTS:
return ContactsFragment.newInstance();
case CALLS:
return CallsFragment.newInstance();
case CHATS:
return ChatsFragment.newInstance();
}
return null;
}
#Override
public int getCount()
{
return TABS.length;
}
#Override
public CharSequence getPageTitle(int position)
{
switch (TABS[position])
{
case CONTACTS:
return mContext.getResources().getString(R.string.contacts);
case CALLS:
return mContext.getResources().getString(R.string.calls);
case CHATS:
return mContext.getResources().getString(R.string.chats);
}
return null;
}
}
I'm not sure if this is newly introduced recently but with Android Support version 27.1.1, you don't even even need a custom data binding adapter, you can simply use:
<android.support.design.widget.TabLayout
android:id="#+id/tl_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:setupWithViewPager="#{some_fragment_viewpager}"
app:tabSelectedTextColor="#android:color/white"
app:tabTextColor="#color/v5_grey_55"
/>
<android.support.v4.view.ViewPager
android:id="#+id/some_fragment_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:addOnPageChangeListener="#{vm.pageChangeListener}"
app:setAdapter="#{vm.pageAdapter}"
app:setCurrentItem="#{vm.pageChangeListener.currentPosition}"
/>
Take note that the viewPager variable in app:setupWithViewPager="#{some_fragment_viewpager}" points to android:id="#+id/some_fragment_viewpager".
That's how the reference to the ViewPager is done (like magic I know)!
ViewModel
public class SomeViewModel {
public ViewPager.OnPageChangeListener pageChangeListener;
public SomeFragmentPagerAdapter pagerAdapter;
// ...
}
FragmentPagerAdapter
public classs SomeFragmentPagerAdapter extends FragmentPagerAdapter {
public Boolean currentPosition;
}
Here is my solution for setUpWithViewpager using databinding:
public class BindingUtil
{
#BindingAdapter({ "setUpWithViewpager" })
public static void setUpWithViewpager(final TabLayout tabLayout, ViewPager viewPager)
{
viewPager.addOnAdapterChangeListener(new ViewPager.OnAdapterChangeListener()
{
#Override
public void onAdapterChanged(#NonNull ViewPager viewPager, #Nullable PagerAdapter oldAdapter, #Nullable PagerAdapter newAdapter)
{
if (oldAdapter == null && (newAdapter == null || newAdapter.getCount() == 0))
{
// this function will helpful when
// we don't create viewpager immediately
// when view created (this mean we create
// will pager after a period time)
return;
}
tabLayout.setupWithViewPager(viewPager);
}
});
}
}
xml
<android.support.design.widget.TabLayout
...
app:setUpWithViewpager="#{ viewPager }"
/>
<android.support.v4.view.ViewPager
...
android:id="#+id/viewPager"
app:adapter="#{viewModel.pagerAdapter}"
/>
ViewModel
public class MainViewModel extends BaseObservable
{
#Bindable
public PagerAdapter getPagerAdapter()
{
return adapter;
}
private void createViewPagerAdapter()
{
...
notifyPropertyChanged(BR.pagerAdapter);
}
}
full demo project here
as Shown in Phan Van Linh's answer, It's working for me but it shows binding error while we provide viewPager's ID as reference to tabLayout in brackets.
I solved this by simply providing the id without brackets and also provide ViewPager's ID in camelCase.
I have struggled in the past couple of days to find the solution to this problem:
I have one activity which contains a tab layout and a view pager. The view pager is filled with fragments using an adapter. Tabs are created with this viewpager and are fixed. My question is how can I change the layout of tabs dynamically (for example after a button click) ?
This is xml file
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.Dark" />
<android.support.design.widget.TabLayout
android:id="#+id/tablayout"
android:layout_width="match_parent"
android:layout_height="65dp"
android:background="#color/white"
app:tabMode="fixed"
app:tabGravity="fill"
android:theme="#style/ThemeOverlay.AppCompat.Dark" />
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
This is Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupToolbar();
viewPager = (ViewPager) findViewById(R.id.viewpager);
setupViewPager(viewPager);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tablayout);
setupTabLayout(tabLayout);
}
private void setupToolbar(){
...
}
public void setupViewPager(ViewPager viewPager) {
pageAdapter = new FragmentPageAdapter(getApplicationContext(), getSupportFragmentManager());
pageAdapter.addFragment(ContentFragment.newInstance(), "Following", R.drawable.following);
pageAdapter.addFragment(ContentFragment.newInstance(), "Discover", R.drawable.flower);
pageAdapter.addFragment(ContentFragment.newInstance(), "", R.drawable.camera);
pageAdapter.addFragment(ProfileFragment.newInstance(), "Profile", R.drawable.profile);
pageAdapter.addFragment(ContentFragment.newInstance(), "Task List", R.drawable.list);
viewPager.setAdapter(pageAdapter);
}
public void setupTabLayout(TabLayout tabLayout) {
try {
tabLayout.setupWithViewPager(viewPager);
for (int i = 0; i < tabLayout.getTabCount(); i++) {
TabLayout.Tab tab = tabLayout.getTabAt(i);
tab.setCustomView(pageAdapter.getTabView(i));
}
tabLayout.requestFocus();
}
catch(Exception ex){
Log.e("errr2", ex.getMessage());
}
}
This is adapter:
public class FragmentPageAdapter extends FragmentStatePagerAdapter {
private Context mContext;
private List<Fragment> mFragments = new ArrayList<>();
private List<String> mFragmentTitles = new ArrayList<>();
private List<Integer> mFragmentIcons = new ArrayList<>();
public FragmentPageAdapter(Context context, FragmentManager fm) {
super(fm);
this.mContext = context;
}
public void addFragment(Fragment fragment, String title, int drawable) {
mFragments.add(fragment);
mFragmentTitles.add(title);
mFragmentIcons.add(drawable);
}
#Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
#Override
public int getItemPosition(Object object)
{
return POSITION_UNCHANGED;
}
#Override
public int getCount() {
return mFragments.size();
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitles.get(position);
}
public View getTabView(int position) {
View tab = LayoutInflater.from(mContext).inflate(R.layout.tabbar_view, null);
TextView tabText = (TextView) tab.findViewById(R.id.tabText);
ImageView tabImage = (ImageView) tab.findViewById(R.id.tabImage);
tabText.setText(mFragmentTitles.get(position));
tabImage.setBackgroundResource(mFragmentIcons.get(position));
if (position == 3) {
tab.setSelected(true);
}
return tab;
}
}
The normal way to replace a fragment is by calling
fragmentManager.beginTransaction().replace(placeholderId, editPrifileFragment).commit();
but what should I use for placeholderId in this case ? because in activity layout I don't have a placeholder for fragments, just a viewpager.
So how can I replace the fragment dynamically and also keep the back button functionality ?
I have searched a lot and found some hacky solutions , but I think this is a very common situation and should have a better solution.
thanks.
Your ViewPager Fragment should hold the placeholderId.
So in your Fragment (which is part of the ViewPager) you can call getChildFragmentManager() to add Fragment like you usually do.
childFragmentManager.beginTransaction().add(placeholderId, editPrifileFragment).addToBackStack(null).commit();
I'm following this example..
I'm having one issue, when I swipe on ViewPager respective fragment appear but when I swipe from from left to right or right to left and select previous Tab the Tab indicator appear on new selected Tab but respective fragment not appear on ViewPager.
Please help me, where I'm getting wrong?
It was bug in support lib 23.0.0 but it is solved in 23.0.1. First of all update your suppory library using SDK manager from the extras section.
and write the following line in app gradle file.
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:design:23.0.1'
for your reference
https://developer.android.com/topic/libraries/support-library/revisions.html
and read the Changes for Design Support library in Android Support Library, revision 23.0.1 section
This is what i use and works fine.
Adapter:
public class SCFragmentPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragments = new ArrayList<>();
private final List<String> mFragmentTitles = new ArrayList<>();
private Context mContext;
private FragmentManager mFragmentManager;
public SCFragmentPagerAdapter(FragmentManager fm, Context context) {
super(fm);
this.mFragmentManager = fm;
this.mContext = context;
}
#Override
public int getCount() {
return mFragments.size();
}
// Return the correct Fragment based on index
#Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
public void addFragment(Fragment fragment, String title) {
mFragments.add(fragment);
mFragmentTitles.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
// Return the tab title to SlidingTabLayout
return mFragmentTitles.get(position);
}
public Fragment getActiveFragment(ViewPager container, int position) {
String name = makeFragmentName(container.getId(), position);
return mFragmentManager.findFragmentByTag(name);
}
private static String makeFragmentName(int viewId, int index) {
return "android:switcher:" + viewId + ":" + index;
}
}
Activity:
public class SCWelcomeActivity extends AppCompatActivity implements
SCWelcomeFragment.OnFragmentInteractionListener,
SCSyncFragment.OnFragmentInteractionListener,
SCRegisterFragment.OnFragmentInteractionListener,
SCConfirmationFragment.OnFragmentInteractionListener {
private static final String TAG = SCWelcomeActivity.class.getSimpleName();
private ViewPager viewPager = null;
private TabLayout tabLayout = null;
private Toolbar toolbar = null;
private SCFragmentPagerAdapter adapter = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scwelcome);
// Layout manager that allows the user to flip through the pages
viewPager = (ViewPager) findViewById(R.id.viewpager);
setupViewPager(viewPager);
// Initialize the Sliding Tab Layout
tabLayout = (TabLayout) findViewById(R.id.tablayout);
// Connect the viewPager with the sliding tab layout
tabLayout.setupWithViewPager(viewPager);
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
#Override
public void onFragmentInteraction(Uri uri) {
}
private void setupViewPager(ViewPager viewPager) {
adapter = new SCFragmentPagerAdapter(getSupportFragmentManager(), SCWelcomeActivity.this);
adapter.addFragment(SCWelcomeFragment.newInstance(), getString(R.string.title_tab1));
adapter.addFragment(SCSyncFragment.newInstance(), getString(R.string.title_tab2));
adapter.addFragment(SCRegisterFragment.newInstance(), getString(R.string.title_tab3));
adapter.addFragment(SCConfirmationFragment.newInstance(), getString(R.string.title_tab4));
viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(4);
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
public void onFragmentInteraction(Uri uri);
}
}
Fragment Example :
public class SCWelcomeFragment extends Fragment {
private OnFragmentInteractionListener mListener;
public static SCWelcomeFragment newInstance() {
SCWelcomeFragment fragment = new SCWelcomeFragment();
return fragment;
}
public SCWelcomeFragment() {
super();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_scwelcome, container, false);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnFragmentInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
public void onFragmentInteraction(Uri uri);
}
}
Layout:
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent">
<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.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="130dp"
android:fitsSystemWindows="true"
android:gravity="bottom"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
android:layout_gravity="center"
android:theme="#style/ThemeOverlay.AppCompat.Dark"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light" />
<android.support.design.widget.TabLayout
android:id="#+id/tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
Please try to implement the adapter as i do. Pay close attention that in mine Adapter all instances are saved in the
private final List<Fragment> mFragments = new ArrayList<>();
In your case you are always returning a new instance. So that's why a set the setOffscreenPageLimit(4). to 4 so they are kept in memory as well.
In your activity, after find Views by Id, you should "config" your ViewPager and TabLayout. Some necessary features maybe: "addOnPageChangeListener" for ViewPager and "setOnTabSelectedListener" for your TabLayout like this:
public class MainActivity extends AppCompatActivity {
private final int numOfPages = 4; //viewpager has 4 pages
private final String[] pageTitle = {"Food", "Movie", "Shopping", "Travel"};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
for (int i = 0; i < numOfPages; i++) {
tabLayout.addTab(tabLayout.newTab().setText(pageTitle[i]));
}
//set gravity for tab bar
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
final ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
final PagerAdapter adapter = new PagerAdapter
(getSupportFragmentManager(), numOfPages);
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.setOnTabSelectedListener(onTabSelectedListener(viewPager));
}
private TabLayout.OnTabSelectedListener onTabSelectedListener(final ViewPager pager) {
return new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
pager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
};
}
I have a tutorial post about this and it works well! There is no error like yours.
Hope it help:
http://www.devexchanges.info/2015/08/android-material-design-viewpager-with.html
None of the above answers worked for me AS of end of 2016 the bug still exists in design support library 24+.
I was able to fix this issue by wrapping the tab layout inside a
co-ordinator layout
I have more shorter variant to fix this bug (android support design lib v.23.0.0):
...
//initialize views
mViewPager.setAdapter(pagerAdapter);
mTabLayout.setupWithViewPager(mViewPager);
mViewPager.clearOnPageChangeListeners();
mViewPager.addOnPageChangeListener(new WorkaroundTabLayoutOnPageChangeListener(mTabLayout));
...
And class WorkaroundTabLayoutOnPageChangeListener:
public class WorkaroundTabLayoutOnPageChangeListener extends TabLayout.TabLayoutOnPageChangeListener {
private final WeakReference<TabLayout> mTabLayoutRef;
public WorkaroundTabLayoutOnPageChangeListener(TabLayout tabLayout) {
super(tabLayout);
this.mTabLayoutRef = new WeakReference<>(tabLayout);
}
#Override
public void onPageSelected(int position) {
super.onPageSelected(position);
final TabLayout tabLayout = mTabLayoutRef.get();
if (tabLayout != null) {
final TabLayout.Tab tab = tabLayout.getTabAt(position);
if (tab != null) {
tab.select();
}
}
}
}
Are you using support library version 23.0.0. There was an issue https://code.google.com/p/android/issues/detail?id=183123 which looks similar to yours. If that is the case indeed, update your support library version to 23.0.1. This issue has been fixed.
I have a main activity, which hosts a fragment, which in turn hosts a TabLayout (with a ViewPager). The tab bar is shown, baut the tabs themselves are not shown.
Here is my code in the main activity for displaying the host fragment:
Fragment fragment = new BMITabsFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).addToBackStack(Constants.BMI_TABS_FRAGMENT).commit();
Here is my the Fragment which hosts the TabLayout, which is BMITabsFragment (s.a.):
public class BMITabsFragment extends Fragment {
...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Get the ViewPager and set it's PagerAdapter so that it can display items
ViewPager viewPager = (ViewPager) view.findViewById(R.id.viewpager);
viewPager.setAdapter(new BMIFragmentPagerAdapter(getActivity().getSupportFragmentManager(),
getActivity()));
// Give the TabLayout the ViewPager
TabLayout tabLayout = (TabLayout) view.findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_bmitabs, container, false);
return view;
}
...
}
This is my FragmentPagerAdapter:
public class BMIFragmentPagerAdapter extends FragmentPagerAdapter {
final int PAGE_COUNT = 2;
private FragmentManager fragmentManager;
private Context context;
public BMIFragmentPagerAdapter(FragmentManager fm, Context context) {
super(fm);
this.context = context;
this.fragmentManager = fm;
}
public BMIFragmentPagerAdapter(FragmentManager fm) {
super(fm);
fragmentManager = fm;
}
#Override
public CharSequence getPageTitle(int position) {
String[] pageTitles = context.getResources().getStringArray(R.array.page_titles_array);
return pageTitles[position];
}
#Override
public Fragment getItem(int position) {
SharedPreferences prefs = context.getSharedPreferences(Constants.SHARED_PREFS_FILE, 0);
long patientId = prefs.getLong(Constants.SELECTED_PATIENT_ID, 1);
Fragment fragment = null;
switch (position){
case 0:
return BMITabelleFragment.newInstance(patientId);
case 1:
return BMIChartFragment.newInstance(patientId);
default:
return BMITabelleFragment.newInstance(patientId);
}
}
#Override
public int getCount() {
return PAGE_COUNT;
}
}
And this is the fragment_bmitabs.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.TabLayout
android:id="#+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="scrollable" />
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"
android:background="#android:color/white" />
</LinearLayout>
My code is based on the Google Android Guide at https://github.com/codepath/android_guides/wiki/Google-Play-Style-Tabs-using-TabLayout
What I am missing here?
Note: I am using AppCompatActivity and the support libraries v4 & v7 and the com:android:support:design library
This fixed it for me:
tabLayout.post(new Runnable() {
#Override
public void run() {
tabLayout.setupWithViewPager(viewPager);
}
});
https://code.google.com/p/android/issues/detail?id=180462
Set tab icons after setupWithViewPager()
private void setTabs {
tabLayout.setupWithViewPager(viewPager);
setupTabIcons();
}
private void setupTabIcons() {
tabLayout.getTabAt(0).setIcon(tabIcons[0]);
tabLayout.getTabAt(1).setIcon(tabIcons[1]);
tabLayout.getTabAt(2).setIcon(tabIcons[2]);
}
like #Nathaniel Ford said,this should a bug, I change to use design library 23.0.1。google fixed it,so change build.gradle to compile 'com.android.support:design:23.0.1'. ps:you also must change your compileSdkVersionto 23
None of the other answers worked for me, I tried all of them
However, this one did: TabLayout not showing tabs after adding navigation bar
According to that answer, you have to enclose your TabLayout in a AppBarLayout. Why? Who knows. But at least it works.
Example Code (taken from that post):
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="200dp"
android:id="#+id/appBarLayout2">
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/tabLayout2"
app:tabMode="fixed"
app:tabGravity="fill"
></android.support.design.widget.TabLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_alignParentStart="true"
android:layout_alignParentBottom="true"
android:id="#+id/viewPager2"
android:layout_below="#+id/appBarLayout2">
</android.support.v4.view.ViewPager>
If you are using android:tabPadding attribute in Tablayout of xml file,remove it.
You can use FragmentStatePagerAdapter instead of FragmentPagerAdapter.
It may help you.
If someone, in future, works with TabLayout along with ViewPager2 and faces same issue. Just add .attach(); at end of new TabLayoutMediator().
new TabLayoutMediator(tabLayoutRef, viewPager2Ref, (tab, position) -> tab.setText("Tab No. "+position)).attach();
Heu guys i am building an app and i have implemented scrollable tabs. i would like to make it google play style like when the viewpager is scrolling i want the tabpagerindicator to move with it. is this possible?? i have tried to use this example but i failed.
Make TabPagerIndicator Like Google Play
My code so far.
public class TabsActivity extends FragmentActivity implements
ActionBar.TabListener {
private ViewPager mViewPager;
private ActionBar actionBar;
#SuppressLint({ "NewApi" })
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tabs);
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager
.setAdapter(new TabsPagerAdapter(getSupportFragmentManager()));
mViewPager
.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int arg0) {
actionBar.setSelectedNavigationItem(arg0);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab tab1 = actionBar.newTab();
ActionBar.Tab tab2 = actionBar.newTab();
tab1.setText(R.string.info);
tab1.setTabListener(this);
tab2.setText(R.string.graph);
tab2.setTabListener(this);
actionBar.addTab(tab1);
actionBar.addTab(tab2);
}
class TabsPagerAdapter extends FragmentPagerAdapter {
public TabsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int arg0) {
Fragment fragment = null;
if (arg0 == 0) {
fragment = new InfoFragment();
}
if (arg0 == 1) {
fragment = new GraphFragment();
}
return fragment;
}
#Override
public int getCount() {
return 2;
}
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
}
I'm a little confuse by your words: "the tabs activity has 2 fragments inside which everyone of them extends FragmentActivity". They (the Fragments) should extends Fragment and not FragmentActivity..
The right way to have this library is to create (in your case) one FragmentActivity (extends FragmentActivity) and two Fragments (extends Fragment). Your FragmentActivity will have an FragmentPagerAdapter setting with your ViewPager and your PagerTabStrip to display the two Fragments.
All is explain on the GitHub page in Usage section:
Firstly, include the library as local library project:
Download the zip > Copy/paste the Library to your application (PagerSlidingTabStrip Library: you will need PagerSlidingTabStrip.java and also the res folder as everything in attrs file, the background_tab.xml drawable, etc. copy/paste it to yours).
Then, your layout with ViewPager will be:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:myappname="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.mypackagename.PagerSlidingTabStrip
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="48dip"
android:background="#drawable/background_tabs" />
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/tabs"
tools:context=".TabsActivity" />
</RelativeLayout>
Finally, your FragmentActivity will be:
import com.mypackagename.PagerSlidingTabStrip;
public class TabsActivity extends FragmentActivity {
private ActionBar actionBar;
private ViewPager pager;
private PagerSlidingTabStrip tabs;
private MyPagerAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tabs);
// ActionBar settings
actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
// ViewPager, Tab, Adapter init
tabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);
pager = (ViewPager) findViewById(R.id.pager);
adapter = new MyPagerAdapter(getSupportFragmentManager());
// Adapter settings
pager.setAdapter(adapter);
tabs.setViewPager(pager);
}
public class MyPagerAdapter extends FragmentPagerAdapter {
private final String[] tab_titles = { "InfoFragment", "GraphFragment" };
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public CharSequence getPageTitle(int position) {
return tab_titles[position];
}
#Override
public int getCount() {
return tab_titles.length;
}
#Override
public Fragment getItem(int position) {
Fragment fragment = null;
if (position == 0) {
fragment = new InfoFragment();
} else {
fragment = new GraphFragment();
}
return fragment;
}
}
}
You don't need to implements ActionBar.TabListener, to set NavigationMode to MODE_TABS and adding Tab dynamically with actionBar.addTab.
As you can read on the project page: compatible with the ViewPager from the Android Support Library, this is not related with the ActionBar but with the ViewPager. Your tabs are added in the Adapter..
Finally, you can customize your Tabs with xml attributes. These attributes are handled via your attrs file and all are visible in Customization section on home page:
<com.mypackagename.PagerSlidingTabStrip
myappname:pstsIndicatorColor="#FFFF0000"
myappname:pstsUnderlineColor="#FFFF0000"
myappname:pstsIndicatorHeight="2dp"
... />
Hope this helps.