2021-11-12 ViewPager 2

转https://blog.csdn.net/xiangshiweiyu_hd/article/details/104005810

1、ViewPager 与 ViewPager2 部分对比

ViewPager                                                               ViewPager 2

PagerAdapter                                                          RecyclerView.Adapter

FragmentStatePagerAdapter                                  FragmentStateAdapter

addPageChangeListener                                        registerOnPageChangeCallback

无                                                                             从右到左 (RTL) 的布局支持

无                                                                             垂直方向支持

无                                                                             停用用户输入的功能                                 

                                                                      (setUserInputEnabled、isUserInputEnabled)


依赖引入

implementation 'androidx.viewpager2:viewpager2:1.0.0'

implementation 'androidx.recyclerview:recyclerview:1.1.0' // ViewPager 2 需要使用 RecycleView 的 adapter

Activity 布局内 就一个 ViewPager 2控件

item 界面就一个textView

就不展示了


package com.example.viewpager2.horizontal;

import android.annotation.SuppressLint;

import android.content.Context;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.LinearLayout;

import android.widget.TextView;

import androidx.annotation.NonNull;

import androidx.recyclerview.widget.RecyclerView;

import com.example.viewpager2.R;

import java.util.ArrayList;

import java.util.List;

/**

* CreateTime: 2020/1/15 15:06

* Author: hxd

* Content:

* UpdateTime:

* UpdateName;

* UpdateContent:

*/

public class HorizontalVpAdapter extends RecyclerView.Adapter<HorizontalVpAdapter.HorizontalVpViewHolder> {

    private List<Integer> backgrounds;

    private Context mContext;

    HorizontalVpAdapter(Context context) {

        mContext = context;

        if (backgrounds == null) {

            backgrounds = new ArrayList<>();

            backgrounds.add(android.R.color.holo_blue_bright);

            backgrounds.add(android.R.color.holo_red_dark);

            backgrounds.add(android.R.color.holo_green_dark);

            backgrounds.add(android.R.color.holo_orange_light);

            backgrounds.add(android.R.color.holo_purple);

        }

    }

    @NonNull

    @Override

    public HorizontalVpViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        return new HorizontalVpViewHolder(LayoutInflater.from(mContext).inflate((R.layout.item_h_v), parent, false));

    }

    @SuppressLint("SetTextI18n")

    @Override

    public void onBindViewHolder(@NonNull HorizontalVpViewHolder holder, int position) {

        holder.mTextView.setText("第  " + (position + 1) + " 界面");

        holder.mLinearLayout.setBackgroundResource(backgrounds.get(position));

    }

    @Override

    public int getItemCount() {

        if (backgrounds == null) {

            return 0;

        }

        return backgrounds.size();

    }

    class HorizontalVpViewHolder extends RecyclerView.ViewHolder {

        LinearLayout mLinearLayout;

        TextView mTextView;

        HorizontalVpViewHolder(@NonNull View itemView) {

            super(itemView);

            mLinearLayout = itemView.findViewById(R.id.ll_h_v);

            mTextView = itemView.findViewById(R.id.tv_hv);

        }

    }

}

适配器逻辑如上,因为 ViewPager 2 底层使用 RecycleView 实现的,所以这里不再使用 PagerAdapter 而是使用了 RecyclerView.Adapter 这也是 引入RecycleView 依赖的原因所在。


public class HorizontalActivity extends AppCompatActivity {

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_horizontal);

        ViewPager2 viewPager2 = findViewById(R.id.vp_h);

        HorizontalVpAdapter adapter = new HorizontalVpAdapter(this);

        viewPager2.setAdapter(adapter);

    }

}


Activity 内的代码就没什么不同了和之前一样的两步走,初始化控件,设置适配器。

3、纵向滑动效果

1)、实现效果

2)、代码逻辑

a、 布局

Activity 的布局需要拿出

    <androidx.viewpager2.widget.ViewPager2

        android:id="@+id/vp_v"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:orientation="vertical" />

1

2

3

4

5

布局内的 android:orientation="vertical" 控制横向和纵向滑动 有点类似于 LinearLayout

b、 逻辑

public class VerticalActivity extends AppCompatActivity {

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_vertical);

        ViewPager2 viewPager2 = findViewById(R.id.vp_v);

        VerticalVpAdapter adapter = new VerticalVpAdapter(this);

        viewPager2.setAdapter(adapter);

        viewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

Activity 内的viewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);可以实现 xml 内的android:orientation="vertical"相同效果。

4、RadioGroup 与 ViewPager 2 连用

1)、实现效果

2)、代码逻辑

a、 布局

