ViewpagerIndicator use with SherlockFragmentActivity or ListFragment - android

In my project im using actionBarSherlok library and is working fine.
I want to implement the google play app, beautiful widgets effect. For that i found the following library.
And also works. But my problem is how can i combine the secod librery to be use with listfragment or with SherlockFragmentActivity (which i prefer).
Example code:
- TestFragment is just a Fragment class. getItem is the method that returns the fragment that will be show when the user move the finger on the screen right? If its an #override method how can i show on screen other class than Fragment?
Do i need to create an adapter, if this is the case how i know what i have to keep in mind? or is there one for this type of things?
I think im missing something.
class GoogleMusicAdapter extends TestFragmentAdapter implements TitleProvider {
public GoogleMusicAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return TestFragment.newInstance(SampleTabsDefault.CONTENT[position % SampleTabsDefault.CONTENT.length]);
}
#Override
public int getCount() {
return SampleTabsDefault.CONTENT.length;
}
#Override
public String getTitle(int position) {
return SampleTabsDefault.CONTENT[position % SampleTabsDefault.CONTENT.length].toUpperCase();
}
}
Regards.

Related

Android viewPager2 FragmentStateAdapter with variable fragments

I am trying to implement viewPager2 with variable number of fragments, and not sure on the correct / best approach and couldn't find any good examples to copy!
The fragments in my viewpager depend on the properties of the object being displayed - the first 2 are always present, but there are 4 more that may or may not be present - i.e. the FragmentStateAdapter does not know how many fragments there will be or which ones will be present until runtime.
My initial approach was to have a List that I passed to my FragmentStateAdapter which looked like this:
public class busDetailFragmentAdapter extends FragmentStateAdapter {
private final List<Fragment> fragmentList;
public busDetailFragmentAdapter(#NonNull Fragment fragmentActivity, List<Fragment> fragmentList) {
super(fragmentActivity);
this.fragmentList = fragmentList;
}
// return fragments at every position
#NonNull
#Override
public Fragment createFragment(int position) {
return fragmentList.get(position);
}
#Override
public int getItemCount() {
return fragmentList.size();
}
}
I then simply added fragments to my list with tabFragments.add(new busDetailInfoFrag()); and notified the fragmentadapter that an item had been inserted.
This worked fine until I navigated away from the parent fragment and then used the back button - the app crashed with a "Fragment already added" error.
I found something in the docs creating about new fragments and not reusing fragment. So, I modified my adapter to use a list of strings rather than a list of fragments, and am looking up the position against this list and using a switch statement to create the correct fragment.
public class busDetailFragmentAdapter extends FragmentStateAdapter {
private final List<String> fragmentList;
public busDetailFragmentAdapter(#NonNull Fragment fragmentActivity, List<String> fragmentList) {
super(fragmentActivity);
this.fragmentList = fragmentList;
}
// return fragments at every position
#NonNull
#Override
public Fragment createFragment(int position) {
switch (fragmentList.get(position)){
case "info":
return new busDetailInfoFrag();
case "location":
return new busDetailLocationFrag();
//More cases as needed
default:
return new missingFrag();
}
}
#Override
public int getItemCount() {
return fragmentList.size();
}
}
This is working as I need it to, but just wondering if this is the best/correct approach or if there's a better way!

How to reuse layouts/fragments in ViewPager

Hi there I am wondering what is the correct way if I would like to add different instance of a Fragment which uses the same Layout with different content in a ViewPager.
So for a better understanding I create my Fragments with an createInstance() method and pass an id with which it gets content for a list from a database. I add them to my FragmentPagerAdapter.
So what I get is the first Fragment added multiple times without getting its content for the actual id.
How could I force the ViewPager to treat the Fragments individually ?
*Edit:
Okay I totally failed within my createInstance() method which was more a getInstance() method and returned the same instance every time...
You need to set adapter.notifyDataSetChanged.
Refer below
class MyFragmentAdapter extends FragmentPagerAdapter{
public MyFragmentAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return new PagerFragment(arrayListUri.get(position),position);
}
#Override
public int getCount() {
return 0;
}
}

How to swipe between fragments?

