I have an Activity with a layout that contains 2 Fragments next to each other. In each Fragment, I have a ViewPager. Since I need both Fragments to look the same way, I use the same layout XML for both, which contains a ViewPager.
Now when I test the app, only the ViewPager of the first Fragment seems to work. The second Fragment shows a PagerTitleStrip, and I can flip through it, but it doesn't show the Fragments in the ViewPager.
Why isn't the second ViewPager showing the Fragments too? What is causing this?
Is the problem that they use the same layout? Isn't it a different Object anyway?
The layout that the 2 Fragments in the Activity share looks like this:
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v4.view.PagerTitleStrip
android:id="#+id/search_mapping_pager_title_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#33b5e5"
android:paddingBottom="4dp"
android:paddingTop="4dp"
android:textColor="#fff" />
</android.support.v4.view.ViewPager>
Both Fragments instantiate the ViewPager the same way:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_search_mapping,
container, false);
mSectionsPagerAdapter = new SectionsPagerAdapter(mActivity
.getSupportFragmentManager());
mViewPager = (ViewPager) view.findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
return view;
}
EDIT: More code showing my SectionsPagerAdapter:
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
Fragment fragment = new SuperclassFragment();
Bundle args = new Bundle();
args.putInt(SuperclassFragment.ARG_SECTION_NUMBER, position + 1);
fragment.setArguments(args);
return fragment;
}
...
}
Any tips where I should look for the cause of the bug? I can of course include more code here if necessary.
I solved the problem myself by not putting the ViewPagers into Fragments, but putting them directly into the layout of the Activity.
The XML layout of the Activity then looks like this:
...
<LinearLayout
android:id="#+id/search_fragment_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<android.support.v4.view.ViewPager
android:id="#+id/objectPager"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.5"
android:layout_margin="16dp" >
<android.support.v4.view.PagerTitleStrip
android:id="#+id/object_pager_title_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#33b5e5"
android:paddingBottom="4dp"
android:paddingTop="4dp"
android:textColor="#fff" />
</android.support.v4.view.ViewPager>
<android.support.v4.view.ViewPager
android:id="#+id/actionPager"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.5"
android:layout_margin="16dp" >
<android.support.v4.view.PagerTitleStrip
android:id="#+id/action_pager_title_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#33b5e5"
android:paddingBottom="4dp"
android:paddingTop="4dp"
android:textColor="#fff" />
</android.support.v4.view.ViewPager>
</LinearLayout>
...
Using it in the Activity itself actually creates 2 distinct ViewPager objects, and both show their Fragments as expected.
I'm still not sure what caused the bug. If someone comes up with a good explanation, I'm willing to accept that as an answer.
FragmentPagerAdapter relies on a combination of ViewPager id/Page Item id to check if the page item needs to be instantiated (see FragmentPagerAdapter.instantiateItem function). If you place your ViewPager into a fragment, both instances of the View Pager will end up having the same id, and since page position is the default id for the page, pages for the second ViewPager are never instantiated.
The workaround is ether to set ViewPager id programmatically:
viewPager.setId(myID++);
or override getItemId on your adapter so item id's are different for different ViewPager's.
By putting ViewPager inside Fragment's layout, you are trying to add a child fragment inside a fragment. Nested fragment is only supported from 4.2 onwards and now its added in Support Library too.
In order to support View Pager insider a fragment, you need to implement your own version of PagerAdapter. From one of the SO post,
It is perfectly possible to put a ViewPager inside a Fragment, so long
as the contents of the ViewPager do not themselves contain fragments.
Since the concrete implementations of PagerAdapter supplied by the
Android Support package use fragments, you have to roll your own
fragment-less PagerAdapter to put the ViewPager in a fragment.
Below are few post which describe the problem and possible solution
Why it is not possible to use ViewPager within a Fragment? It actually is
ViewPager inside fragment issue
Related
I have a ViewPager with a PagerTitleStrip which paints fragments. Each fragment has a StableArrayAdapter which fill the fragment with information.
After an orientation change, when I click on the fragments, I'm getting a crash: java.lang.IndexOutOfBoundsException: Index: 8, Size: 7
When the orientation change is produced, I can see the same fragment page as before the orientation change. But if I click on it, it produces the crash because probably the viewpager has loaded the first fragment instead of the selected fragment.
It seems that when the orientation change is produced, the activity is being recreated (I want it because I want the smart banner from admob to recreate with the new width), but the fragment probably is not being recreated or something, so probably it's pointing to a different fragment from the painted one.
How can I avoid this crash? maybe there is a way to tell the viewpager that it must load the page which is displaying? how can that be done?
I tried storing the current fragment number and selecting it when recreating but the crash is still happening:
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putInt("current_item", viewPager.getCurrentItem());
super.onSaveInstanceState(savedInstanceState);
}
.
.
.
//code in onCreate()
viewPager.setAdapter(collectionPagerAdapter);
if (savedInstanceState != null) {
int currentItem = savedInstanceState.getInt("current_item");
viewPager.setCurrentItem(currentItem);
}
This is my xml layout.
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="3dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toTopOf="#+id/adView">
<android.support.v4.view.PagerTitleStrip
android:id="#+id/pager_title_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:paddingTop="4dp"
android:paddingBottom="4dp"
style="#style/CustomPagerTitleStrip"/>
</android.support.v4.view.ViewPager>
This is the line where is crashing in the StableArrayAdapter which fills the fragments with lines
Override public long getItemId(int position) {
return Math.abs(getItem(position).hashCode());
}
You can go through below link, they have explained handling Fragments & viewPager orientation changes.
https://medium.com/#roideuniverse/android-viewpager-fragmentpageradapter-and-orientation-changes-256c23bee035
I am working on a Scrollable tabs and came to observe a custom scrollable tabe in a mediaplayer app but don't know what is used in this as per my knowledge it is like scrollable tabs.Any hint how to achieve this while changing from one fragment to another .I want to show a gape in the fragment while scrolling as in this app?THIS is what I created
this is what i want a gape between two fragment
I tried to give padding in the view pager but it is not working at all.
my layout content main .xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:background="#drawable/gradient2"
>
<android.support.v4.view.PagerTitleStrip
android:id="#+id/title"
style="#style/viewPagerTitleStrip"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="top"
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:background="#drawable/gradient1">
</android.support.v4.view.PagerTitleStrip>
</android.support.v4.view.ViewPager>
I tried both padding and margine in the ViewPager but it is not working
Here is the similar property used try this https://github.com/astuetz/PagerSlidingTabStrip
Since I am using ViewPager, the easiest way to achieve some space is to use the setPageMargin() method of Viewpager, which in my case will be
ViewPager pager = (ViewPager) findViewById(R.id.pager);
pager.setPageMargin(200);
//200 is value in pixel
There is also a method setPageMarginDrawable() sets a drawable that will be used to fill the margin between pages (Android documentation).
I am attempting to replace a nested fragment inside a tabLayout fragment.
My app structure follows this pattern.
Here is the XML for the Tab Fragment 2
<FrameLayout
android:id="#+id/scene_root"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".Home"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<FrameLayout
android:id="#+id/shows_fragment_list"
android:tag="list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<FrameLayout
android:id="#+id/shows_fragment_details"
android:tag="details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<FrameLayout
android:id="#+id/shows_fragment_info"
android:tag="info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>
I am using this code to add the NestedFragment to the TabFragment FrameLayout
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View root = inflater.inflate(R.layout.shows_fragment_layout, container, false);
ShowDetailsFragment newNestedFragment = new ShowDetailsFragment();
android.support.v4.app.FragmentManager fragmentManager = getChildFragmentManager();
android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction
.add(R.id.show_fragment_details, newNestedFragment)
.addToBackStack("null")
.commit();
return root;
}
But when I add the Nested Fragment to the Tab Fragment, only the last part of my layout appears, in this case it is a list view (highlighted in red), but it always seems to be the which ever element is declared last when the layout is inflated by the corresponding Java file.
When I inflate these layouts as there own activity, there are no inflation problems, so it must relate to my implementation of fragments, any ideas where I am going wrong?
A good idea is always to use the Android Device Monitor to debug your layout.
I would also add some logging on the onCreateView of your fragments.
Ok so my problem was that in my XML layout for my ShowDetailsFragment (The Nested Fragment) I had a FrameLayout as the root, but there were two separate RelativeLayouts as children, meaning only the last element was being displayed, the problem was solved by nesting these two Relative Layouts in another single Relative Layout.
Props go to ctarabusi for pointing me in the right direction, although I am still unsure why this only caused a problem when inflating as a Fragment and not as an Activity.
I have great problems getting the Navigation Tabs work. I am aware of this guide http://developer.android.com/guide/topics/ui/actionbar.html#Tabs
but I have problems understanding the article. It says the following:
To get started, your layout must include a ViewGroup in which you place each Fragment associated with a tab. Be sure the ViewGroup has a resource ID so you can reference it from your code and swap the tabs within it. Alternatively, if the tab content will fill the activity layout, then your activity doesn't need a layout at all (you don't even need to call setContentView()). Instead, you can place each fragment in the default root view, which you can refer to with the android.R.id.content ID.
As I don't use a Fragment for my Main Layout, but for others, I think the "alternative" way is right for me (I would like Tab 1 to be the Main Layout I have right now and then 2 and 3 to be my fragments), but I don't know how to accomplish this. Can someone maybe help out on this?
I was able to set up the tabs and the TabListener, so that is not the problem. The problem is that the first tab is NOT supposed to be a fragment, but my main activity layout! This is where I need help!
I did try to use my main activity-layout for a fragment, but for some reason if I click that tab, the tab changes but the screen stays white. I cannot see my fragment view.
The old code was:
mListView = (ListView) findViewById(R.id.list_view);
mListView.setAdapter(mAdapter);
mListView.setTextFilterEnabled(true);
and I've changed it in the fragment to:
View view = inflater.inflate(R.layout.list, container, false);
mListView = (ListView) view.findViewById(R.id.list_view);
mListView.setAdapter(mAdapter);
mListView.setTextFilterEnabled(true);
// do stuff here //
return view;
and this is list.xml:
<FrameLayout xmlns:android:="http://schemas.android.com/apk/res/android"
android:id="#id/main_fragment"
android:layout_width="match_parent"
android:layout:height=match_parent">
<ListView android:id="#+id/list_view"
android:layout_width="match_parent"
android:layout:height=0dp"
android:layout_weight="1"
android:layout:marginTop="20dp"
android:descendantFocusability="blocksDescendants"/>
</FrameLayout>
how come I cannot see anything?
Solved: This was because I set the height to 0dp.
Please update your code by this:
<FrameLayout xmlns:android:="http://schemas.android.com/apk/res/android"
android:id="#+id/main_fragment"
android:layout_width="match_parent"
android:layout:height=match_parent">
<ListView android:id="#+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="20dp"
android:descendantFocusability="blocksDescendants"/>
</FrameLayout>
The goal is to display two Fragments (Frag A, Frag B) on the screen in a different layout depending on the screen orientation (portrait or landscape).
When the device is in Portrait mode, only one of Frag A and Frag B is displayed at a time using swiping to switch between UIs. ViewPager works perfectly for this.
When the device is in Landscape mode, Frag A is displayed on the left of the screen and Frag B is displayed on the right. A simple LinearLayout works perfectly for this.
The problem arises when trying to get both working in the same application. It seems like the ViewPager class must be referred to in the Java source code (in the onCreate method). This means that a UI element is defined in both the XML and the source code... which seems like a problem when the device is in Landscape mode and there should not be ViewPager object but one is referred to in the source code. Am I approaching this correctly? If one layout is using ViewPager, does every other layout need a ViewPager?
layout/activity_mymain.xml
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MyMainActivity" >
<!--
This title strip will display the currently visible page title, as well as the page
titles for adjacent pages.
-->
<android.support.v4.view.PagerTitleStrip
android:id="#+id/pager_title_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#33b5e5"
android:paddingBottom="4dp"
android:paddingTop="4dp"
android:textColor="#fff" />
</android.support.v4.view.ViewPager>
layout-land/activity_mymain.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<fragment android:name="com.example.ActionFragment"
android:id="#+id/action_fragment"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<fragment android:name="com.example.SummaryFragment"
android:id="#+id/summary_fragment"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
From MyMainActivity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_topmain);
// Create the adapter that will return a fragment for each of the three
// primary sections of the app.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
}
ViewPager is used to instantiate View objects at runtime, so it needs to be defined in the code.
What I was trying to do is very similar to the different tablet/handset layouts described in the Fragments Guide, where they recommend using separate Activities.
(If anyone knows of a way to handle swiping entirely in XML, that would be a much better solution)