Reputation: 143
I can't get this to work. The basic app functions as it's supposed to but the ViewPager on one of the layout files doesn't show any fragment at all. I checked the code multiple times but I can't find a bug. When I tried debugging it I noticed that it doesn't even initialize the fragments classes which it's supposed to when you select a tab. My MainActivity:
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
new GetData(this).execute();
TabLayout tab_layout = (TabLayout) findViewById(R.id.tab_layout);
tab_layout.addTab(tab_layout.newTab().setText("CASUAL"));
tab_layout.addTab(tab_layout.newTab().setText("RANKED"));
tab_layout.setTabGravity(TabLayout.GRAVITY_FILL);
final ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager);
PagerAdapter adapter = new PagerAdapter(getSupportFragmentManager(), tab_layout.getTabCount());
viewPager.setAdapter(adapter);
tab_layout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@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) {
}
});
}
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_stats) {
// Handle the camera action
} else if (id == R.id.nav_about) {
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
}
My PagerAdapter:
public class PagerAdapter extends FragmentStatePagerAdapter {
int mNumOfTabs;
public PagerAdapter(FragmentManager fm, int NumOfTabs) {
super(fm);
this.mNumOfTabs = NumOfTabs;
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
CasualStats tab1 = new CasualStats();
return tab1;
case 1:
RankedStats tab2 = new RankedStats();
return tab2;
default:
return null;
}
}
@Override
public int getCount() {
return mNumOfTabs;
}
}
Layout with the ViewPager:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"><![CDATA[
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_below="@id/tab_layout"/>
]]>
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:id="@+id/tab_layout">
</android.support.design.widget.TabLayout>
<view
android:layout_width="wrap_content"
android:layout_height="wrap_content"
class="android.support.v4.view.ViewPager"
android:layout_alignParentStart="true"
android:id="@+id/view_pager"
android:layout_below="@+id/tab_layout" />
</RelativeLayout>
The classes for the tab fragments which are supposed to be displayed in the ViewPager are just normal auto generated Android Studio fragment classes.
One of the fragments:
public class CasualStats extends Fragment{
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public CasualStats() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment CasualStats.
*/
// TODO: Rename and change types and number of parameters
public static CasualStats newInstance(String param1, String param2) {
CasualStats fragment = new CasualStats();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return 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 View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_casual_stats, container, false);
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
The xml:
<RelativeLayout 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="com.app.anzel.r6s.CasualStats">
<!-- TODO: Update blank fragment layout -->
<TextView
android:text="1st fragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:layout_marginStart="28dp"
android:layout_marginTop="22dp"
android:id="@+id/textView"
android:visibility="visible" />
</RelativeLayout>
Upvotes: 10
Views: 13697
Reputation: 4140
If you are using any tablayout with viewpager inside NestedScrollView, make sure to put android:fillViewport="true"
Reference in the nested scrollview. Note that, if you are working with navigation drawer, your fragment may not have a nested scrollview, but your activity fragment container maybe inside a nested scroll view. Because even an empty layout with a background color (for debugging the issue) does not show up, so it was not the problem of view pager in my case, it was the problem with nested scroll view.
Debugging tip: Instead of viewpager, put some layout and set a background color to see if the layout is visible. If the layout itself is not visible, then you have issue with the parent layout, most probably NestedScrollView.
Upvotes: 2
Reputation: 12222
The problem is that you have nested fragments and use getFragmentManager(); You should use getChildFragmentManager() instead.
java:
viewPagerAdapter = new PagerAdapter(getChildFragmentManager())
kotlin:
viewPagerAdapter = PagerAdapter(childFragmentManager)
Upvotes: 32
Reputation: 1292
The below sample code is working fine with viewpager and tabs. Try it out.
Main activity layout
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<android.support.design.widget.TabLayout
android:id="@+id/tab_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="?attr/actionBarSize" />
<include layout="@layout/content_main" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@android:drawable/ic_dialog_email" />
Then viewpager container layout
<?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:id="@+id/content_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.test.myapplication.MainActivity"
tools:showIn="@layout/app_bar_main">
<android.support.v4.view.ViewPager
android:id="@+id/page_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FF0000" />
</RelativeLayout>
And here is the main activity part:
package com.test.myapplication;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TabLayout;
import android.support.v4.app.*;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
ViewPager pager = (ViewPager)findViewById(R.id.page_container);
pager.setAdapter(new Adapter(getSupportFragmentManager()));
TabLayout tabs = (TabLayout)findViewById(R.id.tab_container);
tabs.setupWithViewPager(pager, true);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_camera) {
// Handle the camera action
} else if (id == R.id.nav_gallery) {
} else if (id == R.id.nav_slideshow) {
} else if (id == R.id.nav_manage) {
} else if (id == R.id.nav_share) {
} else if (id == R.id.nav_send) {
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
public static class Adapter extends FragmentStatePagerAdapter {
private String[] titles = new String[] {"ONE", "TWO"};
public Adapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
switch (position){
case 0:
return new com.test.myapplication.Fragment();
case 1:
return new Fragment1();
}
return null;
}
@Override
public int getCount() {
return 2;
}
@Override
public CharSequence getPageTitle(int position) {
return titles[position];
}
}
}
Upvotes: 1
Reputation: 143
I feel kind of stupid. The problem was with the ViewPager as I suspected. After 3h of code debugging I just moved the ViewPager from the layout with the tabs to another layout which basically connects all of the layouts.
Upvotes: 4
Reputation: 23881
try this:
in your layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:id="@+id/tab_layout">
</android.support.design.widget.TabLayout>
<android.support.v4.view.ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:id="@+id/view_pager"
android:layout_below="@+id/tab_layout" />
</RelativeLayout>
in activity:
TabLayout tab_layout = (TabLayout) findViewById(R.id.tab_layout);
tab_layout.addTab(tab_layout.newTab().setText("CASUAL"));
tab_layout.addTab(tab_layout.newTab().setText("RANKED"));
tab_layout.setTabGravity(TabLayout.GRAVITY_FILL);
final ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager);
PagerAdapter adapter = new PagerAdapter(getSupportFragmentManager(), tab_layout.getTabCount());
viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(2);
tab_layout.post(new Runnable() {
@Override
public void run() {
tab_layout.setupWithViewPager(viewPager);
}
});
tab_layout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@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) {
}
});
PagerAdapter :
public class PagerAdapter extends FragmentStatePagerAdapter {
int mNumOfTabs;
// an array of tab titles
private String tabTitles[] = new String[]{"CASUAL", "RANKED"};
public PagerAdapter(FragmentManager fm, int NumOfTabs) {
super(fm);
this.mNumOfTabs = NumOfTabs;
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
CasualStats tab1 = new CasualStats();
return tab1;
case 1:
RankedStats tab2 = new RankedStats();
return tab2;
default:
return null;
}
}
@Override
public int getCount() {
return mNumOfTabs;
}
@Override
public CharSequence getPageTitle(int position) {
return tabTitles[position];
}
}
Upvotes: 0
Reputation: 2434
You are missing setupWithViewPager
, and you don't need setOnTabSelectedListener
:
tab_layout.setupWithViewPager(viewPager)
Let's look here: http://www.androidhive.info/2015/09/android-material-design-working-with-tabs/
You have to override also getPageTitle
in adapter and there return tab title.
Last, don't use <view ..class>
in xml, create normal xml view:
<android.support.v4.view.ViewPager
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:id="@+id/view_pager"
android:layout_below="@+id/tab_layout"/>
Upvotes: 0