So I have a section_home layout that shows a picture. Then I made another layout called section_home_two that shows a different picture. In my code I have a class called HomeFragment for the section_home layout. The second java class is called PreviewsFragment for the section_home_two layout.
Is there anyway you can make HomeFragment swipe horizontally to PreviewsFragment? Is there anyway to merge them?
I would suggest that you use a ViewPager to swipe between the fragments.
Follow the instructions at http://developer.android.com/training/animation/screen-slide.html to get the ViewPager working, and then change the number of pages to 2:
private static final int NUM_PAGES = 2;
And use this PagerAdapter instead of the one in the sample:
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
public ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
if (position == 0)
return new HomeFragment(); // The ViewPager will show this fragment first
else
return new PreviewsFragment; // and will allow you to swipe to this one and back.
}
#Override
public int getCount() {
return NUM_PAGES;
}
}
This will allow you to swipe horizontally back and forth between the two fragments. if you're using a factory method to create your fragments, use that instead of the return new HomeFragment(); and return new PreviewsFragment(); lines.

How can make my ViewPager load only one page at a time ie setOffscreenPageLimit(0);

I understand the lowest number I can give setOffscreenPageLimit(int) is 1. but I need to load one page at a time because memory problems.
Am i going to have to use the old style tabhost etc? or is there a way/hack I can make my viewPager load one page at a time?
My Adapter extends BaseAdapter with the ViewHolder patern.
I was having the same problem and I found the solution for it:
Steps:
1) First Download the CustomViewPager Class from this link.
2) Use that class as mentioned below:
In Java:
CustomViewPager mViewPager;
mViewPager = (CustomViewPager) findViewById(R.id.swipePager);
mViewPager.setOffscreenPageLimit(0);
In XML:
<com.yourpackagename.CustomViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/swipePager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Now only one page will be loaded at once.
P.S: As per the question's requirement, I have posted the solution for Viewpager. I haven't tried the same with TabLayout yet. If I will find any solution for that I will update the answer.
In this file, KeyEventCompat is used it may not found by the android studio because KeyEnentCompat class was deprecated in API level 26.0.0 so you need to replace KeyEventCompat to event for more details you can view
https://developer.android.com/sdk/support_api_diff/26.0.0-alpha1/changes/android.support.v4.view.KeyEventCompat
As far as I know, that is not possible when using the ViewPager. At least not, when you want your pages to be swipe-able.
The explaination therefore is very simple:
When you swipe between two pages, there is a Point when both pages need to be visible, since you cannot swipe between two things when one of those does not even exist at that point.
See this question for more: ViewPager.setOffscreenPageLimit(0) doesn't work as expected
CommonsWare provided a good explaination in the comments of his answer.
but I need to load one page at a time because memory problems.
That presumes that you are getting OutOfMemoryErrors.
Am i going to have to use the old style tabhost etc?
Yes, or FragmentTabHost, or action bar tabs.
or is there a way/hack I can make my viewPager load one page at a time?
No, for the simple reason that ViewPager needs more than one page at a time for the sliding animation. You can see this by using a ViewPager and swiping.
Or, you can work on fixing your perceived memory problems. Assuming this app is the same one that you reported on earlier today, you are only using 7MB of heap space. That will only result in OutOfMemoryErrors if your remaining heap is highly fragmented. There are strategies for memory management (e.g., inBitmap on BitmapOptions for creating bitmaps from external sources) that help address such fragmentation concerns.
My Adapter extends BaseAdapter with the ViewHolder patern.
BaseAdapter is for use with AdapterView, not ViewPager.
I have an Answer for this. The above said method setUserVisibleHint() is deprecated and you can use setMaxLifecycle() method. For loading only the visible fragment you have to set the behaviour to BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT in the viewpager adapter. ie; in the Constructor. And for handling the fragment use onResume() method in the fragment.
In this way you can load only one fragment at a time in the viewpager.
public static class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
#Override
public int getCount() {
return NUM_ITEMS;
}
#Override
public Fragment getItem(int position) {
return ArrayListFragment.newInstance(position);
}
}
In Kotlin:
class MyAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm,BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT )
Also use with FragmentPagerAdapter (now deprecated) in same way
By using this method you can load one page at time in tab layout with view pager`
#Override
public void onResume() {
super.onResume();
if (getUserVisibleHint() && !isVisible) {
Log.e("~~onResume: ", "::onLatestResume");
//your code
}
isVisible = true;
}
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser && isVisible) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//your code
}
}, 500);
}
}
`
Override the setUserVisibleHint and add postDelayed like below in your every fragments.
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
if (isVisibleToUser)
Handler().postDelayed({
if (activity != null) {
// Do you stuff here
}
}, 200)
super.setUserVisibleHint(isVisibleToUser)
}
I can manage by this way and its working fine now for me.
First, copy in the SmartFragmentStatePagerAdapter.java which provides the intelligent caching of registered fragments within our ViewPager. It does so by overriding the instantiateItem() method and caching any created fragments internally. This solves the common problem of needing to access the current item within the ViewPager.
Now, we want to extend from SmartFragmentStatePagerAdapter copied above when declaring our adapter so we can take advantage of the better memory management of the state pager:
public abstract class SmartFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
// Sparse array to keep track of registered fragments in memory
private SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
public SmartFragmentStatePagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
// Register the fragment when the item is instantiated
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
// Unregister when the item is inactive
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
// Returns the fragment for the position (if instantiated)
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
}
// Extend from SmartFragmentStatePagerAdapter now instead for more dynamic ViewPager items
public static class MyPagerAdapter extends SmartFragmentStatePagerAdapter {
private static int NUM_ITEMS = 3;
public MyPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
// Returns total number of pages
#Override
public int getCount() {
return NUM_ITEMS;
}
// Returns the fragment to display for that page
#Override
public Fragment getItem(int position) {
switch (position) {
case 0: // Fragment # 0 - This will show FirstFragment
return FirstFragment.newInstance(0, "Page # 1");
case 1: // Fragment # 0 - This will show FirstFragment different title
return FirstFragment.newInstance(1, "Page # 2");
case 2: // Fragment # 1 - This will show SecondFragment
return SecondFragment.newInstance(2, "Page # 3");
default:
return null;
}
}
// Returns the page title for the top indicator
#Override
public CharSequence getPageTitle(int position) {
return "Page " + position;
}
}
You actually don't need a custom ViewPager.
I had the same issue and I did like this.
Keep the setOffscreenPageLimit() as 1.
Use fragment's onResume and onPause lifecycle methods.
Initialize and free-up memories on these lifecycle methods.
I know this is an old post, but I stumbled upon this issue and found a good fix if your loading fragments. Simply, check if the user is seeing the fragment or not by overriding the setUserVisibleHint(). After that load the data.
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
getData(1, getBaseUrl(), getLink());
}
}

