I have a TabLayout with a ViewPager2 attached.
I attach my fragments to it like normal but I have an odd behaviour.
Between the TabLayout and the TextView there is some kind of gap although my Textview should be in the very top left corner. I cannot figure out where this extra margin is coming from (It does not matter what kind of view I place into the fragment it seems the whole fragment is shifted down (But the actual background of my fragment covers the entire ViewPager area)
This is the code for the viewPager und TabLayout.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.tabs.TabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
tools:background="?attr/colorPrimary"
app:tabGravity="fill"
app:tabIndicatorColor="?attr/colorSecondary"
app:tabIndicatorFullWidth="false"
app:tabIndicatorHeight="3dp"
app:tabMinWidth="48dp"
app:tabMode="fixed"
app:tabSelectedTextColor="?attr/colorOnPrimary"
app:tabTextAppearance="#style/App.Tab.Text"
app:tabTextColor="?attr/colorPrimaryLight"/>
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:background="#color/lightRed"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
I only added the background color to see which view is "below" the margin
This is the code for the fragment.
<androidx.constraintlayout.widget.ConstraintLayout
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:background="#color/lightOrange"
android:fitsSystemWindows="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="NO MARGIN TOP LEFT"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Where does my margin come from? It drives me nuts. I do not change margins inside the code whatsoever.
I use a custom FragmentStateAdapter which might be the culprit? On a sidenot the first click on a tab after the app opens will not switch the page, I could not make this work yet any idea why?
Here is the Adapter I use:
public class TabAdapter extends FragmentStateAdapter {
private static final String TAG = "TabAdapter";
private final List<TabFragment> mFragments;
private final String prefix;
private final ViewPager2 mViewPager;
private final TabLayout mTabLayout;
private final OnPageChangeCallback callback;
public interface OnPageChangeCallback {
void onPageSelected(int position);
}
public TabAdapter(BaseFragment fragment, TabLayout tabLayout, ViewPager2 viewPager, TabFragment... fragments) {
this(fragment, tabLayout, viewPager, Arrays.asList(fragments), null);
}
public TabAdapter(BaseFragment fragment, TabLayout tabLayout, ViewPager2 viewPager, List<TabFragment> fragments) {
this(fragment, tabLayout, viewPager, fragments, null);
}
public TabAdapter(BaseFragment fragment, TabLayout tabLayout, ViewPager2 viewPager, List<TabFragment> fragments, OnPageChangeCallback listener) {
super(fragment);
this.mFragments = fragments;
this.prefix = fragment.TAG;
this.mViewPager = viewPager;
this.mTabLayout = tabLayout;
this.callback = listener;
initTabLayout();
}
#Override
#NonNull
public BaseFragment<?> createFragment(int position) {
return mFragments.get(position).getFragment();
}
#Override
public long getItemId(int position) {
return Objects.hash(mFragments.get(position));
}
#Override
public boolean containsItem(long itemId) {
for (TabFragment fragment : mFragments) {
if (Objects.hash(fragment) == itemId) return true;
}
return false;
}
#Override
public int getItemCount() {
return mFragments.size();
}
private void initTabLayout() {
mViewPager.setAdapter(this);
mViewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
#Override
public void onPageSelected(int position) {
super.onPageSelected(position);
if (callback != null) callback.onPageSelected(position);
TabStateProvider.saveTab(prefix, position);
}
});
int startTab = TabStateProvider.getTab(prefix, false, 0);
new TabLayoutMediator(mTabLayout, mViewPager, (tab, position) -> {
tab.setText(mFragments.get(position).getTabTitle());
}).attach();
selectPage(startTab);
}
void selectPage(int pageIndex) {
mViewPager.post(() -> {
mViewPager.setCurrentItem(pageIndex, false);
});
}
}
Related
I am using a PageViewer to display fragment's data, and whenever I put a TextView into the fragment's xml, it doesn't display when the app is being run. I put it in a NestedScrollView to put more widgets in then I could without it. I tried putting an ImageView in to see if it was removing everything but that worked fine, except it was a little laggy when changing fragments.
My code for my activity is
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.view_pager);
setupViewPager(viewPager);
tabLayout = (TabLayout) findViewById(R.id.tabLayout);
tabLayout.setupWithViewPager(viewPager);
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new VolleyballFragment(), "Volleyball");
adapter.addFragment(new SoftballFragment(), "Softball");
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);
}
}
}
my fragment codes are the nearly same so I will only provide 1
public class VolleyballFragment extends Fragment{
public VolleyballFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_volleyball, container, false);
}
}
and the activity xml file is
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbar"
android:layout_height="wrap_content"
android:layout_width="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"></androidx.appcompat.widget.Toolbar>
<com.google.android.material.tabs.TabLayout
android:id="#+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.tabs.TabItem
android:id="#+id/softballFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Softball" />
<com.google.android.material.tabs.TabItem
android:id="#+id/volleyballFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Vollyball" />
</com.google.android.material.tabs.TabLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<androidx.viewpager.widget.ViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
If you need any of the xml files or anything else please let me know.
I fallowed an older tutorial online since this is my first time using fragments and tabs, so I'm a little confused to begin with
Also sorry for the code being cut off and replaced as normal text
I tried your code everything else is fine but you're just missing layout_behavior on NestedScrollView.
After adding this property your code would look like this.
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
android:fillViewport="true">
<androidx.viewpager.widget.ViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</androidx.core.widget.NestedScrollView>
Description
I have one activity in the vertical orinentation with two tabs (TabLayout) and fragments, which change with Viewpager.
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
// Assign created adapter to viewPager
viewPager.setAdapter(new TabsExamplePagerAdapter(getSupportFragmentManager()));
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
// This method setup all required method for TabLayout with Viewpager
tabLayout.setupWithViewPager(viewPager);
}
public class TabsExamplePagerAdapter extends FragmentPagerAdapter {
// As we are implementing two tabs
private static final int NUM_ITEMS = 2;
public TabsExamplePagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
// For each tab different fragment is returned
public Fragment getItem(int position) {
switch (position) {
case 0:
return new TabOneFragment();
case 1:
return new TabTwoFragment();
default:
return null;
}
}
#Override
public int getCount() {
return NUM_ITEMS;
}
#Override
public CharSequence getPageTitle(int position) {
return "Tab " + (position + 1);
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".MainActivity">
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:tabTextColor="#ffffff"
app:tabIndicatorColor="#fbff3a"
app:tabSelectedTextColor="#fbff3a"
app:tabIndicatorHeight="5dp"
android:elevation="4dp"
app:tabGravity="fill"
app:tabMaxWidth="0dp" />
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
In each tabs i have for one fragments.
TabOneFragment.java (TabTwoFragment is similar ):
public class TabOneFragment extends Fragment {
// Required empty public constructor
public TabOneFragment() { }
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_tab_one, container, false);
}
}
fragment_one_tab.xml (fragment_one_tab.xml is similar)
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="innovatecode.com.tabexample.TabOneFragment">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="18dp"
android:text="#string/tab_one" />
</FrameLayout>
And i have simply result:
My problem
When my device is rotated to the horizontal position, I want to get the following result:
I create xml for horizontal markup (land):
active_main.xml (land)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<FrameLayout
android:id="#+id/fragment_left"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" />
<FrameLayout
android:id="#+id/fragment_right"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
But I don't know how to change my code to get this result. I'm not very strong in working with fragments.
First, you can improve your landscape layout by adding your fragments directly to the layout file (under "res/layout-land"):
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<fragment
android:name="innovatecode.com.tabexample.TabOneFragment"
android:id="#+id/fragment_left"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<fragment
android:name="innovatecode.com.tabexample.TabTwoFragment"
android:id="#+id/fragment_right"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
You can read move on the topic here.
For the code part, you could make use of distinct features of your landscape and portrait layouts to switch between the corresponding logic in code. For example:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (findViewById(R.id.tab_layout) != null) {
setUpPortraitLayout();
} else {
setUpLandscapeLayout();
}
}
private void setUpPortraitLayout() {
ViewPager viewPager = findViewById(R.id.pager);
// Assign created adapter to viewPager
viewPager.setAdapter(new TabsExamplePagerAdapter(getSupportFragmentManager()));
TabLayout tabLayout = findViewById(R.id.tab_layout);
// This method setup all required method for TabLayout with Viewpager
tabLayout.setupWithViewPager(viewPager);
}
private void setUpLandscapeLayout() {
// Note: with the layout definition suggested above you don't
// need any manual processing to set-up your layout for landscape
// but you still may have some extra set-up (initial binding, etc).
tabOneFragment = (TabOneFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_left);
tabTwoFragment = (TabTwoFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_right);
// ...
}
}
You can pass saved parameters to your fragments via "setArguments()" method. Alternatively consider using "onSaveInstanceState()" methods of your fragments (as opposed to activity, which you use now).
Alternative approach: dynamically add fragments in both landscape and portrait cases. It is based on your code. I think some aspects are arguable (I may be wrong), but changing direction would mean rewriting the whole thing. But it should work eventually.
res/layout-land/active_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<FrameLayout
android:id="#+id/fragment_left"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<FrameLayout
android:id="#+id/fragment_right"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
MainActivity.java (based off the code you shared via gist)
public class MainActivity extends AppCompatActivity {
private Fragment tabOneFragment;
private Fragment tabTwoFragment;
private ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null) {
//Restore the fragment's instance
tabOneFragment = (TabOneFragment) getSupportFragmentManager().getFragment(
savedInstanceState, "tabOneFragment");
tabTwoFragment = (TabTwoFragment) getSupportFragmentManager().getFragment(
savedInstanceState, "tabTwoFragment");
} else {
tabOneFragment = new TabOneFragment();
tabTwoFragment = new TabTwoFragment();
}
if (findViewById(R.id.tab_layout) != null) {
setUpPortraitLayout();
} else {
setUpLandscapeLayout();
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getSupportFragmentManager().putFragment(outState, "tabOneFragment", tabOneFragment);
getSupportFragmentManager().putFragment(outState, "tabTwoFragment", tabTwoFragment);
}
private void setUpPortraitLayout() {
viewPager = (ViewPager) findViewById(R.id.pager);
// Assign created adapter to viewPager
viewPager.setAdapter(new TabsPagerAdapter(getSupportFragmentManager()));
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
// This method setup all required method for TabLayout with Viewpager
tabLayout.setupWithViewPager(viewPager);
}
private void setUpLandscapeLayout() {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_left, tabOneFragment);
transaction.replace(R.id.fragment_right, tabTwoFragment);
transaction.addToBackStack(null);
transaction.commit();
}
private class TabsPagerAdapter extends FragmentPagerAdapter {
// As we are implementing two tabs
private static final int NUM_ITEMS = 2;
public TabsPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
#Override
// For each tab different fragment is returned
public Fragment getItem(int position) {
switch (position) {
case 0:
return tabOneFragment;
case 1:
return tabTwoFragment;
default:
throw new IllegalStateException("Invalid tab index");
}
}
#Override
public int getCount() { return NUM_ITEMS; }
#Override
public CharSequence getPageTitle(int position) { return "Tab " + (position + 1); }
// NOTE: I think you do not really need to override "instantiateItem()", therefore I removed it.
}
}
I'm able to click the tabs to change, but nothing happens when I swipe. I don't see the coloured bar underneath the selected tab either.
Here's my code. I've largely followed this tutorial, but I've changed tabLayout.setOnTabSelectedListener(this) to tabLayout.addOnTabSelectedListener(this) in StoriesActivity because the former is depreceated.
StoriesActivity:
public class StoriesActivity extends AppCompatActivity implements TabLayout.OnTabSelectedListener {
//This is our tablayout
private TabLayout tabLayout;
//This is our viewPager
private ViewPager viewPager;
private Toolbar toolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stories);
/* +++ START Intent +++ */
Bundle extras = getIntent().getExtras();
final int authorID = extras.getInt("author_id");
final String authorName = extras.getString("author_name");
Log.i("click", Integer.toString(authorID));
/* +++ END Intent +++ */
toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle(authorName);
setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
//Initializing the tablayout
tabLayout = (TabLayout) findViewById(R.id.tab_layout);
//Adding the tabs using addTab() method
tabLayout.addTab(tabLayout.newTab().setText("Stories"));
tabLayout.addTab(tabLayout.newTab().setText("Collections"));
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
//Initializing viewPager
viewPager = (ViewPager) findViewById(R.id.pager);
//Creating our pager adapter
StoriesTabsAdapter adapter = new StoriesTabsAdapter(getSupportFragmentManager(), tabLayout.getTabCount());
//Adding adapter to pager
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
//Adding onTabSelectedListener to swipe views
tabLayout.addOnTabSelectedListener(this);
}
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
}
activity_stories.xml:
<RelativeLayout
android:id="#+id/main_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="?attr/colorPrimary"
android:elevation="6dp"
android:minHeight="?attr/actionBarSize"
app:navigationIcon="?attr/homeAsUpIndicator"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"/>
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/toolbar"
android:background="?attr/colorPrimary"
android:elevation="6dp"
android:minHeight="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_below="#id/tab_layout"/>
<ListView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/stories_list_view" />
</RelativeLayout>
StoriesTabsAdapter:
public class StoriesTabsAdapter extends FragmentPagerAdapter {
int mNumOfTabs;
public StoriesTabsAdapter(FragmentManager fm, int NumOfTabs) {
super(fm);
this.mNumOfTabs = NumOfTabs;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
StoriesFragment tab1 = new StoriesFragment();
return tab1;
case 1:
CollectionsFragment tab2 = new CollectionsFragment();
return tab2;
default:
return null;
}
}
#Override
public int getCount() {
return mNumOfTabs;
}
}
StoriesFragment:
public class StoriesFragment extends Fragment {
public StoriesFragment() {
// Required empty public constructor
}
private ListView storiesListView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_stories, container, false);
}
}
You are missing to setupWithViewPager your TabLayout.
mTabLayout.setupWithViewPager(mViewPager)
Regarding the problem of your text not to be appearing, try to move the code below straight after you setupWithViewPager
//Adding the tabs using addTab() method
tabLayout.addTab(tabLayout.newTab().setText("Stories"));
tabLayout.addTab(tabLayout.newTab().setText("Collections"));
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
You should follow below two points.
Use FragmentStatePagerAdapter for good approach.
setupWithViewPager
If you're using a ViewPager together with this layout, you can call
setupWithViewPager(ViewPager) to link the two together. This layout
will be automatically populated from the PagerAdapter's page titles.
Secondly
_tablayoutOBJ.setupWithViewPager(_viewpagerOBJ); // After addOnTabSelectedListener .
For, Demo case you can visit Material Design working with Tabs.
The Problem:
In my onCreate() on my main activity, I am trying to set the text value of a TextView in my fragment which is displayed by a viewpager. When I try to get my fragment instance, It always returns null.
Solutions I Tried:
Almost every solution related to this problem on SO gives me the same result(NPE).
My Code is below as well as some explanation...
Home.java Activity (My Main Activity):
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Show the home layout
setContentView(R.layout.home);
// Setup the toolbar
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Now setup our tab bar
TabLayout tabLayout = (TabLayout)findViewById(R.id.homeTabs);
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
// Setup the view pager
ViewPager viewPager = (ViewPager)findViewById(R.id.viewPager);
PagerAdapter pagerAdapter = new PagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(pagerAdapter);
tabLayout.setupWithViewPager(viewPager);
// Start our service controller
Intent startServiceController = new Intent(this, ServiceController.class);
startService(startServiceController);
Fragment viewFragment = pagerAdapter.getRegisteredFragment(viewPager.getCurrentItem());
if(viewFragment == null){
Log.v("Fragment", "NULL");
}
}
After setting up the pageAdapter and viewpager, I try to access the fragment thats being shown. The code for my PagerAdapter is below...
PagerAdapter:
public class PagerAdapter extends SmartFragmentStatePagerAdapter {
public PagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new ParkListFragment();
case 1:
return new MapFragment();
default:
return null;
}
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
CharSequence title;
switch (position){
case 0:
title = "Spaces Near You";
break;
case 1:
title = "Map";
break;
default:
title = "N/A";
break;
}
return title;
}
}
SmartFragmentStatePagerAdapter:
public abstract class SmartFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
// Sparse array to keep track of registered fragments in memory
private SparseArray<Fragment> registeredFragments = new SparseArray<>();
public SmartFragmentStatePagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
// Register the fragment when the item is instantiated
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
// Unregister when the item is inactive
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
// Returns the fragment for the position (if instantiated)
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
}
I really don't understand what the issue is. I have tried many things. What I don't want to use is this:
String tag="android:switcher:" + viewId + ":" + index;
ParkListFragment.java:
public class ParkListFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.park_list_fragment, container, false);
}
}
ParkList Fragment 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:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.5">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_centerInParent="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/confidenceText"
android:textAlignment="center"
android:textSize="24sp"
android:textColor="#android:color/primary_text_light"
android:padding="10dp"/>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.5">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_centerInParent="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/activityText"
android:textAlignment="center"
android:textSize="24sp"
android:textColor="#android:color/primary_text_light"
android:padding="10dp"/>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
Stack Trace: Pastebin
So after hours of trial and error, the only thing that worked for me was this SO post:
ViewPager Fragments are not initiated in onCreate
I have used a sectionsPageAdapter class in Java which is given below.
This is a tabbed activity and I later added a navigation drawer to it.
Now I wish to let user navigate through tabs from the main activity by swiping (which works successfully) and also through nav drawer as I have included the same fragments names there also.
what code should i write in the switch case to direct user to the clicked fragment activity?
Main Activity.java
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private SectionsPageAdapter mSectionsPageAdapter;
private ViewPager mViewPager;
private ArrayAdapter<String> mAdapter;
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG,"onCreate: Starting");
mSectionsPageAdapter =new SectionsPageAdapter(getSupportFragmentManager());
mViewPager =(ViewPager)findViewById(R.id.container);
setupViewPager(mViewPager);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
mDrawerLayout =(DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList=(ListView)findViewById(R.id.navList);
addDrawerItems();
mDrawerList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
switch (position)
{
case 0:
// what Code??
break;
case 1:
break;
}
}
});
}
private void setupViewPager(ViewPager viewPager){
SectionsPageAdapter adapter=new SectionsPageAdapter(getSupportFragmentManager());
adapter.addFragment(new Tab1Fragment(),"Our Picks");
adapter.addFragment(new Tab2Fragment(),"Technology");
adapter.addFragment(new Tab3Fragment(),"Fashion");
viewPager.setAdapter(adapter);
}
private void addDrawerItems() {
String[] osArray = { "Our Picks", "Technology","Fashion" };
mAdapter = new ArrayAdapter<String>(this,R.layout.drawerpart1, osArray);
mDrawerList.setAdapter(mAdapter);
}
SectionsPageAdapter.java
public class SectionsPageAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList=new ArrayList<>();
private final List<String> mFragmentTitleList=new ArrayList<>();
public void addFragment(Fragment fragment,String title){
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
public SectionsPageAdapter(FragmentManager fm) {
super(fm);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:id="#+id/drawer_layout"
android:layout_height="match_parent"
tools:context="com.example.aa.news.MainActivity">
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
>
<android.support.v4.view.ViewPager
android:id="#+id/container"
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="wrap_content"
android:paddingTop="#dimen/appbar_padding_top"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
<ListView
android:id="#+id/navList"
android:layout_width="250dp"
android:layout_height="match_parent"
android:layout_gravity="left|start"
android:background="#ffeeeeee"/>
</android.support.v4.widget.DrawerLayout>
drawerpart1.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/label"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dip"
android:textSize="16dip"
android:textStyle="bold" >
</TextView>
Tab1Fragment
public class Tab1Fragment extends Fragment {
private static final String TAG = "Tab1Fragment";
private Button btn1;
#Nullable
#Override
public View onCreateView(#Nullable LayoutInflater inflater, #Nullable ViewGroup container,#Nullable Bundle savedInstanceState)
{
View view= inflater.inflate(R.layout.tab1_fragment,container,false);
btn1=(Button) view.findViewById(R.id.btn1);
btn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getActivity(),"Button 1 Clicked",Toast.LENGTH_SHORT).show();
}
});
return view;
}
}
tab1_fragment.xml
<?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:layout_height="match_parent">
<Button
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:id="#+id/btn1"
android:text="Button 1" />
<TextView
android:layout_height="60dp"
android:layout_width="120dp"
android:id="#+id/tv1"
android:text="Fragment 1"/>
</LinearLayout>
The other fragments tab2 and 3 are same as tab 1.
Use setCurrentItem() on viewpager
mDrawerList.setOnItemClickListener(new AdapterView.OnItemClickListener(){
#Override
public void onItemClick (AdapterView < ? > parent, View view,int position, long id){
mViewPager.setCurrentItem(position);
}
});