I want to access Views that are in Fragment's children that are put in ViewPager. The idea is to toggle (disable/enable) spinners when button is pressed. Spinners are placed in separate fragments that are displayed in ViewPager controlled by TabLayout:
// Snippet of code from Fragment A
final TabLayout tabLayout = (TabLayout) view.findViewById(R.id.tabLayout);
final ViewPager viewPager = (ViewPager) view.findViewById(R.id.viewPager);
Fragment childFragment = new Fragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.replace(R.id.viewPager, childFragment).commit();
ViewPagerAdapter adapter = new ViewPagerAdapter(childFragment.getFragmentManager());
adapter.AddFragment(new fragment_unositelj(), "FragmentB");
adapter.AddFragment(new fragment_voditelj(), "FragmentC");
adapter.AddFragment(new fragment_pratitelj(), "FragmentD");
viewPager.setAdapter(adapter);
tabLayout.setupWithViewPager(viewPager);
FragmentB = viewPager.findViewById(R.id.FragmentB);
FragmentC = viewPager.findViewById(R.id.FragmentC);
FragmentD = viewPager.findViewById(R.id.FragmentD);
I don't know how to achieve to set Spinner disabled / enabled in all fragment children's spinner. I tried to set public variable in MainActivity and to control Spinners attribute based on that, but I am not sure in which lifecycle part to place it because fragment B is inflated initialy, and others are when TabItem clicked. I hope I could describe my problem properly. If anything more is needed please let me know. Thanks!
I found workaround for this problem, I am not sure if it is correct way, but for now it works for me. In FragmentB,FragmentC,FragmentD i added
#Nullable
#Override
public View getView() {
if (((MainActivity) getActivity()).getStatus() == 1) {
mySpinner.setEnabled( true );
} else
mySpinner.setEnabled( false );
return super.getView();
}
//(MainActivity) getActivity()).getStatus() - method that returns state if it shold be enabled
Related
I'm using a ViewPager2 with a ViewPagerAdapter. This adapter includes Fragments. The layout of this Fragment has a ScrollView.
What I want to do is to scroll the ScrollView of the shown Fragment to a certain position after clickling a button in the MainActivity. But I don't know how to get the ScrollView. All I know is how to get the shown item (mPager.getCurrentItem).
Details
Fragement:
public class ChapterFragment extends Fragment {
ViewPagerAdapter:
public class ViewPagerAdapter extends FragmentStateAdapter
MainActivity:
ViewPager2 mPager;
ViewPagerAdapter mAdapter = new ViewPagerAdapter(this);
mPager= findViewById(R.id.viewPager);
mPager.setAdapter(mAdapter);
Does anybody can help me?
Thanks.
A highly unsatisfactory answer would be to do the following when your button is clicked:
ViewPager2 yourViewPager = findViewById(R.id.view_pager);
String tag = "f" + yourViewPager.getCurrentItem();
Fragment frag = getSupportFragmentManager().findFragmentByTag(tag);
if(frag != null) {
//find scrollview with 'frag.getView().findViewById...' and scroll to required position
}
There is multiple things u can do there.
Implement an interface in activity.
implement a following code on OnClick of button.
make scrollview variable public in Fragment
if(mPager.getCurrentItem() instanceof ChapterFragment)
{
ChapterFragment chapterFragment =
(ChapterFragment)mPager.getCurrentItem();
chapterFragment.scrollView.scrollTo(20) //move to specific position
}
I used the tablayout in my project. I have to replace the fragment in the tablayout. The code is like below
Activity Class
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(Fragment1, "One");
adapter.addFragment(Fragment2, "Two ");
adapter.addFragment(Fragment3, "Three");
viewPager.setAdapter(adapter);
}
Interface in Activity
#Override
public void onInput(int input) {
Here how to replace fragment three
}
I think replacing the fragment is not a good idea. So I would like to show you another way to achieve what you want.
viewPager.setCurrentItem(position); you can use this method to change the page. Here position is page-number starting from 0 to total-pages - 1.
Use ViewModal to pass latest data (in your case "input"). So here you can set value from onInput(int input) and in each fragment of ViewPager you can subscribe/ unsubscribe ViewModal to listen changes. In this way you do not need to replace fragment and the page which is on screen will get latest data and can show.
I have a ViewPager to which I am adding 3 tab fragments dynamically:
private void addTabs(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new QuotesFragment(), "Quotes");
adapter.addFragment(new BooksFragment(), "Books");
adapter.addFragment(new ExercisesFragment(), "Exercises");
viewPager.setAdapter(adapter);
}
Here's the code of the fragment that is not working as expected:
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
recyclerView = (RecyclerView) getActivity().findViewById(R.id.quotes_recycler);
layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
MasonryAdapter adapter = new MasonryAdapter(context, quotesList);
recyclerView.setAdapter(adapter);
}
The RecyclerView view holders form QuotesFragment() will not show up at parent Activity's start. They only show up when I have scrolled to the last tab (ExercisesFragment() in this case) and returned to the first one. Checking in Hierarchy Viewer it seems that at the app start the RecyclerView is initialized (the container takes necessary space on the screen), but its children are not.
What's odd, when I change the order in which I am adding tabs like so (note my problematic tab is now in the middle):
private void addTabs(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new ExercisesFragment(), "Exercises");
adapter.addFragment(new QuotesFragment(), "Quotes");
adapter.addFragment(new BookFragment(), "Books");
viewPager.setAdapter(adapter);
}
it does never load! I have tried various things, and there's even one question about exactly the same problem, but it does not help in my case. Could it have to do with Fragment/ViewPager lifecycle or implicit methods?
Any help appreciated.
I finally got it to work and it's dumb simple really. I was calling my method that loads quotes from JSON inside Fragment's onCreate() instead of onViewCreated(). When I moved it to onViewCreated() (after setting adapter and layout manager) it started working.
Below is my code. What i am trying to achieve is that i am displaying viewholder inside my Recycler view. Inside view pager i am displaying one fragment and on swipe left i am displaying another fragment. But when i run the app. App is crashing.Don't know where i am going wrong. I think it's some where in fragment's concept. Please do help me
#Override
public void onBindViewHolder(ManageCustomerViewHolder holder, int position)
{
holder.viewPager.setAdapter(new MyPageAdapter(fragmentManager, fragments));
}
private List<Fragment> getFragments()
{
List<Fragment> fList = new ArrayList<Fragment>();
fList.add(MyFragment.newInstance("Fragment 1"));
fList.add(Myfragment1.newInstance("Fragment 2"));
return fList;
}
public class ManageCustomerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
ViewPager viewPager;
viewPager = (ViewPager) itemView.findViewById(R.id.viewpager);
itemView.setOnClickListener(this);
}
This is what the error is :
java.lang.IllegalStateException: Fragment has not been attached yet.
I was facing the same issue in my app.
Stack Trace:
java.lang.IllegalStateException: Fragment has not been attached yet. android.support.v4.app.Fragment.instantiateChildFragmentManager(Fragment.java:2154)
android.support.v4.app.Fragment.getChildFragmentManager(Fragment.java:704)
The app was crashing at this line:
function performSomeActionInChildFragments() {
List<Fragment> fragments = getChildFragmentManager().getFragments();
...
}
This happens when the fragment is no longer attached to its parent activity/fragment. So a simple isAdded() check should resolve this issue for you.
Fix:
function performSomeActionInChildFragments() {
if (!isAdded()) return;
List<Fragment> fragments = getChildFragmentManager().getFragments();
...
}
From documentation:
isAdded() - Return true if the fragment is currently added to its activity.
Update the Support Library Revision to 27.0.2 to solve the problem. See changelog.
you can do this
FragmentManager childFragmentManager ;
in onCreate :
childFragmentManager = getChildFragmentManager();
then you can use childFragmentManager in
ViewPagerAdapter adapter = new ViewPagerAdapter(childFragmentManager);
adapter.addFragment(tabLlegadaFragment, "Llegada");
adapter.addFragment(tabIngresoFragment, "Ingreso");
viewPager.setAdapter(adapter);
`
and don't forget before do that you have to check your activity was added or not.
you can try this way:
if(getActivity()!=null && isAdded()) //do now
I faced this exception today. After looking for answer I noticed that all are related with ViewPager and getFragmentManger() or in my case getChildFragmentManager().
Well sometimes this things happen when there is no fragment so nothing can be attached or shown. Therefore when my fragment was created I now save in a variable the fragment manager, then I use that manager in my Viewpager instance so there will allways be a manager saved in the class.
To clarify what I'm saying here's my code:
Before
ViewPagerAdapter adapter = new ViewPagerAdapter(getChildFragmentManager());
adapter.addFragment(tabLlegadaFragment, "Llegada");
adapter.addFragment(tabIngresoFragment, "Ingreso");
viewPager.setAdapter(adapter);
Here I faced the error because I recreated the view with some method and I also pressed the back button. So when that happened Android is looking for a getChildFragmentManager() from a Fragment that no longer exists or is gone (because I pressed the back button)
Now
FragmentManager childFragMang;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_tab_main, container, false);
..
childFragMang= getChildFragmentManager();
..
return view;
}
and when I call Viewpager I use that manager
ViewPagerAdapter adapter = new ViewPagerAdapter(childFragMang);
adapter.addFragment(tabLlegadaFragment, "Llegada");
adapter.addFragment(tabIngresoFragment, "Ingreso");
viewPager.setAdapter(adapter);
I did not face that exception again so it was because my fragment had dissapeared when I pressed back and there were no getChildFragmentManager() to call
In all cases,when you using getChildFragmentManager, add isAdded() will beneficial to our application.
You shouldn't be trying to instantiate Fragments. Fragments are created and have lifecycles that are controlled by the Android system. You respond to lifecycle events by overriding callback methods like onAttached (called when the fragment is attached to its Activity)
I currently have a view pager in a tab layout
//Get the ViewPager and set it's PagerAdapter so that it can display items
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPager.setAdapter(new SettingsFragmentPagerAdapter(getSupportFragmentManager()));
//Give the TabLayout the ViewPager
TabLayout tabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
And then the fragments in the view pager have TextViews with OnClickListeners attached
final TextView zSemTxt = (TextView) getActivity().findViewById(R.id.zSemTxt);
zSemTxt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mSelectedTextView = zSemTxt;
showDialogToSelectClass();
}
});
My issue is the OnClickListeners are never called, it appears that all touches go to the ViewPager and never goes through to the TextViews. I've tried things like viewPager.requestDisallowInterceptTouchEvent(true); but none of it change anything.
Ideas?
Show more code.
Probably onClick dosen't work because your textview = null.
final TextView zSemTxt = (TextView) getActivity().findViewById(R.id.zSemTxt);
Are You sure about this?
I dont see your code but try
final TextView zSemTxt = (TextView) view.findViewById(R.id.zSemTxt);
where view is your fragment inflated view.
Turns out neither the onActivityCreated or onCreateView were being called on the fragment.
The solution was to go to the PageFragment class I was using to manage which fragment was displayed by the ViewPager and add the onClickListeners to there. The fragments were being inflated there which is why the other classes were never called.