Use one Fragment in a ViewPager multiple times

Is it possible to use one fragment in a viewpager multiple times? I am trying to build a dynamically updated UI using ViewPager.
I want to use the same design, basically the same fragment with different data for every page, like a listview adapter.
You can instantiate the same Fragment class for every page in your ViewPager, passing the position of the ViewPager to control what to display. Something like that:
public class MyFragment extends Fragment {
private int mIndex;
public MyFragment(int index) {
mIndex = index;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
switch(mIndex){
case 0:
// do you things..
case 1:
// etcetera
}
}
}
then, in you FragmentPagerAdapter:
public static class MyAdapter extends FragmentPagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return NUM_ITEMS;
}
#Override
public Fragment getItem(int position) {
return new MyFragment(position);
}
}
That way you can reuse most of your code changing only what you need in the switch/case statement.
You misunderstood the concept of class versus object of class. Your MyFragment.java source code defines class which you turn into "living thing" each time you instantiate it with new operator (new MyFragment();) - this creates object which is an instance of your class. Unless you intentionally prevent this (by i.e. using Singleton pattern) your can make as many instances of the class as you like, same way you are allowed to make as many i.e. cakes using single recipe. And this applies to fragments as well.
So as long as you create separate object (aka said instance) of your class for each page, you should be able to do what you want.

Categories

Resources