Правильна реалізація ViewPager2 в Android


86

Я дізнався про ViewPager2 і спробував його реалізувати, але не знайшов жодного належного прикладу.

Хто-небудь може сказати мені, як я можу ним користуватися.

Я шукаю правильного використання, а не прикладу.


7
Ось пояснення та приклад перевірити це: michaelevans.org/blog/2019/02/07/hands-on-with-viewpager2
Мехул Кабарія

3
Той, хто дав близькі голоси за, recommend or find a book, tool, software library, tutorial or other off-site resourceбудь ласка, уважно прочитайте, що я не шукаю приклад.
Пратік Бутані



@NikunjParadva Відповідь Nilesh Rathod дуже цінується, а також виглядає як допис у блозі. Питання просто.
Пратік Бутані

Відповіді:


196

ОНОВЛЕННЯ 7

Перевірка: Мігруйте з ViewPager на ViewPager2

Позначка : Створіть подання пальцем за допомогою вкладок за допомогою ViewPager2

ОНОВЛЕННЯ 6

Перевірте мою відповідь, якщо ви хочете застосувати Карусель за допомогою View Pager2

ОНОВЛЕННЯ 5

Як використовувати TabLayout з ViewPager2

ЗРАЗОК КОДУ

Використовуйте нижче dependencies

implementation 'com.google.android.material:material:1.1.0-alpha08'
implementation 'androidx.viewpager2:viewpager2:1.0.0-beta02'

ЗРАЗОК КОДУ

Розмітка XMl

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
        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">

    <com.google.android.material.appbar.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:layout_scrollFlags="scroll|enterAlways"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

        <com.google.android.material.tabs.TabLayout
                android:id="@+id/tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewpager"
            app:layout_anchor="@id/tabs"
            app:layout_anchorGravity="bottom"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
    />


</androidx.coordinatorlayout.widget.CoordinatorLayout>

Діяльність

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*
import com.google.android.material.tabs.TabLayoutMediator

import com.google.android.material.tabs.TabLayout


class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

//        setSupportActionBar(toolbar)
        viewpager.adapter = AppViewPagerAdapter(supportFragmentManager, lifecycle)

        TabLayoutMediator(tabs, viewpager, object : TabLayoutMediator.OnConfigureTabCallback {
            override fun onConfigureTab(tab: TabLayout.Tab, position: Int) {
                // Styling each tab here
                tab.text = "Tab $position"
            }
        }).attach()


    }
}

ВИХІД

TabLayout із ViewPager2

З Документів

ViewPager2

Нові можливості

  • Підтримка макета справа наліво (RTL)
  • Підтримка вертикальної орієнтації
  • notifyDataSetChanged повністю функціональний

Зміни API

  • FragmentStateAdapter замінює FragmentStatePagerAdapter
  • RecyclerView.Adapter замінює PagerAdapter
  • registerOnPageChangeCallback замінює addPageChangeListener

ЗРАЗОК КОДУ

додати останню версію dependenciesдляViewPager2

implementation 'androidx.viewpager2:viewpager2:1.0.0-alpha01'

макет

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    tools:context=".MainActivity">

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

</LinearLayout>

діяльність

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;

import java.util.ArrayList;

public class MyActivity extends AppCompatActivity {

    ViewPager2 myViewPager2;
    MyAdapter MyAdapter;
    private ArrayList<String> arrayList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);

        myViewPager2 = findViewById(R.id.view_pager);

        arrayList.add("Item 1");
        arrayList.add("Item 2");
        arrayList.add("Item 3");
        arrayList.add("Item 4");
        arrayList.add("Item 5");

        MyAdapter = new MyAdapter(this, arrayList);


        myViewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);

        myViewPager2.setAdapter(MyAdapter);
    }
}

