i have seen the relative post to my issue but, it's not solve my probleme.
I'm trying to get a swipe view with 3 fragment.
In the main fragment i have this:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View vue = inflater.inflate(R.layout.fragment_conversions, container, false);
ConversionsPagerAdapter cPageAdapter = new ConversionsPagerAdapter(getActivity().getSupportFragmentManager());
ViewPager vp = vue.findViewById(R.id.conversionsPager);
cPageAdapter.getItem(0);
vp.setAdapter(cPageAdapter);
Button convKmhKts = (Button) vue.findViewById(R.id.convKmhKts);
convKmhKts.setText("...");
...
Here is the class of my FragmentStatePagerAdapter:
public class ConversionsPagerAdapter extends FragmentStatePagerAdapter{
public ConversionsPagerAdapter(FragmentManager fm) {
super(fm);
Log.i("ARKA", "FragmentStatePagerAdapter CONSTRUCTOR");
}
#Override
public Fragment getItem(int i) {
return ConversionFragment.newInstance(i);
}
#Override
public int getCount() {
return 1;
}
}
And finnaly the Fragment which display the Tab:
public class ConversionFragment extends Fragment {
public static final String ID_CONVERSION = "id_conversion";
public static ConversionFragment newInstance(int pos) {
ConversionFragment stf = new ConversionFragment();
Bundle args = new Bundle();
args.putInt("pos", pos);
stf.setArguments(args);
return stf;
}
public ConversionFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
// The last two arguments ensure LayoutParams are inflated
// properly.
Bundle args = getArguments();
int idConversion = args.getInt(ID_CONVERSION);
Log.i("idConversion", String.valueOf(idConversion));
int idVue;
switch (idConversion){
case 0: idVue = R.layout.fragment_conversions_vitesse;
break;
case 1: idVue = R.layout.fragment_conversions_vitesse;
default: idVue = R.layout.fragment_conversions_vitesse;
break;
}
View rootView = inflater.inflate(idVue, null);
return rootView;
}
}
The fact is, the getItem() is never called.
I try to change getActivity().getSupportFragmentManager() by getChildFragmentManager(), but it seem it's not the good way...
When i'm trying to acces my button i get this:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
At the line where i'm using the button.
If you use ViewPager inside fragment you have to use chield fragment manager so try replace getActivity().getSupportFragmentManager() with getChildFragmentManager(). If you use one fragment manager for all stuff, it will bring some bugs to you.
For more information
You are doing wrong here
cPageAdapter.getItem(0);
vp.setAdapter(cPageAdapter);
Set adapter to view pager first and then try to call get item method.
vp.setAdapter(cPageAdapter);
cPageAdapter.getItem(0);
Ok,
the probleme was that i try to acces a component which is not inflated:
convKmhKts.setText("...");
I acces to it in the child fragment and now it's ok....
Related
So currently my code can move between objects from the same fragment, but I want to move between different fragments that have different layouts.What code do I need to add to viewpager to make it work? Do I need to make use of a FragentManager? Can anyone guide me on how to go about it? Thanks.
Below if my code:
ScreenSlidePagerActivity.java
public class ScreenSlidePagerActivity extends FragmentActivity {
private static final int NUM_PAGES = 5;
private ViewPager mPager;
private PagerAdapter pagerAdapter;
/**
* The pager adapter, which provides the pages to the view pager widget.
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.slide_screen_viewpager);
//declare viewpager and pageradapter
mPager = findViewById(R.id.ViewPageSlide);
pagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(pagerAdapter);
}
#Override
public void onBackPressed() {
if (mPager.getCurrentItem() == 0){
// If the user is currently looking at the first step, allow the system to handle the
// Back button. This calls finish() on this activity and pops the back stack.
super.onBackPressed();
}
else {
mPager.setCurrentItem(mPager.getCurrentItem() -1 );
}
}
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
public ScreenSlidePagerAdapter(FragmentManager fm)
{
super(fm);
}
#Override
public Fragment getItem(int position) {
return new ScreenSlidePageFragment();
}
#Override
public int getCount() {
return NUM_PAGES;
}
}
}
ScreenSlidePageFragment.java
public class ScreenSlidePageFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
ViewGroup rootView = (ViewGroup) inflater.inflate(
R.layout.slide_content_page, container, false
);
return rootView;
}
}
You have only one class i.e.,ScreenSlidePageFragment that extends fragments. If you want different layouts for that, its better if you create different classes that inflates different layouts. eg: if you want two layouts, create two classes and both classes should inflate different layouts. The changes need to be done are :
//inside ScreenSlidePagerAdapter
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new ScreenSlidePageFragment();
case 1:
return new NewClass();
//and so on
}
}
You have to create the new Class similar to ScreenSlidePageFragment. The only change is inflate a different layout.
public class NewClass extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
ViewGroup rootView = (ViewGroup) inflater.inflate(
R.layout.new_layout, container, false
);
return rootView;
}
}
You can create a new_layout similar to slide_content_page and customize it as you want. You can also increase the no of fragment objects and layout as you wish.
But a new way of doing this things has come. Its better if you extend FragmentStateAdapter instead of FragmentStatePagerAdapter. This is more easy and efficient. You have to override createFragment in this case instead of getItem. Ignore of you are okay with it.
Hope this is the question you have asked and this helps. Thankyou.
I have an activity and its child Fragment with a LinearLayout that I generate buttons inside of. When the fragment is created, everything runs fine. However, when the parent activity downloads a new item, I call the method in the fragment that is used to generate the buttons and add them to the view, but the LinearLayout returns null and I can't figure out why. I either need to fix it or find a way to "re-display" my fragment. Here is the related code:
SongFragment:
LinearLayout linearLayout;
DatabaseHelper databaseHelper;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_song, container, false);
linearLayout = rootView.findViewById(R.id.songFragmentMainLayout);
databaseHelper = new DatabaseHelper(getActivity());
return rootView;
}
#Override
public void onResume() {
super.onResume();
RefreshButtons();
}
public void RefreshButtons(){
linearLayout.removeAllViews(); //this line is where the NullPointerException is called
...
}
MainActivity:
//refresh fragment view
SongFragment fragment = (SongFragment) sectionsPagerAdapter.getItem(0);
if(downloadQueue.size() == 0){
fragment.RefreshButtons();
Toast.makeText(context, "New songs downloaded", Toast.LENGTH_SHORT).show();
}
...
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = new SongFragment();
break;
case 1:
fragment = new PlaceholderFragment();
break;
}
return fragment;
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "Songs";
case 1:
return "Playlists";
}
return null;
}
}
Thanks for your help.
The method fragment.RefreshButtons(); returns an NPE because if you implemented SectionsPagerAdapter like you should, getItem() returns a new Instance of that fragment which is not yet attached to the fragment manager, therefore causing a Nullpointer exception.
So what you should do is get a currently active fragment instance like this:
Fragment frag = (Fragment) mViewPager.getAdapter().instantiateItem(mViewPager, 0);
0 is the position of your fragment, so for example if you have 3 fragments, 0 will return the first fragment instance etc...
I'm using ViewPager to show welcome, register, and some other screens. those screens are fragments controlled by FragmentStatePagerAdapter:
private static class TourPagerAdapter extends FragmentStatePagerAdapter {
public TourPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
WellcomeTourFragment ta = null;
switch (position) {
case 0:
ta = WellcomeTourFragment.newInstance(R.layout.welcome_fragment);
break;
case 1:
ta = WellcomeTourFragment.newInstance(R.layout.signup_fragment);
break;
first fragment (WellcomeFragment) shows some views and background image loaded from internet using picasso library:
private ImageView bkgImage;
public static WellcomeTourFragment newInstance(int layoutId){
WellcomeTourFragment pane = new WellcomeTourFragment();
Bundle args = new Bundle();
args.putInt(LAYOUT_ID, layoutId);
pane.setArguments(args);
return pane;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final ViewGroup rootView = (ViewGroup) inflater.inflate(getArguments().getInt(LAYOUT_ID, -1), container, false);
this.bkgImage = (ImageView) rootView.findViewById(R.id.imgView_Background);
return rootView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Picasso.with(getActivity())
.load(IMG_uRL)
.into(this.bkgImage);
}
My problem here is that, i am getting
java.lang.IllegalArgumentException: Target must not be null.
I am sure the ImageView does exits in my welcome_fragment layout. but really don't know what makes target to be null.
Are you sure that the correct layout is being inflated? Try debugging and looking at the rootView after it has been inflated. Is it possible you are including the wrong layout id when you call your newInstance method?
I seem to be having an issue updating the fragments that I am using in my ViewPager, regardless of whether I try in onCreate(), onCreateView(), or onResume(). Here is how I'm setting up my ViewPager in my MainFragment:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_screen, container, false);
mPager = (ViewPager)rootView.findViewById(R.id.pager);
mPager.setOffscreenPageLimit(2); // So all 3 pages are loaded at once.
mAdapter = new JournalPagerAdapter(getActivity().getSupportFragmentManager(), this);
mPager.setAdapter(mAdapter);
// Add bar graph to view
mGraphLayout = (LinearLayout) rootView.findViewById(R.id.journalGraph);
updateGraph();
mGraphLayout.addView(mGraphView);
mPainFrag = (PainFragment)mAdapter.getRegisteredFragment(0);
// Null pointer here, but if I put the action in a button listener, it works.
mPainFrag.setScale(mEntry.getPain());
...
I'm accessing the fragments through some overridden methods in my FragmentPagerAdapter:
public class JournalPagerAdapter extends FragmentPagerAdapter {
SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
private View.OnClickListener mOnClickListener;
public JournalPagerAdapter(FragmentManager mgr, View.OnClickListener onClickListener) {
super(mgr);
mOnClickListener = onClickListener;
}
#Override
public Fragment getItem(int pos) {
switch(pos) {
case 0: return PainFragment.newInstance("PainFragment", mOnClickListener);
case 1: return StressFragment.newInstance("StressFragment", mOnClickListener);
case 2: return SleepFragment.newInstance("SleepFragment", mOnClickListener);
default: return PainFragment.newInstance("PainFragment", mOnClickListener);
}
}
#Override
public int getCount() {
return 3;
}
/* Thanks to Streets of Boston (http://stackoverflow.com/questions/8785221/retrieve-a-fragment-from-a-viewpager)
*/
#Override
public Object instantiateItem(ViewGroup container, int position) {
Log.v("rx", "itemInstantiated");
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 getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
I can't seem to figure out why the fragment is null right after I set the adapter, but if I put the fragment update code in a click event, I have no issues.
I would try adding a layout listener to your ViewPager to get notified when the laying out of views has occurred.
When you create your ViewPager call mPager.getViewTreeObserver().addOnGlobalLayoutListener() and pass something implementing OnGlobalLayoutListener.
In the callback method, do your fragment updating. Make sure to call mPager.getViewTreeObserver().removeGlobalOnLayoutListener(this) in the callback, otherwise the callback will be called multiple times.
You could instantiate your fragments in the PagerAdapter's constructor and just have getItem return them instead of instantiating them.
this is my first time using tabs in an app and I feel like this will be a simple fix but I can not find the correct solution. I have 5 tab fragments right now but when I run it all of them contain the same material. I think the problem is with this method:
#Override
public Fragment getItem(int position) {
Fragment fragment = new MiscFragment();
Bundle args = new Bundle();
args.putInt(MiscFragment.ARG_SECTION_NUMBER, position + 1);
fragment.setArguments(args);
return fragment;
}
I have the fragment set to a new MiscFragment(); (which eclipse automatically built with a dummyfragment when I created the project)
And I have:
public static class MiscFragment extends Fragment {
public static final String ARG_SECTION_NUMBER = "section_number";
public MiscFragment() {
}
View rootView;
GridView gridView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.misc_fragment,
container, false);
gridView = (GridView) rootView.findViewById(R.id.miscgridview);
gridView.setAdapter(new MiscAdapter(getActivity()));
return rootView;
}
}
public static class OtherFragment extends Fragment{
public static final String ARG_SECTION_NUMBER = "section_number";
public OtherFragment(){
}
View rootView;
GridView gridView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup contatiner,
Bundle savedInstanceState){
rootView = inflater.inflate(R.layout.sb_fragment,
contatiner, false);
gridView = (GridView) rootView.findViewById(R.id.sbgridview);
gridView.setAdapter(new OtherAdapter(getActivity()));
return rootView;
}
}
(The first method and both inner classes are in my MainActivity)and it looks like they both use the same "section_number" so both GridViews are referencing the same thing. Both my adapter classes for each fragment have a different number of items in the GridView but the second one looks and acts the same as the first. Any help would be much appreciated!
You never read the section_number argument in the fragment.
int section = getArguments().getInt(ARG_SECTION_NUMBER);
I hate answering my own question but here it is:
The problem was with the getItem method. It works as follows:
public Fragment getItem(int position) {
Fragment fragment1 = new FirstFragment();
Fragment fragment2 = new SecondFragment();
Fragment fragment3 = new ThirdFragment();
if(position == 0){
return fragment1;
}
else if (position == 1){
return fragment2;
}
else{
return fragment3;
}
}
Then each (Number)Fragment() relates to the inner Fragment classes