I have a fragment that holds a viewpager and tablayout. I can access the tablayout from the fragment but when I try to do the same for the view pager it always returns null
//this is a method on the pagefragment
public override void OnActivityCreated(Bundle savedInstanceState)
{
base.OnActivityCreated(savedInstanceState);
tabs = this.View.FindViewById<TabLayout>(Resource.Id.mytab);
vp = (ViewPager) Activity.FindViewById(Resource.Id.myviewpage);
SetUpViewPager(vp);
tabs.SetupWithViewPager(vp);
}
vp alway returns null so the app crashes when it get to SetUpViewPager(vp) but the the tabs is accessible
I have a fragment that holds a viewpager and tablayout.
Problem is that you are hosting your ViewPager in a fragment, but you're trying to find it in the Activity. In the Fragment, you can code like this:
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var view = inflater.Inflate(Resource.Layout.fragment1, container, false);
var tabs = view.FindViewById<TableLayout>(Resource.Id.mytab);
var vp1 = (ViewPager)view.FindViewById(Resource.Id.myviewpage);
return view;
}
Related
I' m trying to improve my android app. I have main app menu (with possible actions) in a GridView 3x3. And I decided to add ViewPager to separate my grid. Before I've added ViewPager, I had only one Activity with GridView. In my onCreate method, I calculated the window height with DisplayMetrics to understand, what height should I use for my GridView items.
Now I'm trying to use ViewPager with Fragments. I have my Activity with ViewPager, and 2 Fragments. Each Fragment has the same layout (GridView in LinearLayout). I'm trying to pass screen height into Fragment in this way:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_grid_layout);
pageHeight = getHeight();
Log.d("HEIGHT", "Page height: "+pageHeight);
ViewPager viewPager;
viewPager = findViewById(R.id.main_menu_viewpager);
src = new ArrayList<MainPageTableFragment>();
/*Определяем количество страниц меню*/
int pagesCount = 2;
for (int i = 0; i < pagesCount; i++) {
src.add(MainPageTableFragment.newInstance(i, pageHeight));
}
FragmentPagerAdapter adapter = new ScreenSlidePagerAdapter(getSupportFragmentManager(), src);
viewPager.setAdapter(adapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabDots);
tabLayout.setupWithViewPager(viewPager, true);
}
So, each launch of onCreate method should recreate Fragments.
And in Fragment, I get my height in this way:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
ViewGroup rootView = (ViewGroup) inflater.inflate(
R.layout.activity_main_grid_fragment, container, false);
gridView = rootView.findViewById(R.id.main_menu_grid);
//PROBLEM IS HERE...
height = this.getArguments().getInt("containerHeight");
pageNum = this.getArguments().getInt("pageNumber");
populateGridItems(); //method to load items in gridview
return rootView;
}
The problem is: when I rotate my device, all methods are called, but
height = this.getArguments().getInt("containerHeight");
uses old value. For instance, in first launch (vertical screen orientation), it is 690. When I rotate my device, in onCreate I calculate new height (382), but my Fragment takes old value (690). I tried to call getArguments() in several places (onAttach, onCreate, onActivityCreated), but didn't help.
Can anybody explain me, where is the problem, and what should I do?
Thank you!
UPD: Code of my MainPageTableFragment
public static MainPageTableFragment newInstance(int pageNumber, int height) {
Bundle args = new Bundle();
args.putInt("pageNumber", pageNumber);
args.putInt("containerHeight", height);
MainPageTableFragment fragment = new MainPageTableFragment();
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
ViewGroup rootView = (ViewGroup) inflater.inflate(
R.layout.activity_main_grid_fragment, container, false);
gridView = rootView.findViewById(R.id.main_menu_grid);
height = getArguments().getInt("containerHeight");
Log.d("HEIGHT", "Fragment height in onCreateView: "+height);
pageNum = getArguments().getInt("pageNumber");
populateGridItems();
return rootView;
}
private void populateGridItems() {
/*adding items in GridView*/
gridView.setAdapter(new MenuGridAdapter(this.getContext(), items, height));
}
}
I'm not sure but i think it's because of supportFragmentManager and pagerAdapter.
First time in instantiateItem it creates a name for fragment and in destroyItem it's just detach fragment.
Then after rotating in instantiateItem it founds fragment by name and uses old instance instead of new. I think for optimization and so on.
As a solution, you can remove all fragments from supportFragmentManager or override instantiateItem/destroyItem to remove frgament as you need.
I found another way to do this. In my Activity, I've created public method to calculate height, and in onCreateView in my Fragment, I call this method. It works. But for me, it's unknown problem: why recreation of the fragment took values of arguments from the old bundle.
I have an Activity that has a ViewPager with four Fragments. One of those Fragments must have two tabs inside of it so I tried FragmentTabHost.
private FragmentTabHost fragmentTabHost;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_zbritjet, container, false);
fragmentTabHost = (FragmentTabHost) view.findViewById(android.R.id.tabhost);
fragmentTabHost.setup(view.getContext(), getFragmentManager(), android.R.id.tabcontent);
fragmentTabHost.addTab(fragmentTabHost.newTabSpec("tab_ofertat").setIndicator("Ofertat"), OfertatItems.class, null);
fragmentTabHost.addTab(fragmentTabHost.newTabSpec("tab_bizneset").setIndicator("Bizneset"), BiznesetItems.class, null);
return view;
}
The problem is that android is throwing
java.lang.IllegalStateException: FragmentManager is already executing transactions
Stack trace:
android.support.v4.app.FragmentManagerImpl.ensureExecReady(FragmentManager.java:1946)
android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1992)
android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:762)
android.support.v4.app.FragmentTabHost.onAttachedToWindow(FragmentTabHost.java:289)
Try getChildFragmentManager() instead of getFragmentManager().
From the docs:
Return a private FragmentManager for placing and managing Fragments inside of this Fragment.
I'm getting a strange problem with Fragment and ViewPager.
I have 1 ViewPager contains 3 Fragments.
When my app run for the first time. onCreateView on all my fragments get called and ViewPager works perfectly.
Code for initalizing ViewPager
private void initPager() {
mFragmentList.add(new MainSongListFragment());
mFragmentList.add(new MainAlbumArtFragment());
mFragmentList.add(new MainLyricsFragment());
if (mFragmentList == null)
mFragmentList = new ArrayList<Fragment>();
MainPagerAdapter pagerAdapter = new MainPagerAdapter(
getSupportFragmentManager(), mFragmentList);
mMainPager.setAdapter(pagerAdapter);
myListViewInsideFragment= (ListView) findViewById(R.id.my_list);
}
When I press back button and run app again. I get error at the code:
myListViewInsideFragment= (ListView) findViewById(R.id.my_list);
It returns null because the onCreateView method on Fragment does not get called so all views on this fragment is not avaiable.
Code in My Fragment:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.lo_my_list, container,
false);
mListView = (ListView) view
.findViewById(R.id.my_list);
return view;
}
My question is:
Why does not onCreateView method get called when Activity get destroyed and re-run again?.
Thank you.
Once again, I am so annoyed by the AndroidSDK . Why does this have to be so complicated?
I have a ViewPager that I want to populate with my Fragment. I implemented this on an Activity and it works. But when its in another Fragment the whole thing crashes and the erros messages tells me nothing:
07-01 12:58:20.210: E/AndroidRuntime(10146): java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
Here is my code:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_tabwrapper, container);
List<Fragment> fragments = getFragments();
pageAdapter = new MyPageAdapter(getActivity()
.getSupportFragmentManager(), fragments);
pager = (ViewPager) v.findViewById(R.id.viewpager);
pager.setAdapter(pageAdapter); // <- CRASH!
return v;
}
BTW: The whole thing is based on this tutorial: http://architects.dzone.com/articles/android-tutorial-using
This error occurs beacuse you have to remove all views before set adapter in view pager so get right way..... So check this:
MyPageAdapter pageAdapter ;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_tabwrapper, container);
List<Fragment> fragments = getFragments();
pageAdapter = new MyPageAdapter(getActivity()
.getSupportFragmentManager(), fragments);
pager = (ViewPager) v.findViewById(R.id.viewpager);
pager.removeallviews();
pager.setAdapter(pageAdapter); // <- CRASH!
return v;
}
you should not use the ViewGroup that onCreateView provides as container to put your inflated view:
Change
View v = inflater.inflate(R.layout.fragment_tabwrapper, container);
to
View v = inflater.inflate(R.layout.fragment_tabwrapper, null);
This might shed a little light on the topic: http://developer.android.com/about/versions/android-4.2.html#NestedFragments
IMHO: I don't understand why developers put up with these tools. I find them impossible to work with. No wonder there are so many low-quality apps on the Play store. I'm looking forward to the day this project is done. Won't be working with this OS anytime soon again ...
I have a FragmentActivity which sets a main layout with 3 tabs. Each tab has it's own fragment which inflates is own layout into main layout.
For example, one of the three Fragments:
public class Fragment1 extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
return null;
}
return inflater.inflate(R.layout.fragment1, container, false);
}
}
When I add all the fragments and connect them with tabs everything works. When I click on tab1, layout of the Fragment1 shows, when I click on Tab2, layout of the Fragment2 shows.
The problem is that when I want to change something in that inflated layout (for example execute setText to textView in fragment1 layout), I receive a NullPointerException in that line and application stops.
This doesn't work:
TextView test = (TextView) findViewById(R.id.fragmentOneText1);
test.setText("Test text!");
How to set data to inflated layout?
You have to inflate your fragment specific layout first by using LayoutInflater and map the control in your Fragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.R.layout.fragment1, container, false);
TextView text = (TextView) fragmentView.findViewById(R.id.fragmentOneText1);
mTextNoResult=(TextView)fragmentView.findViewById(R.id.text_noresult);
return fragmentView;
}