I'm developing an app that displays information about wifistate, battery and other stuffs. To do this, I'm using fragments and each one has It's own ListView showing the info. When I slide from a fragment to another one, Listviews make the UI lag causing a bad user experience. How could I avoid this?
Thank You in advance.
EDIT:
This is my Adapter code:
public class GenericFragmentPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> _fragments;
public GenericFragmentPagerAdapter(FragmentManager fm,List<Fragment> fragments) {
super(fm);
_fragments = fragments;
}
#Override
public int getCount() {
return _fragments.size();
}
#Override
public Fragment getItem(int position) {
return _fragments.get(position);
}
#Override
public String getPageTitle(int position) {
return ((ITitledFragment) _fragments.get(position)).getTitle();
}
}
Related
I'm trying to create a calendar application. Each month is one Fragment. I'm using ViewPager and FragmentPageAdapter. I want to add one Fragment when swiping to the left and position is 2 and I want to add one Fragment when swiping to the right and position is fragments.size() - 2.
I have no problem to add Fragment to the right but the problem occurs when adding to 0 position because of Can't change tag of fragment exception. I was looking to the solution to the problem with no success. I'm wondering if there is some alternative to ViewPager or another solution to this problem.
Here is my adapter:
public class ViewPagerAdapter extends FragmentPagerAdapter {
private ArrayList<Fragment> fragments = new ArrayList<>();
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getCount() {
return fragments.size();
}
public void addFragment(Fragment fragment) {
fragments.add(fragment);
notifyDataSetChanged();
}
public void addFragment(Fragment fragment, int position) {
fragments.add(position, fragment);
notifyDataSetChanged();
}
public void removeFragment(int position) {
fragments.remove(position);
notifyDataSetChanged();
}
public void removeFragment(Fragment fragment) {
fragments.remove(fragment);
notifyDataSetChanged();
}
}
I'm building a FragmentPagerAdapter (The one with the small icons) which I want;
To the first item in the middle (Horizontal) of the screen
To swipe through it and make them go one 5th of the screen to the left/right
What would be the best way to achieve this?
This is a visual representation:
This is the code of the FragmentPagerAdapter:
public class NavigationPagerAdapter extends FragmentPagerAdapter {
public NavigationPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return NavigationFragment.newInstance(position);
}
#Override
public int getCount() {
return stores.size();
}
#Override
public CharSequence getPageTitle(int position) {
return null;
}
#Override
public float getPageWidth(int position) {
return 0.2f;
}
}
I hope I understood this right. Try to add the following configuration to your `ViewPager.
pager.setOffScreenPageLimit(4);
pager.setClipToPadding(false);
pager.setPageMargin(-500);
pager.setHorizontalFadingEdgeEnabled(true);
pager.setFadingEdgeLength(20);
Feel free to customize the values and get your desired effect
public class MyPageAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
public MyPageAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
#Override
public Fragment getItem(int position) {
return this.fragments.get(position);
}
#Override
public int getCount() {
int s = this.fragments.size();
return this.fragments.size();
}
}
Text here:
if i go from tab4 to tab2 than first control go to tab2 than it go to tab1. i could not understand how can it go to tab1?
I can see you're trying to cache the fragments into memory by using the this context. But you're not supposed to, FragmentPagerAdapter class should do it for you. Google webpage and sample # FragmentPagerAdapter. Look at sample code on that page.
Code snippet:
#Override
public Fragment getItem(int position) {
return ArrayListFragment.newInstance(position);
}
Notes:
Notice the call to method newInstance. Implement it in your Fragment.
Need to define a fragment subclass, sample uses ArrayListFragment.
In the android documentation on FragmentStatePagerAdapter it is explained that the adapter can be set up like this:
public static class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return NUM_ITEMS;
}
#Override
public Fragment getItem(int position) {
return MyFragment.newInstance();
}
}
I would like to use this, however, I would also like to manage the Fragments that were added with a FragmentManager. How can I do this? My approach is throwing a NullPointerException.
public static class MyAdapter extends FragmentStatePagerAdapter {
private FragmentManager mFragmentManager;
public MyAdapter(FragmentManager fm) {
super(fm);
mFragmentManager = fm;
}
#Override
public int getCount() {
return NUM_ITEMS;
}
#Override
public Fragment getItem(int position) {
mFragmentManager.beginTransaction()
.add(MyFragment.newInstance(), MyFragment.TAG).commit();
return mFragmentManager.findFragmentByTag(MyFragment.TAG);
}
}
How can I do this?
You write your own PagerAdapter implementation from scratch. FragmentPagerAdapter and FragmentStatePagerAdapter will do their own fragment transactions, colliding with yours.
I want to prepend a new View as first page of my ViewPager.
My adapter looks like this:
public class PagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> fragments;
public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
#Override
public Fragment getItem(int index) {
return fragments.get(index);
}
#Override
public int getCount() {
return fragments.size();
}
public void add(int i, ImageFileObject imageFile) {
ImageViewFragment f = new ImageViewFragment();
f.setImage(imageFile);
fragments.add(0, f);
notifyDataSetChanged();
}
public void add(ImageFileObject imageFile) {
ImageViewFragment f = new ImageViewFragment();
f.setImage(imageFile);
fragments.add(f);
notifyDataSetChanged();
}
}
But when calling add(0, aImageFile) the item is not prepended to the fragment list. (It's not even appended).
Any ideas?
Update: The problem that you described in comment is real, I missed it in first testing. After analyzing the source code of FragmentPagerAdapter I realized that all we need to do is to Override getItemId() in a way that it won't return same id for different fragment items. E.g. current default implementation would just return position as an id for fragment which won't work for this case:
public long getItemId(int position) {
return position;
}
I am updating this answer, please have a look. As before I have tested this code and the problem you described is not happening now.
Only thing you need is not to keep reference of fragments by yourself in List, This is done for you by FragmentPagerAdapter. And as far as I know its not a good practise either. And also even if you return POSITION_NONE from getItemPosition() as suggested by other answer(s), you will end up with Exception
Caused by: java.lang.IllegalStateException: Can't change tag of fragment.
This is because you are trying to reposition alive Fragments in your List by adding a fragment at 0th index (which causes other fragments to reposition) and ViewPager assigns tags based on position.
Keeping all this in mind, here is a tested and working modified adapter:
public class PagerAdapter extends FragmentPagerAdapter {
public static class FragmentInfo {
public String classz;
public ImageFileObject imageFile;
public static long IDS;
public long id;
public FragmentInfo(){
id = IDS++;
}
}
private final List<FragmentInfo> fragments;
private Context context;
public PagerAdapter(FragmentManager fm, List<FragmentInfo> fragments,
Context context) {
super(fm);
this.fragments = fragments;
this.context = context;
}
#Override
public Fragment getItem(int index) {
FragmentInfo info = fragments.get(index);
ImageViewFragment frag = (ImageViewFragment) Fragment.instantiate(
context, info.classz, /* null arguments*/ null);
frag.setImage(info.imageFile);
return frag;
}
#Override
public long getItemId(int position) {
return fragments.get(position).id;
}
#Override
public int getCount() {
return fragments.size();
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
public void add() {
FragmentInfo f = new FragmentInfo();
f.classz = ImageViewFragment.class.getName();
fragments.add(0, f);
notifyDataSetChanged();
}
}
Please change your code accordingly.
The problem is actually with notifyDataSetChanged. Just add to your Adapter:
public int getItemPosition(Object object) {
return POSITION_NONE;
}
However, I think you will get other problems when the Adapter actually tries to call getItem again. These problems will be in the lines of "Fragment Already Added".