MyAdapter

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {

    private Context context;
    private ArrayList<String> arrayList = new ArrayList<>();

    public MyAdapter(Context context, ArrayList<String> arrayList) {
        this.context = context;
        this.arrayList = arrayList;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        holder.tvName.setText(arrayList.get(position));
    }

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

    public class MyViewHolder extends RecyclerView.ViewHolder {
        TextView tvName;

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            tvName = itemView.findViewById(R.id.tvName);
        }
    }
}

Нові можливості

тепер нам потрібно використовувати, ViewPager2.OnPageChangeCallback()щоб отримати Swipe подіюViewPager2

ЗРАЗОК КОДУ

    myViewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            super.onPageScrolled(position, positionOffset, positionOffsetPixels);
        }

        @Override
        public void onPageSelected(int position) {
            super.onPageSelected(position);

            Log.e("Selected_Page", String.valueOf(position));
        }

        @Override
        public void onPageScrollStateChanged(int state) {
            super.onPageScrollStateChanged(state);
        }
    });

ми можемо встановити Орієнтацію за допомогою myViewPager2.setOrientation()

ЗРАЗОК КОДУ

Для HORIZONTAL Orientationвикористання

myViewPager2.setOrientation(ViewPager2.ORIENTATION_HORIZONTAL);

Для VERTICAL Orientationвикористання

myViewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);

Ми можемо використовувати те notifyDataSetChangedсаме, що і вRecyclerView.Adapter

ЗРАЗОК КОДУ, щоб додати новий елемент

    btnAdd.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            arrayList.add("New ITEM ADDED");
            MyAdapter.notifyDataSetChanged();
        }
    });

ЗРАЗОК КОДУ, щоб видалити новий елемент

    btnRemove.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            arrayList.remove(3);
            MyAdapter.notifyItemRemoved(3);
        }
    });

ОНОВЛЕННЯ

Спробуйте це, якщо хочете використовувати FragmentзViewPager2

Спочатку створіть ViewPagerFragmentAdapterклас, який розширюєтьсяFragmentStateAdapter

import java.util.ArrayList;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.viewpager2.adapter.FragmentStateAdapter;

public class ViewPagerFragmentAdapter extends FragmentStateAdapter {

    private ArrayList<Fragment> arrayList = new ArrayList<>();

    public ViewPagerFragmentAdapter(@NonNull FragmentManager fragmentManager) {
        super(fragmentManager);
    }

    @NonNull
    @Override
    public Fragment getItem(int position) {
        return arrayList.get(position);
    }

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

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

Тепер використовуйте так у своїй діяльності

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import neel.com.bottomappbar.R;

public class MainActivity extends AppCompatActivity {

    ViewPager2 myViewPager2;
    ViewPagerFragmentAdapter myAdapter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myViewPager2 = findViewById(R.id.view_pager);

        myAdapter = new ViewPagerFragmentAdapter(getSupportFragmentManager());

        // add Fragments in your ViewPagerFragmentAdapter class
        myAdapter.addFragment(new FragmentOne());
        myAdapter.addFragment(new Fragmenttwo());
        myAdapter.addFragment(new FragmentThree());

        // set Orientation in your ViewPager2
        myViewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);

        myViewPager2.setAdapter(myAdapter);

    }

}

для отримання додаткової інформації перевірте це

ОНОВЛЕННЯ 2

Версія 1.0.0-alpha02

Нові можливості

  • Можливість вимкнення введення користувачем ( setUserInputEnabled, isUserInputEnabled)

Зміни API

  • ViewPager2 фінал класу

Виправлення помилок

  • FragmentStateAdapter виправлення стабільності

ЗРАЗОК КОДУ, щоб вимкнути проведення пальцем у viewpager2

myViewPager2.setUserInputEnabled(false);// SAMPLE CODE to disable swiping in viewpager2


myViewPager2.setUserInputEnabled(true);//SAMPLE CODE to enable swiping in viewpager2

ОНОВЛЕННЯ 3

Версія 1.0.0-alpha03

