ViewPage2使用及坑点解决

ViewPage2使用及坑点解决,第1张

一.ViewPage2添加新特性:

      *  从右到左的布局支持

      *  垂直方向

      *  RecyclerView.Adapter取代PagerAdapter

      *  registerOnPageChangeCallback 取代 addPageChangeListener

      *  更高效的notifyDataSetChanged

二.以下案例是使用RecyclerView结合ViewPage2实现上下滑动

1.依赖导入

    //ViewPage2

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

    //recyclerview

    implementation 'androidx.recyclerview:recyclerview:1.0.0-beta01'

2.Activity和Adapter布局设置

  1>.Activity布局

      <?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=".MainActivity">

          <androidx.viewpager2.widget.ViewPager2

            android:id="@+id/viewpager2"

            android:layout_width="match_parent"

            android:layout_height="match_parent"/>

        </androidx.constraintlayout.widget.ConstraintLayout>

  2>.recycleview_item.xml适配器布局

      <?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:id="@+id/container"

        android:layout_width="match_parent"

        android:layout_height="match_parent">

        //原生控件

        <androidx.appcompat.widget.AppCompatTextView

          android:id="@+id/tvTitle"

          android:layout_width="wrap_content"

          android:layout_height="wrap_content"

          android:layout_centerInParent="true"

          android:textColor="@android:color/white"

          android:textSize="32sp"

          tools:text="item" />

      </RelativeLayout>

3.ViewPage2的适配器

    package com.wd.viewpage2demo

    import android.content.Context

    import androidx.annotation.NonNull

    import androidx.recyclerview.widget.RecyclerView

    import android.view.LayoutInflater

    import android.view.View

    import android.view.ViewGroup

    import android.widget.RelativeLayout

    import android.widget.TextView

    import java.util.List

    import androidx.viewpager2.widget.ViewPager2

  /**

  * Author : 张自力

  * Created on time.

  *

  * ViewPage2的适配器

  *

  */

  public class ViewPagerAdapter extends RecyclerView.Adapter<ViewPagerAdapter.ViewHolder>{

    private List<String>mData

    private LayoutInflater mInflater

    private ViewPager2 viewPager2

    //定义一个色彩背景数组

    private int[] colorArray = new int[]{android.R.color.black, android.R.color.holo_blue_dark,

                                          android.R.color.holo_green_dark, android.R.color.holo_red_dark}

    public ViewPagerAdapter(Context context, List<String>data, ViewPager2 viewPager2) {

        this.mInflater = LayoutInflater.from(context)

        this.mData = data

        this.viewPager2 = viewPager2

    }

    @NonNull

    @Override

    public ViewPagerAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        View view = mInflater.inflate(R.layout.recycleview_item, parent, false)

        return new ViewHolder(view)

    }

    @Override

    public void onBindViewHolder(@NonNull ViewPagerAdapter.ViewHolder holder, int position) {

        String animal = mData.get(position)

        holder.myTextView.setText(animal)

        holder.relativeLayout.setBackgroundResource(colorArray[position])

    }

    @Override

    public int getItemCount() {

        return mData.size()

    }

    public static class ViewHolder extends RecyclerView.ViewHolder {

        TextView myTextView

        RelativeLayout relativeLayout

        ViewHolder(View itemView) {

            super(itemView)

            myTextView = itemView.findViewById(R.id.tvTitle)

            relativeLayout = itemView.findViewById(R.id.container)

          }

      }

    }

4.Activity界面编写

    package com.wd.viewpage2demo

    import android.os.Bundle

    import androidx.appcompat.app.AppCompatActivity

    import java.util.ArrayList

    import java.util.List

    import androidx.viewpager2.widget.ViewPager2

    public class MainActivity extends AppCompatActivity {

    private ViewPager2 viewpager2

    private List<String>list

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_main)

        //初始化控件

        initView()

        //初始化数据

        initDatas()

        //ViewPage2设置

        setViewPage2S()

    }

    /**

    * ViewPage2设置

    *

    * */

    private void setViewPage2S() {

        /**

        * 垂直方向属性

        * 默认是水平方向ORIENTATION_HORIZONTAL,垂直是ORIENTATION_VERTICAL

        *

        * */

        //设置方向

        viewpager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL)

        //设置adapter

        viewpager2.setAdapter(new ViewPagerAdapter(this, list, viewpager2))

        viewpager2.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)

            }

            @Override

            public void onPageScrollStateChanged(int state) {

                super.onPageScrollStateChanged(state)

            }

        })

    }

    /**

    * 初始化数据

    *

    * */

    private void initDatas() {

        list = new ArrayList<>()

        list.add("页面一")

        list.add("页面二")

        list.add("页面三")

        list.add("页面四")

    }

    /**

    * 初始化控件

    *

    * */

    private void initView() {

        //初始化ViewPage2

        viewpager2 = (ViewPager2) findViewById(R.id.viewpager2)

    }

}

