在安卓中正确使用ViewPager2的实现方式

150

我了解到 ViewPager2 并尝试使用它,但是没有找到合适的例子。

有人可以告诉我如何使用它吗?

我正在寻找正确的用法,而不是一个例子。


7
这里有解释和示例,请查看:http://michaelevans.org/blog/2019/02/07/hands-on-with-viewpager2/ - Mehul Kabaria
3
给“推荐或寻找书籍、工具、软件库、教程或其他离线资源”投了反对票的人,请仔细阅读,我并不是在寻找例子。请翻译成中文。 - Pratik Butani
这里有一个官方示例:https://github.com/googlesamples/android-viewpager2 - Albert Vila Calvo
1
感谢您的提问,看起来像是博客:D - Nikunj Paradva
@NikunjParadva对Nilesh Rathod的回答非常感激,看起来像是一篇博客文章。问题很简单。 - Pratik Butani
1
这是一篇实现方案的文章 https://t.ly/3qgj - iamnaran
13个回答

0

这是我的解决方案(Android Studio 3.6):

在 app/build.gradle 中:

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation('com.crashlytics.sdk.android:crashlytics:2.10.1@aar') { transitive = true; }
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'com.google.android.material:material:1.1.0-beta01'
    implementation 'org.altbeacon:android-beacon-library:2.16.3'
    implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
    implementation 'androidx.viewpager2:viewpager2:1.0.0-beta05'

    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    implementation "androidx.core:core-ktx:+"
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

这是我的活动:

import android.os.Bundle;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.widget.ViewPager2;

import java.util.ArrayList;
import java.util.List;

import com.myproject.android.R;
import com.myproject.android.adapter.CustomFragmentStateAdapter;
import com.myproject.android.ui.fragment.BluetoothPageFragment;
import com.myproject.android.ui.fragment.QrPageFragment;

public class QRBluetoothSwipeActivity extends AppCompatActivity {
    private ViewPager2 myViewPager2;
    private CustomFragmentStateAdapter myAdapter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        // Make sure this is before calling super.onCreate
        setTheme(R.style.AppTheme); // show splash screen
        super.onCreate(savedInstanceState);
        setContentView(R.layout.qr_bluetooth_swipe_activity);
        init();
    }

    private void init() {
        List<Fragment> fragmentList = new ArrayList<Fragment>();
        QrPageFragment m1 = new QrPageFragment();
        BluetoothPageFragment m2 = new BluetoothPageFragment();
        myViewPager2 = findViewById(R.id.viewPager2);
        fragmentList.add(m2);
        fragmentList.add(m1);
        myAdapter = new CustomFragmentStateAdapter(this, fragmentList);
        myViewPager2.setAdapter(myAdapter);
    }
}

这里是布局:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.actviity.SplashDelayActivity">

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

</androidx.constraintlayout.widget.ConstraintLayout>

这里是我的CustomFragmentStateAdapter

import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;

import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;

public class CustomFragmentStateAdapter extends FragmentStateAdapter {
    private List<Fragment> listFragment = new ArrayList<>();

    public CustomFragmentStateAdapter(FragmentActivity fa, List<Fragment> list) {
        super(fa);
        listFragment = list;
    }

    @NotNull
    @Override
    public Fragment createFragment(int position) {
        return listFragment.get(position);
    }

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

这是我的代码片段:

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import com.myproject.android.R;

public class BluetoothPageFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.bluetooth_page_fragment, container, false);
    }

}

和第二个片段:

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import com.myproject.android.R;

public class QrPageFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.qr_page_fragment, container, false);
    }

}

现在我使用androidx.viewpager2.widget.ViewPager2与我的自定义片段。

它可以工作!!!

很好。

P.S. 另一个实现:

public class CustomFragmentStateAdapter extends FragmentStateAdapter {
    private ArrayList<Fragment> arrayList = new ArrayList<>();

    public CustomFragmentStateAdapter (FragmentActivity fa) {
        super(fa);
    }

    public void addFragment(Fragment fragment) {
        arrayList.add(fragment);
    }

    @Override
    public int getItemCount() {
        return arrayList.size();
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        // return your fragment that corresponds to this 'position'
        return arrayList.get(position);
    }
}

然后在活动中这样使用:

 myViewPager2 = findViewById(R.id.viewPager2);
        myAdapter = new CustomFragmentStateAdapter (this);
        myAdapter.addFragment(new QrPageFragment());
        myAdapter.addFragment(new BluetoothPageFragment());
        myViewPager2.setAdapter(myAdapter);

我使用了FragmentPageAdapter中的RecyclerView来展示图片,但是速度太慢了,就像一只猪和马一起奔跑。 - Gilberto Ibarra
5
这不正确。FragmentStateAdaptercreateFragment 回调函数应该(正如它的名称所示)创建一个 Fragment,而不是返回已经创建好并且正在等待中的 Fragment。使用你的方法会干扰 FragmentManager 的操作。 - Bartek Lipinski
@BartekLipinski。那么,我如何像文档中所说的那样在运行时动态修改片段集合,并使ViewPager2正确显示修改后的集合? - ramaral
@BartekLipinski,我创建了一个由4个片段组成的列表,然后在createFragment中按位置返回了一个项目。一切都按预期工作,无需每次重新创建片段。但是适配器是这样调用的:val adapter = object : FragmentStateAdapter(childFragmentManager, viewLifecycleOwner.lifecycle) - CoolMind
2
仅仅因为它“按预期工作”,并不意味着它“按照应该的方式工作”。FragmentManager 是相当复杂的机制(约 4k 行代码),如果不遵循其 API,你可能会遇到一些边缘情况和不确定的行为。 - Bartek Lipinski
我正在做同样的事情,但是我注意到如果我在onCreate()中使用viewpager.setCurrentItem(savedIndex),在屏幕方向改变时会出现一些片段的重复。有人遇到过这个问题吗? - Muhammad Hanzilah