Нові можливості

  • Можливість програмної прокрутки ViewPager2: fakeDragBy (offsetPx) .

Зміни API

  • FragmentStateAdapterтепер потрібен Lifecycleоб’єкт. Додано два конструктори утиліти, щоб отримати його від хоста FragmentActivityабо фрагмента хосту

ЗРАЗОК КОДУ

ViewPagerFragmentAdapter

import java.util.ArrayList;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Lifecycle;
import androidx.viewpager2.adapter.FragmentStateAdapter;

public class ViewPagerFragmentAdapter extends FragmentStateAdapter {

    private ArrayList<Fragment> arrayList = new ArrayList<>();


    public ViewPagerFragmentAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) {
        super(fragmentManager, lifecycle);
    }

    @NonNull
    @Override
    public Fragment getItem(int position) {
        return arrayList.get(position);
    }

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

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

Код MainActivity

import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import neel.com.bottomappbar.R;

public class MainActivity extends AppCompatActivity {

    ViewPager2 myViewPager2;
    ViewPagerFragmentAdapter myAdapter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myViewPager2=findViewById(R.id.view_pager);
        myAdapter = new ViewPagerFragmentAdapter(getSupportFragmentManager(), getLifecycle());

        // add Fragments in your ViewPagerFragmentAdapter class
        myAdapter.addFragment(new FragmentOne());
        myAdapter.addFragment(new Fragmenttwo());
        myAdapter.addFragment(new FragmentThree());

        myViewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);

        myViewPager2.setAdapter(myAdapter);
    }
}

ОНОВЛЕННЯ 4

Version 1.0.0-alpha05 Нові можливості

  • ItemDecoratorвведено з поведінкою, що відповідає RecyclerView.
  • MarginPageTransformer представлений, щоб забезпечити можливість створювати простір між сторінками (поза вставкою сторінки).
  • CompositePageTransformer представлений для забезпечення можливості поєднання кількох PageTransformers

Зміни API

  • FragmentStateAdapter#getItemметод, перейменований на FragmentStateAdapter#createFragment- попередня назва методу в минулому виявилась джерелом помилок.
  • OFFSCREEN_PAGE_LIMIT_DEFAULTзначення змінено з 0 на -1. Не потрібно змінювати код клієнта, якщо він OFFSCREEN_PAGE_LIMIT_DEFAULTconstantвикористовується.

ЗРАЗОК КОДУ

Код діяльності

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.MarginPageTransformer;
import androidx.viewpager2.widget.ViewPager2;
import neel.com.bottomappbar.R;

public class MainActivity extends AppCompatActivity {

    ViewPager2 myViewPager2;
    ViewPagerFragmentAdapter myAdapter;
    private ArrayList<Fragment> arrayList = new ArrayList<>();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myViewPager2 = findViewById(R.id.myViewPager2);

        // add Fragments in your ViewPagerFragmentAdapter class
        arrayList.add(new FragmentOne());
        arrayList.add(new Fragmenttwo());
        arrayList.add(new FragmentThree());

        myAdapter = new ViewPagerFragmentAdapter(getSupportFragmentManager(), getLifecycle());
        // set Orientation in your ViewPager2
        myViewPager2.setOrientation(ViewPager2.ORIENTATION_HORIZONTAL);

        myViewPager2.setAdapter(myAdapter);

        myViewPager2.setPageTransformer(new MarginPageTransformer(1500));


    }
}

ViewPagerFragmentAdapter

import java.util.ArrayList;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Lifecycle;
import androidx.viewpager2.adapter.FragmentStateAdapter;

public class ViewPagerFragmentAdapter extends FragmentStateAdapter {

    private ArrayList<Fragment> arrayList = new ArrayList<>();


    public ViewPagerFragmentAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) {
        super(fragmentManager, lifecycle);
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        switch (position) {
            case 0:
                return new FragmentOne();
            case 1:
                return new Fragmenttwo();
            case 2:
                return new FragmentThree();

        }
        return null;
    }

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