Activity 布局

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout 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=".withRadioGroup.RgActivity">

    <androidx.viewpager2.widget.ViewPager2

        android:id="@+id/vp_rg"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:layout_above="@+id/rg_vp" />

    <RadioGroup

        android:id="@+id/rg_vp"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_alignParentBottom="true"

        android:layout_gravity="bottom"

        android:orientation="horizontal">

        <RadioButton

            android:id="@+id/rb_home"

            android:layout_width="0dp"

            android:layout_height="wrap_content"

            android:layout_weight="1"

            android:button="@null"

            android:checked="true"

            android:drawableTop="@drawable/selector_home"

            android:drawablePadding="5dp"

            android:gravity="center"

            android:paddingTop="5dp"

            android:paddingBottom="5dp"

            android:text="@string/home"

            android:textColor="@color/selector_rg"

            android:textSize="16sp" />

        <RadioButton

            android:id="@+id/rb_msg"

            android:layout_width="0dp"

            android:layout_height="wrap_content"

            android:layout_weight="1"

            android:button="@null"

            android:drawableTop="@drawable/selector_msg"

            android:drawablePadding="5dp"

            android:gravity="center"

            android:paddingTop="5dp"

            android:paddingBottom="5dp"

            android:text="@string/msg"

            android:textColor="@color/selector_rg"

            android:textSize="16sp" />

        <RadioButton

            android:id="@+id/rg_my"

            android:layout_width="0dp"

            android:layout_height="wrap_content"

            android:layout_weight="1"

            android:button="@null"

            android:drawableTop="@drawable/selector_my"

            android:drawablePadding="5dp"

            android:gravity="center"

            android:paddingTop="5dp"

            android:paddingBottom="5dp"

            android:text="@string/my"

            android:textColor="@color/selector_rg"

            android:textSize="16sp" />

    </RadioGroup>

</RelativeLayout>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

这里没啥说的就类似于各位 HomeActivity 的实现方式了。

每个 Fragment 内的布局更加简洁这里不再陈述

b、 逻辑

Adapter 内逻辑

package com.example.viewpager2.withRadioGroup;

import androidx.annotation.NonNull;

import androidx.fragment.app.Fragment;

import androidx.fragment.app.FragmentActivity;

import androidx.viewpager2.adapter.FragmentStateAdapter;

import java.util.ArrayList;

import java.util.List;

/**

* CreateTime: 2020/1/15 16:32

* Author: hxd

* Content:

* UpdateTime:

* UpdateName;

* UpdateContent:

*/

public class RgAdapter extends FragmentStateAdapter {

    private List<Class> fragments;

    public RgAdapter(@NonNull FragmentActivity fragmentActivity) {

        super(fragmentActivity);

        if (fragments == null) {

            fragments = new ArrayList<>();

        }

    }

    public void addFragment(Fragment fragment) {

        if (fragments != null) {

            fragments.add(fragment.getClass());

        }

    }

    @NonNull

    @Override

    public Fragment createFragment(int position) {

        try {

            return (Fragment) fragments.get(position).newInstance();

        } catch (IllegalAccessException e) {

            e.printStackTrace();

        } catch (InstantiationException e) {

            e.printStackTrace();

        }

        return null;

    }

    @Override

    public int getItemCount() {

        return fragments.size();

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

Activity 内代码

package com.example.viewpager2.withRadioGroup;

import androidx.appcompat.app.AppCompatActivity;

import androidx.viewpager2.widget.ViewPager2;

import android.os.Bundle;

import android.widget.RadioButton;

import android.widget.RadioGroup;

import com.example.viewpager2.R;

public class RgActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener {

    private ViewPager2 vpRg;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_rg);

        RgAdapter adapter = new RgAdapter(this);

        RadioGroup rgVp = findViewById(R.id.rg_vp);

        vpRg = findViewById(R.id.vp_rg);

        rgVp.setOnCheckedChangeListener(this);

        vpRg.setAdapter(adapter);

        adapter.addFragment(new HomeFragment());

        adapter.addFragment(new MessageFragment());

        adapter.addFragment(new MyFragment());

        vpRg.setCurrentItem(0);

        vpRg.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {

            @Override

            public void onPageSelected(int position) {

                super.onPageSelected(position);

                switch (position) {

                    case 0:

                        ((RadioButton) findViewById(R.id.rb_home)).setChecked(true);

                        break;

                    case 1:

                        ((RadioButton) findViewById(R.id.rb_msg)).setChecked(true);

                        break;

                    case 2:

                        ((RadioButton) findViewById(R.id.rg_my)).setChecked(true);

                        break;

                }

            }

        });

    }

    @Override

    public void onCheckedChanged(RadioGroup group, int checkedId) {

        switch (checkedId) {

            case R.id.rb_home:

                vpRg.setCurrentItem(0);

                break;

            case R.id.rb_msg:

                vpRg.setCurrentItem(1);

                break;

            case R.id.rg_my:

                vpRg.setCurrentItem(2);

                break;

        }

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

这里需要说的是 registerOnPageChangeCallback 方法 ,这个方法可以可以监听到 ViewPager 2 的界面变化,进而去操作其他的控件。

4、TabLayout 与 ViewPager 2 连用

1)、实现效果