三.RecyclerView和ViewPage2结合使用出现的坑点及解决方案:

  1.将build tools更新到3.2.0,gradle更新到4.6,依赖库统一更新到28.0.0,这一步非常重要,否则会导致第二步不能完全转换成功(如果已经更新过了,可以忽略这一步)

  2.选择工程右键→Refactor→Migrate to Androidx:

  https://img-blog.csdnimg.cn/20190311164212477.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mjc5NzA0OA==,size_16,color_FFFFFF,t_70

  3.选中所有需要重命名的目录,执行Do Refactor:

  https://img-blog.csdnimg.cn/2019031116422580.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mjc5NzA0OA==,size_16,color_FFFFFF,t_70

最近一个项目要实现可以无限循环的PageView,主要思路是在初始化pageview的list的时候在开始和结尾多加一个结尾和开头的widget,当滑动到开头和结尾的时候手动进行页面的切换,详细可以搜索pageview无限轮播。

这种方法有一个要点就是要维护两个索引,一个是内部list的索引,一个是外部显示的索引,由于list的容量是比显示的数量多2的,所以如果要在外部进行一些比如指示器或者计时器功能要进行和页面同步显示或者切换页面 *** 作时,需要将显示的索引转换成list的索引。

不过网上说的都是一些比较简单的实现,看到比较多的就是当滑动到要手动切换的时候进行一个时延,这样可以避免直接切换页面造成的卡顿和跳动现象。但是存在一个问题,如果要同时实现一个跟随页面切换的指示器,就会出现当页面切换过去之后指示器才会跟着过去,因为页面切换的时候执行了时延,而时延之后才会真正改变索引,此时才会setstate,之后指示器才能响应到索引的切换,但是如果在时延之前就切换的话又会出现指示器先行的情况。因此这种方法其实是存在一些问题的。

所以解决这个问题的关键在于如何进行页面切换的判断。这里可以有两种思路实现,第一种是实现viewpage的onpagechanged方法,在里面进行逻辑的判断,然后用controller来进行页面跳转,不过这种方法存在当controller跳转的时候又会回调onpagechanged,所以就会出现多次对索引不必要 *** 作,而且如果有比如计时器等额外的功能的话可能不方便将页面逻辑分开,而且依旧无法解决指示器延迟问题,同时也很难进行细粒度的 *** 作。

第二种方法我们就要去看pageview的源码了,从源码的角度来解决问题才是正确的方法。首先我们点进去pageview的源码

看到这里其实已经有一些思路了,我们之前难点在于重写了onpagechanged方法导致问题无法很好的解决,现在我们找到了onpagechanged调用的地方,只要找办法避免掉就可以实现了。

当然这里我们要说到NotificationListener,以及flutter对应的冒泡事件传输机制,这里大家可以去看看这篇 文章 。

我来总结一下,其实就是flutter对于notification这个组件,有一中事件规则叫冒泡传递,底层的notification如果在它的 onNotification写的逻辑中返回是false以及它不是根结点,就会去向上遍历寻找它的祖先notification组件,知道遇到root节点或者某一个返回true,则事件传递结束。

而且在onNotification中可以对多种事件进行监听和处理,所以我们可以把对viewpage页面跳转对索引处理的逻辑写在这里,而且我们可以分别处理比如滑动开始的start事件和结束的end事件,分别进行细粒度的逻辑的处理,这样就可以在外部进行 *** 作和别的功能实现了。

因此不仅无限轮播事件可以通过这种方法来解决,如果有其他的 *** 作也可以这样进行处理,而且因为我们没有传入onpagechanged方法,所以不存在多次调用的问题,pageview那里判断onpagechanged是null方法就不会进去了,会直接我们写在pageview外面的notification的逻辑。

最后的结构大概这样

 基本上现在所有的应用都会有一个欢迎界面,在欢迎界面对应用做一个整体的介绍,然后在跳入到主界面,这次要说的这个引导页就是带翻页的引导页。效果如下所示

概要实现

主要分为两部分功能,一个是翻页效果,一个是页面位置指示器。为了实现翻页效果我采用系统自带的ViewPager对象来实现;页面指示器则通过一个LinearLayout在其中放置相应个数的图片,然后根据页面的滑动动态修改各个图片的资源。布局文件如下所示

复制代码

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

2 xmlns:tools="http://schemas.android.com/tools"

3 android:layout_width="match_parent"

4 android:layout_height="match_parent"

5 tools:context=".MainActivity" >

6

7 <android.support.v4.view.ViewPager

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

9 android:id="@+id/welcome_pager"

10 android:layout_width="match_parent"

11 android:layout_height="match_parent" />

12

13 <!-- 图片位置指示器 -->

14 <LinearLayout

15 android:id="@+id/director"

16 android:layout_width="match_parent"

17 android:layout_height="wrap_content"

18 android:gravity="center_horizontal"

19 android:orientation="horizontal"

