Change Viewpager2 fragment from child fragment - java

I have a Main fragment/ViewPager fragment inside the Main Activity and the Main Fragment has the Viewpager2 where I add child fragments into ViewPager via Adapter. Earlier I had a method in Main Activity (Which also had view pager)
public void ChangeFragment_ViewPager(int position, boolean outside) {
if (viewPager!=null){
viewPager.setCurrentItem(position);
}
}
This method easily changes the fragment when I call from any child fragment of viewpager but since I shifted the viewpager to the Main fragment, my viewpager always comes out null from child.
MainFragment.newInstance().ChangeFragment_ViewPager(0, false);
The Main Fragment
public class MainFragment extends Fragment {
ViewPager2 viewPager;
public MainFragment() {
// Required empty public constructor
}
// TODO: Rename and change types and number of parameters
public static MainFragment newInstance() {
MainFragment fragment = new MainFragment();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.main_fragment, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
viewPager = view.findViewById(R.id.Navigation_Drawer_ViewPager);
TabAdapter tabAdapter = new TabAdapter(getChildFragmentManager(), getLifecycle());
viewPager.setAdapter(tabAdapter);
}
public void ChangeFragment_ViewPager(int position, boolean outside) {
if (viewPager!=null){
viewPager.setCurrentItem(position);
}
}
Tab Adapter
public class TabAdapter extends FragmentStateAdapter {
String TAG="###TAB ADAPTER###";
public TabAdapter(#NonNull FragmentManager fragmentManager, #NonNull Lifecycle lifecycle) {
super(fragmentManager, lifecycle);
}
#NonNull
#Override
public Fragment createFragment(int position) {
switch (position) {
case 0:
Log.d(TAG, "Fragment 1");
return FriendsList.newInstance();
case 1:
Log.d(TAG, "Fragment 2");
return PPL_main.newInstance();
}
return FriendsList.newInstance();
}
#Override
public int getItemCount() {
return 2;
}
}
How can I change the fragment from any ViewPager's child fragment?

MainFragment.newInstance().ChangeFragment_ViewPager(0,false);
This line of code instantiates a brand new instance of MainFragment; and therefore you found a null ViewPager.
Instead of that, the current instance exist in the fragment manager is required or simply use requireParentFragment() from the ViewPager child page fragment to get the MainFragment that hosts the ViewPager:
((MainFragment) requireParentFragment()).ChangeFragment_ViewPager(0, false);

Related

PageViewer nested inside a fragment

im trying to have a ViewPager inside a Fragment, I've already seen that i have to use getChildFragmentManager() but i cant find a way to make it work.
Basically what i have is a drawer layout to have a side menu where i can choose the fragment i want to use. In one of these fragments i need a ViewPager with 2 sub-fragments.
When i try to run the fragment with the sub-fragments what i usually get is the error "must implement OnFragmentInteractionListener".
The code i actually have, if i run it as an activity, it goes well, but being a fragment makes it crash
public class Calculator extends Fragment implements Basic.OnFragmentInteractionListener, Cientific.OnFragmentInteractionListener{
private SectionsPagerAdapter mSectionsPagerAdapter;
private OnFragmentInteractionListener mListener;
private ViewPager mViewPager;
public Calculator() {
// Required empty public constructor
}
public static Calculator newInstance(String param1, String param2) {
Calculator fragment = new Calculator();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set up the ViewPager with the sections adapter.
if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
mViewPager = (ViewPager) getView().findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
//here i already tried using getChildFragmentManager()
// but i dont know if i used it wrong
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_calculator, 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 onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
void onFragmentInteraction(Uri uri);
}
#Override
public void onFragmentInteraction(Uri uri) {
}
public static class PlaceholderFragment extends Fragment {
private static final String ARG_SECTION_NUMBER = "section_number";
public PlaceholderFragment() {
}
public static Fragment newInstance(int sectionNumber) {
Fragment fragment=null;
switch (sectionNumber){
case 1: fragment=new Basic();
break;
case 2: fragment=new Cientific();
break;
}
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.content_main, container, false);
return rootView;
}
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
return PlaceholderFragment.newInstance(position + 1);
}
#Override
public int getCount() {
// Show 2 total pages.
return 2;
}
}
The context received in onAttach(Context context) is the instance of Activity so to make it work You need to implement OnFragmentInteractionListener in your Activity.

Tabbed Activity Page Title not showing

This is what I was trying to do, The "Tab One" "Tab Two" as my Tabbed Page Title. Ignore the Toolbar
I created an app that uses tabbed activity, I used the preset tabbed activity in android studio and modified it to my use. But I'm having a problem in showing the tabbed title. I'm working only on 2 tabs for now but i'm planning to add more as I progress.
Here is the codes for my Tabbed Activity Class
public class StudLearnTab extends AppCompatActivity {
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
String key;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tabbed_content);
// primary sections of the activity.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position){
case 0:
Bundle bundle = new Bundle();
bundle.putString("keys",key);
fragment_tabbed_content tab1 = new fragment_tabbed_content();
tab1.setArguments(bundle);
return tab1;
case 1:
fragment_tabbed_activity tab2 = new fragment_tabbed_activity();
return tab2;
default:
return null;
}
}
#Override
public int getCount() {
// Show 2 total pages.
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position){
case 0:
return "Content";
case 1:
return "Try Yourself";
}
return null;
}
}
}
My Fragments only contains the constructor and createview but I'll included it here for reference. Both fragments are almost the same.
public class fragment_tabbed_activity extends Fragment {
public fragment_tabbed_activity() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_tabbed_activity, container, false);
return rootView;
}
}