2)、代码逻辑

a、 布局

Activity 布局

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:app="http://schemas.android.com/apk/res-auto"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:orientation="vertical">

    <com.google.android.material.tabs.TabLayout

        android:id="@+id/tb_vp"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        app:tabIndicatorFullWidth="false"

        app:tabMode="scrollable"

        app:tabIndicatorColor="#0371DD"

        app:tabRippleColor="@android:color/transparent"

        app:tabSelectedTextColor="#0371DD"

        app:tabTextColor="#111111" />

    <androidx.viewpager2.widget.ViewPager2

        android:id="@+id/vp_tb"

        android:layout_width="match_parent"

        android:layout_height="match_parent" />

</LinearLayout>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

Fragment 内布局很简单,不再列举了。

b、 逻辑

adapt 内部代码

package com.example.viewpager2.withTab;

import androidx.annotation.NonNull;

import androidx.fragment.app.Fragment;

import androidx.fragment.app.FragmentActivity;

import androidx.viewpager2.adapter.FragmentStateAdapter;

import java.util.ArrayList;

import java.util.List;

/**

* CreateTime: 2020/1/15 17:47

* Author: hxd

* Content:

* UpdateTime:

* UpdateName;

* UpdateContent:

*/

public class TabAdapter extends FragmentStateAdapter {

    private List<Integer> colors;

    TabAdapter(@NonNull FragmentActivity fragmentActivity) {

        super(fragmentActivity);

        if (colors == null) {

            colors = new ArrayList<>();

        }

    }

    void addColor(int color) {

        if (colors != null) {

            colors.add(color);

        }

    }

    @NonNull

    @Override

    public Fragment createFragment(int position) {

        return ShowFragment.newInstance(colors, position);

    }

    @Override

    public int getItemCount() {

        return colors.size();

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

这里提出一点,笔者 在 RadioGroup 、TabLayout 分别于ViewPager 2 的连用过程中分别使用了两种方法 将 Fragment 传给 adapter 这样的操作可以让各位的 Leaks 分析工具报出 内存泄漏。

Fragment 内的代码

package com.example.viewpager2.withTab;

import android.annotation.SuppressLint;

import android.os.Bundle;

import androidx.annotation.NonNull;

import androidx.annotation.Nullable;

import androidx.fragment.app.Fragment;

import android.os.Parcelable;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.FrameLayout;

import android.widget.TextView;

import com.example.viewpager2.R;

import java.util.ArrayList;

import java.util.List;

public class ShowFragment extends Fragment {


    @Override

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        return inflater.inflate(R.layout.fragment_show, container, false);

    }


    static ShowFragment newInstance(List<Integer> colors, int item) {

        Bundle bundle = new Bundle();

        bundle.putSerializable("color", (ArrayList<Integer>) colors);

        bundle.putInt("item", item);

        ShowFragment fragment = new ShowFragment();

        fragment.setArguments(bundle);

        return fragment;

    }


    @SuppressLint("SetTextI18n")

    @Override

    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {

        view.<FrameLayout>findViewById(R.id.fl_show)

                .setBackgroundResource(((ArrayList<Integer>) getArguments()

                        .getSerializable("color")).get(getArguments().getInt("item")));

        view.<TextView>findViewById(R.id.tv_show).setText("第 " + (getArguments().getInt("item") + 1) + " 个页面");

        super.onViewCreated(view, savedInstanceState);

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

这里有一个静态方法 来接收 传入的数据。

这里 Activity 与 RadioGroup 与ViewPager 2 连用方式 很相似的没什么可说的,不再复述。

c、 google 官方 bug

仔细观察这个案例 ,你会发现在ViewPager 2滑动的时候 TabLayout 的下划线切换了,但是 TabLayout 的字体颜色没有随之改变,但是在点击T abLayout 的 tab 标签的时候,下面的下划线和 ViewPager 2 是联动效果是有的,目前百度里各个大佬是没有解决方案的,所以笔者把这个 bug 提交给了 google 官方就是下面这个样子

现在陡然觉得,学英语真有用。

四、源码

闲话不多说了把源码贴上

源码

————————————————

版权声明:本文为CSDN博主「码虫韩小呆」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/xiangshiweiyu_hd/article/details/104005810

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342