0
在 Kotlin FragmentStateAdapter with ViewPager2 中,迁移的主要原因是 ViewPager2 正在接受积极的开发支持,而 ViewPager 不是。然而,ViewPager2 还提供了其他几个特定的优点。
在 ViewPager2 中的 FragmentStateAdapter 与 ViewPager 中略有不同,具体如下: 1] 不再实现 getCount(),而是实现 getItemCount() 2] 不再实现 getItem(int position),而是实现 createFragment(int position) 3] 构造函数签名不同,需要添加 Lifecycle 参数,并在 super 中包含
因此,请使用以下 Kotlin PagerAdapter 替换您的 ViewPagerFragmentAdapter。
class SurveyPagerAdapter(
private val fragmentList: MutableList< Fragment>,
fragment: FragmentManager,
lifecycle: Lifecycle) : FragmentStateAdapter(fragment,lifecycle){
override fun getItemCount(): Int = fragmentList.size
override fun createFragment(position: Int): Fragment {
    return fragmentList[position]
}
fun getFragmentName(position: Int) = fragmentList[position]
fun addFragment(fragment: Fragment) {
    fragmentList.add(fragment)
    notifyDataSetChanged()
}}

Kotlin Activity *只需在onCreate()方法中添加一个方法*

private fun setUpViewPager(){

    val fragmentList : MutableList< Fragment> = mutableListOf()
    fragmentList.add(SurveyPageOneFragment.newInstance(true))
    fragmentList.add(SurveyPageTwoFragment.newInstance(true))
    fragmentList.add(SurveyPageThreeFragment.newInstance(true))
    fragmentList.add(SurveyPageFourFragment.newInstance(true))
    fragmentList.add(SurveyPageFiveFragment.newInstance(true))

    surveyPagerAdapter = SurveyPagerAdapter(fragmentList,supportFragmentManager,lifecycle)
    binding.viewPager.adapter = surveyPagerAdapter
    binding.dotsIndicator.attachTo(binding.viewPager)

}

Kotlin碎片

class SurveyPageOneFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    arguments?.let {
    }
}
override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    return inflater.inflate(R.layout.fragment_survey_page_one, container, false)
}
companion object {
    @JvmStatic
    fun newInstance(isMyBoolean: Boolean) = SurveyPageOneFragment().apply {
        val fragment = SurveyPageOneFragment()
        arguments = Bundle().apply {
            putBoolean("REPLACE WITH A STRING CONSTANT", isMyBoolean)
        }
        fragment.arguments
        return fragment
    }
}}

在ViewPager2中的XML代码

<androidx.viewpager2.widget.ViewPager2
                android:id="@+id/view_pager"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layoutDirection="ltr"/>

圆点指示器 //Kotlin圆点指示器实现'com.tbuonomo:dotsindicator:4.3'

<com.tbuonomo.viewpagerdotsindicator.DotsIndicator
                android:id="@+id/dots_indicator"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:dotsColor="@color/colorSurveyEditGreenLight"
                app:dotsCornerRadius="8dp"
                app:dotsSize="16dp"
                app:dotsSpacing="4dp"
                app:dotsWidthFactor="2.5"
                app:selectedDotColor="@color/white"
                app:progressMode="true"
                />

-2

我个人在 Fragment 中使用了 ViewPager2。这是我的做法。GitHub 上有示例代码 [https://github.com/codebyjames/Example-Using-ViewPager2-Slide-Page-Adapter]

首先,在 onCreate 方法中:

        // pager adapter
        val pagerAdapter = ScreenSlidePageAdapter(this@ManagerFragment)
        viewPager.adapter = pagerAdapter
        viewPager.setPageTransformer(ZoomOutPageTransformer())

ViewPager的适配器

class ScreenSlidePageAdapter(val fragment: Fragment): FragmentStateAdapter(fragment) {

val fragments = listOf(WalkThroughFragment(), PermissionsFragment(), DatastoreFragment())

override fun getItemCount(): Int {
    return fragments.size
}

override fun createFragment(position: Int): Fragment {
    return fragments[position]
}

}

ViewPager2 的转换 - 可选

class ZoomOutPageTransformer : ViewPager2.PageTransformer {

override fun transformPage(view: View, position: Float) {
    view.apply {
        val pageWidth = width
        val pageHeight = height
        when {
            position < -1 -> { // [-Infinity,-1)
                // This page is way off-screen to the left.
                alpha = 0f
            }
            position <= 1 -> { // [-1,1]
                // Modify the default slide transition to shrink the page as well
                val scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position))
                val vertMargin = pageHeight * (1 - scaleFactor) / 2
                val horzMargin = pageWidth * (1 - scaleFactor) / 2
                translationX = if (position < 0) {
                    horzMargin - vertMargin / 2
                } else {
                    horzMargin + vertMargin / 2
                }

                // Scale the page down (between MIN_SCALE and 1)
                scaleX = scaleFactor
                scaleY = scaleFactor

                // Fade the page relative to its size.
                alpha = (MIN_ALPHA +
                        (((scaleFactor - MIN_SCALE) / (1 - MIN_SCALE)) * (1 - MIN_ALPHA)))
            }
            else -> { // (1,+Infinity]
                // This page is way off-screen to the right.
                alpha = 0f
            }
        }
    }
}

}

我的 ManagerFragment 布局(包含 ViewPager2)

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

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