13
Здається, мені доводиться робити допис у блозі: D
Пратік Бутані

1
Чудово, у мене не було часу на публікацію в блозі, але я зроблю це точно.
Пратік

1
Раннє введення ViewPager2 від @BirjuVachhani, перевірте це, це може бути корисно
Раві

2
Чи можна використовувати PagerTitleStripабо PagerTabStripз ViewPager2, або, можливо, є альтернатива?
Гійом

1
@NileshRathod, ти створив список фрагментів, але нікуди їх не кличеш?
вхід

7

Насправді зараз існує офіційний зразок репозиторію для ViewPager2 (посилання нижче)

РЕПО містить наступні зразки (цитування з репо-репозиторію нижче)

Зразки

  • ViewPager2 з поданнями - показує, як налаштувати ViewPager2 з поданнями як сторінки
  • ViewPager2 з фрагментами - показує, як налаштувати ViewPager2 з фрагментами як сторінками
  • ViewPager2 з змінною колекцією (Views) - демонструє використання ViewPager2 з поданнями як сторінки та мутації в адаптері сторінок
  • ViewPager2 з мінливою колекцією (фрагменти) - демонструє використання ViewPager2 з фрагментами як сторінками та мутаціями в адаптері сторінок
  • ViewPager2 з TabLayout (Views) - показує, як налаштувати ViewPager2 з поданнями як сторінками та зв’язати його з TabLayout

Простий приклад ViewPager2 з фрагментами в Kotlin

Activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".MainActivity">

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/pager2_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

</LinearLayout>

MainActivity.kt

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)


        val viewPager2 = findViewById<ViewPager2>(R.id.pager2_container)

        val fragmentList = arrayListOf(
            FirstFragment.newInstance(),
            SecondFragment.newInstance(),
            ThirdFragment.newInstance()
        )
        viewPager2.adapter = ViewPagerAdapter(this, fragmentList)
   }
}

FirstFragment.kt ( SecondFragment.ktі ThirdFragment.ktсхожий на FirstFragment.kt)

class FirstFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_first, container, false)
    }

    companion object{
        fun newInstance() = FirstFragment()
    }
}

ViewPagerAdapter.kt

class ViewPagerAdapter(fa:FragmentActivity, private val fragments:ArrayList<Fragment>): FragmentStateAdapter(fa) {

    override fun getItemCount(): Int = fragments.size

    override fun createFragment(position: Int): Fragment = fragments[position]

}

Деякі інші корисні ресурси:


Як ми можемо використовувати цей тип реалізації з ViewBinding?
Maulik Dodia

@MaulikDodia нічого особливого не потрібно використовувати, як зазвичай, перегляньте документи: developer.android.com/topic/libraries/view-binding
user158

Я буду посилатися на документ. Дякую!
Маулік Додія

4

Використання ViewPager2 в Android

Як згадувалося на сайті розробника

Зміни API

FragmentStateAdapter замінює FragmentStatePagerAdapter

RecyclerView.Adapter замінює PagerAdapter

registerOnPageChangeCallback замінює addPageChangeListener

Простими словами вони роблять так, щоб адаптер View Pager працював як адаптер Recycle View.

Примітка: - Нам не потрібно використовувати фрагмент у View Pager 2. Це повністю залежить від макета надуття RecyclerView.Adapter.

Ось зразок посилання на репозитарій gitHub

Приклад: -

MainActivity.class

public class MainActivity extends AppCompatActivity {
    
    private ViewPager2 mPager;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getSupportActionBar().setTitle("View Pager 2");
        mPager = findViewById(R.id.pager);
        mPager.setAdapter(new MyViewPagerAdapter(this));
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return super.onCreateOptionsMenu(menu);
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (R.id.change == item.getItemId()) {
            mPager.setOrientation(mPager.getOrientation() != ViewPager2.ORIENTATION_VERTICAL ? ViewPager2.ORIENTATION_VERTICAL : ViewPager2.ORIENTATION_HORIZONTAL);
        }
        return super.onOptionsItemSelected(item);
    }
}

Activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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=".MainActivity">

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

</android.support.constraint.ConstraintLayout>

MyViewPagerAdapter.class

public class MyViewPagerAdapter extends RecyclerView.Adapter<MyHolder> {
    
    private Context context;
    
    public MyViewPagerAdapter(Context context) {
        this.context=context;
    }
    
    @NonNull
    @Override
    public MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new MyHolder(LayoutInflater.from(context).inflate(R.layout.cell_item, parent, false));
    }
    
    @Override
    public void onBindViewHolder(@NonNull MyHolder holder, int position) {
      holder.mText.setText("Page "+(position+1));
    }
    
    @Override
    public int getItemCount() {
        return 10;
    }
}

cell_item.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="Page 1"
        android:textSize="20sp" />

</android.support.constraint.ConstraintLayout>

MyHolder.class

class MyHolder extends RecyclerView.ViewHolder {
    
    public TextView mText;
    
    public MyHolder(@NonNull View itemView) {
        super(itemView);
        mText = itemView.findViewById(R.id.text);
    }
}

вихід:

введіть тут опис зображення


Чи не можемо ми використовувати ViewPager2 з фрагментами?
ysfcyln

@ysfcyln так, ви можете використовувати Fragmentз, ViewPager2будь ласка, перевірте мою відповідь вище, я додав зразок коду для How use Fragment with ViewPager2
AskNilesh

Дякую, але сховище видалено.
CoolMind

@CoolMind Яке сховище видаляється?
sushildlh

github.com/sushildlh/ViewPager2 . Дивіться також medium.com/swlh/android-viewpager2-tablayout-3099aae2f396 для отримання нової інформації. :)
CoolMind

3

Ось що я зробив для реалізації ViewPager2 з TabLayout з 3 Fragment full Examble:

Макет містить ViewPager2з TabLayout:

 <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:orientation="vertical"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/include3">

        <com.google.android.material.tabs.TabLayout
            android:id="@+id/tab_layout"
            android:layout_width="match_parent"
            android:background="@color/colorPrimary"
            app:tabTextColor="@color/tab_dismiss_color"
            app:tabSelectedTextColor="@color/green"
            android:layout_height="wrap_content" />

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:layout_gravity="bottom"
            android:background="#e4e4e4" />

        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/pager"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1" />
    </LinearLayout>

init ViewPager2 та встановіть ім'я Tabs:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_report);
        ButterKnife.bind(this);
        actionBarTitleId.setText(R.string.reports);

        viewPager.setAdapter(new ViewPagerAdapter(this));

        new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
            switch (position) {
                case 0:
                    tab.setText(R.string.financial_duty_str);
                    break;
                case 1:
                    tab.setText(R.string.financial_unpaid_str);
                    break;
                case 2:
                    tab.setText(R.string.financial_paid_str);
                    break;

            }
        }).attach();

    }

ViewPager2 адаптер:

public class ViewPagerAdapter extends FragmentStateAdapter {