20 android:layout_marginBottom="15dip"

21 android:layout_alignParentBottom="true"

22 >

23

24 <ImageView

25 android:layout_width="wrap_content"

26 android:layout_height="wrap_content"

27 android:background="@drawable/pageindicator_on" />

28

29 <ImageView

30 android:layout_width="wrap_content"

31 android:layout_height="wrap_content"

32 android:background="@drawable/pageindicator_off" />

33

34 <ImageView

35 android:layout_width="wrap_content"

36 android:layout_height="wrap_content"

37 android:background="@drawable/pageindicator_off" />

38

39 <ImageView

40 android:layout_width="wrap_content"

41 android:layout_height="wrap_content"

42 android:background="@drawable/pageindicator_off" />

43 </LinearLayout>

44

45 </RelativeLayout>

复制代码

ViewPager

先来看下官方解释:Layout manager that allows the user to flip left and right through pages of data.意思是说,Viewpage是一个允许用户在多个页面数据之间通过左滑或者右滑的方式切换页面数据的布局管理器。

主要功能点有两部分,数据适配器Adapter,和事件监听器OnPageChangeListener。数据适配器用来管理这个ViewPager对象的显示内容,而OnPageChangeListener用来处理当页面切换的时候的行为动作,我修改页面指示器就是通过这个事件来完成的。

适配器

复制代码

1 class pagerAdapter extends FragmentPagerAdapter{

2

3 public pagerAdapter(FragmentManager fm) {

4 super(fm)

5 }

6

7 @Override

8 public Fragment getItem(int arg0) {

9 //得到要显示的对象并初始化图片

10 WelcomeFragment fm = new WelcomeFragment()

11 fm.setImg(imgs.get(arg0))

12

13 return fm

14 }

15

16 @Override

17 public int getCount() {

18 return imgs.size()

19 }

20

21 }

复制代码

上面这段就是ViewPager要用的适配器了,其中imgs是一个id数组,存放了要在欢迎界面展示的图片的id,WelcomeFragment是一个Fragment类,用来展示页面内容,这两个代码会在完整代码中体现。两个方法需要实现,getCout,用来表示有多少个页面;getItem,用来获取指定位置的Pager对象。

imgs数组定义及实现:

复制代码

1 List<Integer>imgs = null

2 //初始化欢迎界面图片数组

3 imgs = new ArrayList<Integer>()

4 imgs.add(R.drawable.help1)

5 imgs.add(R.drawable.help2)

6 imgs.add(R.drawable.help3)

7 imgs.add(R.drawable.help4)

复制代码

WelcomeFragment类定义

复制代码

1 public class WelcomeFragment extends Fragment {

2

3 View view = null

4 int imgId

5 @Override

6 public View onCreateView(LayoutInflater inflater, ViewGroup container,

7 Bundle savedInstanceState) {

8 view = inflater.inflate(R.layout.welcome_fragment, null)

9

10 ImageView fragmentVw = (ImageView) view.findViewById(R.id.welcome_Img)

11 fragmentVw.setBackgroundResource(imgId)

12 return view

13 }

14

15 /**

16 * 为该Fragment设置显示图片

17 * */

18 public void setImg(int imgID){

19

20 imgId = imgID

21 }

22 }

复制代码

WelcomeFragment布局文件

复制代码

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

2 android:layout_width="match_parent"

3 android:layout_height="match_parent" >

4

5 <ImageView

6 android:id="@+id/welcome_Img"

7 android:contentDescription="welcome"

8 android:layout_width="match_parent"

9 android:layout_height="match_parent" />

10

11 </FrameLayout>

复制代码

事件监听器OnPageChangeListener

这个监听器用来监听页面切换事件,实现这个接口用来处理页面切换时,页面指示器跟着改变状态。实现代码如下

复制代码

1 /**

2 * 页面切换的事件监听器

3 * */

4 class pageChangeListener implements OnPageChangeListener{

5

6 /**

7 * 当某一个页面被选中的时候触发

8 * */

9 @Override

10 public void onPageSelected(int arg0) {

11 int count = directorLayout.getChildCount()

12 /**

13 * 指示器自对象顺序和页面显示顺序一样的设置为on,其余的设置为off

14 * */

15 for(int i=0i<counti++){

16 ImageView iv = (ImageView) directorLayout.getChildAt(i)

17 if(i == arg0){

18 iv.setBackgroundResource(R.drawable.pageindicator_on)

19 }else{

20 iv.setBackgroundResource(R.drawable.pageindicator_off)

21 }

22 }

23 }

24

25 @Override

26 public void onPageScrolled(int arg0, float arg1, int arg2) {

27 // TODO Auto-generated method stub

28 }

29

30 @Override

31 public void onPageScrollStateChanged(int arg0) {

32 // TODO Auto-generated method stub

33 }

34 }


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/bake/11445593.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-16
下一篇2023-05-16

发表评论

登录后才能评论

评论列表(0条)

    保存