OnClick Fragment to Fragment switch results in Blank Screen

When switching from one fragment to another fragment (within the second tab of my application), my second fragment is blank. I have tried the solutions linked here, but none seem to work:
Transaction of fragments in android results in blank screen
Android: Getting white screen with fragment transaction
MainActivity:
public class MainActivity extends AppCompatActivity {
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_activity);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter, and add pages.
mViewPager = (ViewPager) findViewById(R.id.container);
mSectionsPagerAdapter.addPage(new Received());
mSectionsPagerAdapter.addPage(new Send());
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_alert_partners, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
private static final String ARG_SECTION_NUMBER = "section_number";
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if(getArguments().getInt(ARG_SECTION_NUMBER)==1) {
View rootView = inflater.inflate(R.layout.fragment_received, container, false);
return rootView;
}
else if(getArguments().getInt(ARG_SECTION_NUMBER)==2) {
View rootView = inflater.inflate(R.layout.fragment_send, container, false);
return rootView;
}
else {//main empty fragment in case of error. Never used in normal behaviour.
View rootView = inflater.inflate(R.layout.fragment_alert_partners, container, false);
return rootView;
}
}
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
//Create an Array list that will hold the pages.
ArrayList<Fragment> pages = new ArrayList<>();
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
return pages.get(position);
}
//Add a page
public void addPage(Fragment f) {
pages.add(f);
}
#Override
public int getCount() {
// Show 2 total pages.
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "Received";
case 1:
return "Send";
}
return null;
}
}
}
SendFragment:
public class Send extends Fragment {
private OnFragmentInteractionListener mListener;
private TextView text1;
public Send() {
// 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
View v = inflater.inflate(R.layout.fragment_send, container, false);
//Need getView() for fragment since setContentView must be set first but is not possible in fragment.
text1 = (TextView)v.findViewById(R.id.textview1);
text1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Send2 send2 = new Send2();
fragmentTransaction.addToBackStack(null);
fragmentTransaction.hide(Send.this);
fragmentTransaction.add(android.R.id.content, send2);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
});
return v;
}
public interface OnFragmentInteractionListener {
}
}
Send2Fragment:
public class Send2 extends Fragment {
private OnFragmentInteractionListener mListener;
public Send2() {
// 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
final View v = inflater.inflate(R.layout.fragment_send2, container, false);
return v;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
}
}
Had to add a framelayout at the end of the layout code for the fragment I was replacing:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/send1frameLayoutId">
</FrameLayout>
Then used this code to switch to a fragment in the same tab of the previous fragment:
Fragment send2 = new Send2();
FragmentManager fragmentManager = getChildFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.send1frameLayoutId, send2);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();

My fragmentClass get wrong page from ViewPager in medod onContextItemSelected

First. Sorry for my English.
I have Activity class with ViewPager as a field and a Fragment class. My activity is a host for a fragment. In Fragment I want to call context menu registered for ImageView. For that, I override 2 methods: onCreateContextMenu and onContextItemSelected.
Problem is:
When onCreateContextMenu is called I get the correct page (that
on the screen now).
But when onContextItemSelected is called I get another page (this
depend on what parameter is set in
ViewPager.setOffscreenPageLimit(int)). For example, if it set 3, the returned page will be those, that on 3 positions to the left or to the right from current that on the screen.
How can I fix it?
Thank you.
Activity code
public class CrimePagerActivity extends FragmentActivity {
private ViewPager mViewPager;
private ArrayList<Crime> mCrimes;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mViewPager = new ViewPager(this);
mViewPager.setId(R.id.viewPager);
setContentView(mViewPager);
mCrimes = CrimeLab.get(this).getCrimes();
mViewPager.setOffscreenPageLimit(4);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mViewPager.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
}
FragmentManager fm = getSupportFragmentManager();
mViewPager.setAdapter(new FragmentStatePagerAdapter(fm) {
#Override
public Fragment getItem(int position) {
Crime crime = mCrimes.get(position);
return CrimeFragment.newInstance(crime.getId());
}
#Override
public int getCount() {
return mCrimes.size();
}
});
UUID crimeId = (UUID) getIntent().getSerializableExtra(CrimeFragment.EXTRA_CRIME_ID);
for (int i = 0; i< mCrimes.size(); i++){
if (mCrimes.get(i).getId().equals(crimeId)){
mViewPager.setCurrentItem(i);
break;
}
}
}
}
and fragment code
public class CrimeFragment extends Fragment {
.......
private ImageView mPhotoView;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
........
View v = inflater.inflate(R.layout.fragment_crime, container, false);
mPhotoView = (ImageView) v.findViewById(R.id.crime_imageView);
registerForContextMenu(mPhotoView);
return v;
}
.........
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
Log.i(TAG, mCrime.getTitle());
switch (v.getId()) {
case R.id.crime_imageView:
if (mCrime.getPhoto() != null)
getActivity().getMenuInflater().inflate(R.menu.crime_photo_context, menu);
break;
}
}
#Override
public boolean onContextItemSelected(MenuItem item) {
Log.i(TAG, mCrime.getTitle());
switch (item.getItemId()) {
case R.id.menu_item_delete_photo:
getActivity().deleteFile(mCrime.getPhoto().getFilename());
PictureUtils.cleanImageView(mPhotoView);
mCrime.setPhoto(null);
return true;
}
return super.onContextItemSelected(item);
}
}
ViewPager.setOffscreenPageLimit(int);
This will prepare the pages at both sides to the left and right (neighbours).
By default it is 1.
So, in your case to get the current fragment created by the viewPager.
You can store the fragments when created in an SparseArray by overriding the instantiateItem() and destroyItem() callback of viewPager with position.
private SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getFragment(int position) {
return registeredFragments.get(position);
}
And where you want to get the current fragment, get it by using the getFragment() method by passing the position.

