ViewPager2与Fragment和点击事件不正常工作

8

我只是想知道是否做错了什么,因为我对这一切都很新。
如果还有其他你想让我添加的内容,请告诉我。
这里是我正在尝试实现ViewPager的repo分支,如果你想查看所有代码。

上下文

所以我有4个类别用Fragments表示,每个类别都拥有一个ArrayList的项目,每个项目都有一个onItemClickListener,应该播放一些音频。
我正在尝试使用ViewPager显示Fragments,但问题在于当我从一个Fragment滚动到另一个Fragment,然后回到已创建的Fragment时,它不会注册触摸事件,什么也不会发生,甚至没有错误或异常。
如果我去一个新创建的Fragment,触摸就可以正常工作。
此外,在切换回已创建的Fragment后,如果我滚动即使只是很少一点到另一个Fragment,然后回来或通过那个FragmentArrayList,由于某种原因,它开始再次识别ArrayList项中的触摸。

类似的问题并没有真正帮助

我尝试过的方法

  • 我尝试使用coordinatorlayout包装ViewPager2,但没有任何区别
  • 我已经阅读了一些用Kotlin编写的官方viewPager2示例,但它们似乎没有类似的情况(而且很难阅读Kotlin代码)

代码片段

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>

这是其中一个片段,其他三个基本相同,只是arrayList中的项目不同以及其他一些小细节:

// ...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");
    }

}

这是分类适配器,它管理片段:

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;
    }
}

这是我的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);
    }
}

在创建ViewPager后,在您的MainActivity中添加以下代码:viewPager.setOffscreenPageLimit(3); - sai Pavan Kumar
@saiPavanKumar 哇,非常感谢,那个方法真的有效。只是我不太明白为什么。 - UnaLuz
2个回答

14

在创建ViewPager后,在你的MainActivity里添加这行代码:viewPager.setOffscreenPageLimit(3);

这是因为ViewPager默认的离屏数量为1,而ViewPager2默认为0。

在ViewPager2中,当你切换标签时,前一个标签将自动刷新。

而在ViewPager中,如果你有3个或更多的标签,当你切换到第三个标签时,第一个标签将被销毁,并且当你回到第一个标签时,它将被重新创建。

viewPager.setOffscreenPageLimit(3); 这行代码的作用是,在你切换到一个标签时,前面的3个标签和后面的3个标签都会被预加载,这样就不会出现任何刷新的情况。


在我的情况下,我有3个片段,如果我设置viewPager.setOffScreenPageLimit(2),并且当前位置是第3个片段,则第一个片段的布局会消失(我可以在第2个片段上看到透明背景)。这正常吗? - Tom3652
是的,我想是这样 - sai Pavan Kumar
我在一个Fragment中使用了FragmentStateAdapter,所以宿主是这个Fragment,而所有的子项也都是Fragments。 - Sharad

0
我在一个Fragment中使用了FragmentStateAdapter和ViewPager2,所以宿主是该Fragment,所有的子项也都是Fragments。唯一解决我遇到的所有子项Fragment的onClick问题的方法是使用适配器的这个构造函数。
FragmentStateAdapter(childFragmentManager, viewLifecycleOwner.lifecycle)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接