Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ViewPager2 not working properly with Fragments and click events

I just wanna know if I'm doing something wrong since I'm kinda new to all this.
If there is anything else that you'll like me to add just let me know.
This is the repo branch where I'm trying to implement the ViewPager if you wanna see all the code.

Context

So I have 4 Categories represented with Fragments, each of this categories holds an ArrayList of items that each has a onItemClickListener that should reproduce some audio.
I'm trying to display the Fragments with a ViewPager but the problem is that when I scroll from a Fragment to another, then come back to the already created Fragment, it doesnt register the touch event, nothing happens, not even an error nor exception.
If I go to a newly created Fragment the touch works just fine.
Also, after switching back to an already created Fragment if I scroll even just a little bit to another Fragment and comeback or through the ArrayList of that Fragment for some reason it starts to recognize the touch in the ArrayList items again.

Similar questions that didn't really help

  • Fragments in ViewPager2 does not respond to clicks if scroll position is 0
  • ViewPager2 conflicting with SwipeRefreshLayout
  • Android ViewPager2 with fragment containing a recyclerview not scrolling

What I've tried

  • I tried to use a coordinatorlayout wrapping the ViewPager2 but there is no difference
  • I've been reading some of the official viewPager2 examples that are written in Kotlin but none of them seem to have a similar situation (also it's hard for me to read Kotlin code)

Code Snippets

word_list.xml:

<ListView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root_list_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/tan_background" />

activity_main.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="MainActivity">

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"/>

</FrameLayout>

This is one of the Fragments, the other three are basically the same, just the items in the arrayList change and some other minor things:

// ...Skipped some irrelevant code...

public class NumbersFragment extends Fragment {
    private ArrayList<Word> mWords;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View rootView = inflater.inflate(R.layout.word_list, container, false);

        mWords = new ArrayList<>();
        // ...Add all the items to the list...

        // Make the adapter for the word items
        WordAdapter adapter = new WordAdapter(getActivity(), mWords, R.color.category_numbers);
        // Find the root view of the list
        ListView listView = rootView.findViewById(R.id.root_list_view);
        // Add adapter to the root list view
        listView.setAdapter(adapter);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Log.d("NumbersFragment", "CLICKED");
                }
            }

        });

        return rootView;
    }

    @Override
    public void onPause() {
        super.onPause();

        Log.d("NumbersFragment", "Fragment paused");
    }

}

This is the Category adapter, it manages the fragments:

public class CategoryAdapter extends FragmentStateAdapter {
    private static final int NUM_CATEGORIES = 4;

    // Required public constructor
    public CategoryAdapter(@NonNull FragmentActivity fragmentActivity) {
        super(fragmentActivity);
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        // Depending on which page the user is in,
        // create a fragment of the corresponding category
        switch (position) {
            case 0:
                return new NumbersFragment();
            case 1:
                return new FamilyFragment();
            case 2:
                return new ColorsFragment();
            default:
                return new PhrasesFragment();
        }
    }

    @Override
    public int getItemCount() {
        return NUM_CATEGORIES;
    }
}

And this is my MainActivity:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Set the content of the activity to use the activity_main.xml layout file
        setContentView(R.layout.activity_main);

        // Find the view pager that will allow the user to swipe between fragments
        ViewPager2 viewPager = findViewById(R.id.viewpager);

        // Create an adapter that knows which fragment should be shown on each page
        CategoryAdapter adapter = new CategoryAdapter(this);
        //or CategoryAdapter adapter = new CategoryAdapter(getSupportFragmentManager(), getLifecycle());

        // Set the adapter into the view pager
        viewPager.setAdapter(adapter);
    }
}
like image 469
UnaLuz Avatar asked Jun 20 '20 06:06

UnaLuz


People also ask

How to pass listener to Fragment?

You need to call an extra method every time you want to instantiate the Fragment . You can't guarantee that mListener is set at any time. You may need to pepper your Fragment code with null checks. You need to be careful to make sure the listener remains set after lifecycle events such as screen rotation.

How does ViewPager2 work?

ViewPager2 uses FragmentStateAdapter objects as a supply for new pages to display, so the FragmentStateAdapter will use the fragment class that you created earlier. Create an activity that does the following things: Sets the content view to be the layout with the ViewPager2 .

How to share data between fragments?

Share data between a parent and child fragment When working with child fragments, your parent fragment and its child fragments might need to share data with each other. To share data between these fragments, use the parent fragment as the ViewModel scope.


Video Answer


1 Answers

add this in your MainActivity viewPager.setOffscreenPageLimit(3); after creating viewpager

It’s because the ViewPager has a default offscreen limit of 1 ,and ViewPager2 has a default offscreen limit of 0.

In ViewPager2 when you switch tabs the previous tab will be automatically refreshed.

in ViewPager if you have 3 tabs or more when you switch to 3rd tab automatically first one will be destroyed and when you goes to 1st tab it will be recreated.

viewPager.setOffscreenPageLimit(3); from this line when you switch to a tab,the previous 3 tabs will be preloaded and next 3 tabs will be preloaded so nothing will be refreshed.

like image 120
sai Pavan Kumar Avatar answered Sep 21 '22 21:09

sai Pavan Kumar