FragmentStatePagerAdapter, childFragmentManager and orientation change a bad combination?

Here is my the problem, I have an activity, which includes a Fragment that has a ViewPager using (FragmentStatePagerAdapter), all works perfect when the Activity loads for the first time, but when setting setRetainInstance(true) to the parent fragment (the one with the pager), and orientation changes on the activity, it causes
java.lang.IllegalStateException: No activity
When trying to add the saved fragment, here is the code:
Activity:
public class DetailActivity{
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.frame_layout_with_progress_container);
...
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
FragmentManager fm = getSupportFragmentManager();
if (savedInstanceState != null) {
Fragment f = fm.findFragmentById(R.id.container);
if(f instanceof DetailPagerFragment){
detailPagerFragment = (DetailPagerFragment) f;
}
}
}
#Override
protected void onPostResume() {
super.onPostResume();
//If fragment is null, create a new instance
if(detailPagerFragment==null){
detailPagerFragment =
DetailContainerFragment.newInstance(details, initialPosition);
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.container, detailPagerFragment);
ft.commit();
}
Note: that i have to save the fragment instance on onCreate because when the code reaches onStart the reference for this fragment was null (this issue is not important for the time it has something to do with the NavigationDrawer), so i need to manually save the instance of the fragment.
Activity layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/container"/>
</RelativeLayout>
ViewPager Fragmentm this class extends for DetailPagerFragment which is a custom pager fragment it only wraps common code for pagers (for example view inflation, uses inflateView method), this is why the pager is added on a fragment instead of directly to the activity:
public class DetailContainerFragment extends DetailPagerFragment {
List<Detail> details;
public static DetailContainerFragment newInstance(List<Detail> details,int selectedPosition) {
DetailContainerFragment df = new DetailContainerFragment();
df.setSelectedPosition(selectedPosition);
df.setDetails(details);
return df;
}
public void setDetails(List<Detail> details) {
this.details = details;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
/**
* Inflates the view to be used by this fragment
*
* #param inflater
* Inflater to use
* #return Inflated view
*/
#Override
public View inflateView(LayoutInflater inflater) {
return inflater.inflate(R.layout.detail_pager_fragment, null);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
DetailStatePagerAdapter detailStatePagerAdapter = new DetailStatePagerAdapter(getChildFragmentManager());
setPagerAdapter(detailStatePagerAdapter);
return super.onCreateView(inflater, container, savedInstanceState);
}
private class DetailStatePagerAdapter extends FragmentStatePagerAdapter {
public DetailStatePagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return DetailFragment.newInstance(details.get(position));
}
#Override
public CharSequence getPageTitle(int position) {
return details.get(position).getTitle();
}
#Override
public int getCount() {
return details.size();
}
}
}
I had a similar problem with child fragments in a ViewPager.
The parent fragment created new instances of the child fragments to be used with the ViewPager while the adapter kept instances of the old child fragments used before the configuration change.
I ended up cleaning the ChildFragmentManager before initializing the adapter with it:
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mPager = (ViewPager) view.findViewById(R.id.pager);
cleanChildFragments(getChildFragmentManager());
mPagerAdapter = new MyPagerAdapter(getChildFragmentManager(), getTabFragments());
mPager.setAdapter(mPagerAdapter);
}
/**
* This is necessary to have a clean ChildFragmentManager, old fragments might be called otherwise
* #param childFragmentManager
*/
private void cleanChildFragments(FragmentManager childFragmentManager) {
List<Fragment> childFragments = childFragmentManager.getFragments();
if (childFragments != null && !childFragments.isEmpty()) {
FragmentTransaction ft = childFragmentManager.beginTransaction();
for (Fragment fragment : childFragments) {
ft.remove(fragment);
}
ft.commit();
}
}
Maybe this helps someone...

Categories