    public ViewPagerAdapter(@NonNull FragmentActivity fragmentActivity) {
        super(fragmentActivity);
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        switch (position) {
            case 0:
                return new FinancialFragment();
            case 1:
                return new FinancialUnPaidFragment();
            case 2:
                return new FinancialPaidFragment();
            default:
                return null;

        }
    }

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

залежність, що використовується:

implementation "androidx.viewpager2:viewpager2:1.0.0"
implementation 'com.google.android.material:material:1.1.0-alpha10'

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зі своїми користувацькими фрагментами.

І це робота !!!

Приємно.

PS Ще одна реалізація:

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, і це занадто повільно, як свиня, що біжить з конями.
Gilberto Ibarra

3
Це НЕ правильно. createFragmentзворотний виклик FragmentStateAdapterслід (як говорить метод) createa Fragment. І не дайте тієї, яка вже створена і валяється. Використовуючи свій підхід, ви заплутуєтесь з FragmentManager'sоперацією.
Bartek Lipinski,

@BartekLipinski. Отже, як я "можу динамічно змінювати колекцію фрагментів під час виконання, і ViewPager2 правильно відображатиме модифіковану колекцію." як сказано в документації ?
Рамарал,

0

Як це використовувати, дуже чітко пояснено. Дозвольте мені дати невеликі, але дуже важливі поради та подробиці щодо ViewPager2, особливо якщо це всередині фрагмента про те, як запобігти витоку пам'яті

  1. Не використовуйте конструктор, який бере фрагмент, особливо якщо ви використовуєте TabLayout.

    public FragmentStateAdapter(@NonNull Fragment fragment) {
        this(fragment.getChildFragmentManager(), fragment.getLifecycle());
    }
    

оскільки існує ризик витоку пам’яті, як описано тут

замість цього використовуйте один, який бере FragmentManager та LifeCycle. І не надсилайте lifeCycleфрагмент як аргумент, використовуйте viewLifeCycleOwnerжиттєвий цикл ', оскільки viewLifeCycleOwner представляє життєвий цикл фрагмента view.

 class NavigableFragmentStateAdapter(
    fragmentManager: FragmentManager,
    lifecycle: Lifecycle
) : FragmentStateAdapter(fragmentManager, lifecycle) {


}

і встановити адаптер з в onCreateView

viewPager.adapter =
            NavigableFragmentStateAdapter(childFragmentManager, viewLifecycleOwner.lifecycle)
  1. Якщо ви використовуєте, TabLayoutколи ViewPager2 знаходиться всередині фрагмента, не забудьте від'єднати TabLayout та встановити адаптер ViewPager2 як

від'єднайте TabLayoutMediator, оскільки він спричиняє витік пам'яті, коли він знаходиться у фрагменті

/programming/61779776/leak-canary-detects-memory-leaks-for-tablayout-with-viewpager2

ViewPager2 всередині фрагмента витікає після заміни фрагмента, в якому він знаходиться, за допомогою навігаційного компонента навігації

TabLayoutMediator(tabLayout, viewPager2, tabConfigurationStrategy).detach()     
viewPager2.adapter = null

внутрішній onDestroyViewметод Fragment

  1. Якщо ви хочете використовувати сторінки ViewPager як navHostFragmentіз навігаційними компонентами, щоб повернутися до дочірніх фрагментів, зареєструйте FragmentTransactionCallback в FragmentStateAdapterяк

    private val fragmentTransactionCallback =
        object : FragmentStateAdapter.FragmentTransactionCallback() {
            override fun onFragmentMaxLifecyclePreUpdated(
                fragment: Fragment,
                maxLifecycleState: Lifecycle.State
            ) = if (maxLifecycleState == Lifecycle.State.RESUMED) {
    
                // This fragment is becoming the active Fragment - set it to
                // the primary navigation fragment in the OnPostEventListener
                OnPostEventListener {
                    fragment.parentFragmentManager.commitNow {
                        setPrimaryNavigationFragment(fragment)
                    }
                }
            } else {
                super.onFragmentMaxLifecyclePreUpdated(fragment, maxLifecycleState)
            }
        }
    
    init {
        // Add a FragmentTransactionCallback to handle changing
        // the primary navigation fragment
        registerFragmentTransactionCallback(fragmentTransactionCallback)
    }
    

Крім того, якщо ви хочете побачити деякі зразки використання ViewPager2 з навігаційними компонентами, модулями динамічних функцій та поєднанням з BottomNavigationView, ви можете ознайомитись з підручниками в цьому репозиторії github.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.