Android-0.ViewPager基础示例


点击下载源码

简介

ViewPager,视图翻页工具,提供了多页面切换的效果,也就是我们通过创建adapter给它填充多个view,左右滑动时,切换不同的view。Google官方是建议我们使用Fragment来填充ViewPager的,这样 可以更加方便的生成每个Page,以及管理每个Page的生命周期。

基本使用

1. xml引用

    <android.support.v4.view.ViewPager
        android:id="@+id/vp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

2. 创建适配器

public class MyPagerAdapter extends PagerAdapter {

    private Context mContext;
    private List<String> mData;

    public MyPagerAdapter(Context mContext, List<String> mData) {
        this.mContext = mContext;
        this.mData = mData;
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
        return view == object;
    }

    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
        View view = View.inflate(mContext, R.layout.item_base,null);
        TextView tv = (TextView) view.findViewById(R.id.tv);
        tv.setText(mData.get(position));
        container.addView(view);
        return view;
    }

    @Override
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        // super.destroyItem(container,position,object); 这一句要删除,否则报错
        container.removeView((View)object);
    }
}

3. 设置适配器

    private void setVp() {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            list.add("第" + i + "个View");
        }

        ViewPager vp = (ViewPager) findViewById(R.id.vp);
        vp.setAdapter(new MyPagerAdapter(this, list));
    }

运行效果:

PagerAdapter函数解释

中文翻译地址:http://www.cnblogs.com/tony-yang-flutter/p/3591825.html

0、 调用预说明

1.ViewPager不直接处理每一个View, 而是将各个View与一个key关联起来。这个key用来跟踪且唯一代表一个View

2.当PagerAdapter将要改变的时候它会调用startUpdate函数,接下来会调用一次或多次的instantiateItem或者destroyItem
最后在更新的后期会调用finishUpdate

3.当finishUpdate返回时 instantiateItem返回的对象应该已添加到ViewGroupdestroyItem返回的对象应该被ViewGroup删除。

4.isViewFromObject(View, Object)代表了当前的View是否与给定的Object(key)相关联。

每个滑动View都对应一个Key,而且这个Key值是用来唯一追踪这个View的,也就是说每个滑动View都与一个唯一的Key一一对应。

对于非常简单的PagerAdapter或许你可以选择用View本身作为键,在创建并且添加到ViewGroupinstantiateItem方法里返回该View本身即可。destroyItem将会将该View从viewgroup里面移除。isViewFromObject方法里面直接可以返回view == object

即将当前页面本身的View作为Key跟踪,上面的示例就是这样写的。

1、destroyItem(ViewGroup container, int position, Object object)

移除一个给定位置的View。适配器有责任从容器中删除这个View。这是为了确保在finishUpdate(viewGroup)返回时View已经被移除。

2、getCount()

返回了当前要滑动View的个数。

3、instantiateItem (ViewGroup container, int position)

创建指定位置的View。适配器有责任增加即将创建的View视图到这里给定的container中,这是为了确保在finishUpdate(viewGroup)返回时对象已添加到ViewGroup
返回值:返回一个代表新增View的Object(Key),这里没必要一定返回View本身,可以是任意值,只要可以与你增加的View一一对应即可,比如position变量也可以做为Key

1.把指定position的View添加到conatiner中。
2.返回值就是新增View对应的Key。

4、isViewFromObject (View view, Object object)

用来判断一个View与object(Key)是否有对应关系,这个object(Key)是instantiateItem(ViewGroup, int)函数的返回值。

添加标题栏

给Viewpager设置标题栏有以下几种方式:

1、PagerTabStrip、PagerTitleStrip

PagerTabStrip带有下划线,而PagerTitleStrip不带下划线。
官方介绍:
https://developer.android.com/reference/android/support/v4/view/PagerTabStrip
1.它经常作为ViewPager控件的一个子控件被添加在XML布局文件中。
2.将它的 android:layout_gravity 属性设置为topbottom来将它显示在ViewPager的顶部或底部。
3.它的标题由重写PagerAdapter的getPageTitle(int position)来获得。
简单示例:
在原来的ViewPager中增加子控件PagerTabStrip,这里把它设置在底部:

    <android.support.v4.view.ViewPager
        android:id="@+id/vp"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <android.support.v4.view.PagerTabStrip
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom">
        </android.support.v4.view.PagerTabStrip>

在MyPagerAdapter中增加设置标题:

public class MyPagerAdapter extends PagerAdapter {
	 private String[] mTitles = {"标题一","标题二","标题三"};
	 ......
	    public CharSequence getPageTitle(int position) {
        return mTitles[position];
    }
}

运行效果如下:

这两个实现的效果基本一样,但有两点不同:
1、PagerTabStrip在当前页面下,会有一个下划线条来提示当前页面的Tab是哪个。
2、PagerTabStrip的Tab是可以点击的,当用户点击某一个Tab时,当前页面就会跳转到这个页面,而PagerTitleStrip则没这个功能。
3、它们实现的效果并不好,不能指定一个页面一次显示一个,或者全部显示,所以不推荐使用。

2、TabLayout

TabLayout提供了一个水平布局用于展示tabs。一般与Viewpager结合使用实现页面和标签联动的效果,是时下APP中非常用的一个控件。
如果运行时遇到错误:Error inflating class android.support.design.widget.TabLayout,解决方案是在AndroidManifest.xml的增加属性:

 <activity android:name=".MainActivity"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar">
1.添加design依赖
implementation 'com.android.support:design:28.0.0'
2.xml或代码中添加tab

通过xml添加:

    <android.support.design.widget.TabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <android.support.design.widget.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Tab1"/>
        <android.support.design.widget.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Tab2"/>
        <android.support.design.widget.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Tab3"/>
    </android.support.design.widget.TabLayout>

或直接在代码中添加:

<android.support.design.widget.TabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
        // tablayout,Tab是TabLayout的内部类,且Tab的构造方法是包访问权限
        TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
        tabLayout.addTab(tabLayout.newTab().setText("Tab1"));
        tabLayout.addTab(tabLayout.newTab().setText("Tab2"));
        tabLayout.addTab(tabLayout.newTab().setText("Tab3"));

运行效果如下:

3.属性详解
<declare-styleable name="TabLayout">
    <!--指示器颜色-->
    <attr name="tabIndicatorColor" format="color"/>
    <!--指示器高度-->
    <attr name="tabIndicatorHeight" format="dimension"/>
    <!--tabs距TabLayout开始位置的偏移量,但app:tabMode="scrollable"才生效-->
    <attr name="tabContentStart" format="dimension"/>
    <!--仅是Tab背景,设置TabLayout背景用android:background-->
    <attr name="tabBackground" format="reference"/>
    <!--默认fixed,所有Tab只能在屏幕内显示,超出会被挤压;scrollable,tab数量多会超出屏幕,可滑动-->
    <attr name="tabMode">
        <enum name="scrollable" value="0"/>
        <enum name="fixed" value="1"/>
    </attr>
    <!--默认fill,tab填满TabLayout,但tabMode=“fixed”才生效;center,tabs位于TabLayout的中间-->
    <attr name="tabGravity">
        <enum name="fill" value="0"/>
        <enum name="center" value="1"/>
    </attr>
    <!--Tab的最小宽度-->
    <attr name="tabMinWidth" format="dimension"/>
    <!--Tab的最大宽度-->
    <attr name="tabMaxWidth" format="dimension"/>
    <!--Tab文本设置样式-->
    <attr name="tabTextAppearance" format="reference"/>
    <!--Tab未选中字体颜色-->
    <attr name="tabTextColor" format="color"/>
    <!--Tab选中字体颜色-->
    <attr name="tabSelectedTextColor" format="color"/>
    <!--Tab内填充相关-->
    <attr name="tabPaddingStart" format="dimension"/>
    <attr name="tabPaddingTop" format="dimension"/>
    <attr name="tabPaddingEnd" format="dimension"/>
    <attr name="tabPaddingBottom" format="dimension"/>
    <attr name="tabPadding" format="dimension"/>
</declare-styleable>
4.添加图片

通过Tab.setCustomView()设置自定义View

自定义view布局ltem_tab.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:gravity="center">
    <ImageView
        android:id="@+id/iv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_home"/>
    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="2dp"
        android:textSize="16sp"
        android:text="首页"
        android:textColor="@android:color/black"/>
</LinearLayout>

代码设置:
注意此处的setCustomView是生成view的,而Tab.setCustomView()是设置自定义View

// 生成自定义的View
 private View setCustomView(int drawableId, String tabText) {
        View view = View.inflate(this, R.layout.item_tab, null);
        ImageView iv = (ImageView) view.findViewById(R.id.iv);
        TextView tv = (TextView) view.findViewById(R.id.tv);
        iv.setImageResource(drawableId);
        tv.setText(tabText);
        return view;
    }
        // tab通过设置自定义view,实现图文混排
        TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
        tabLayout.addTab(tabLayout.newTab().setCustomView(setCustomView(R.drawable.ic_home,"首页")));
        tabLayout.addTab(tabLayout.newTab().setCustomView(setCustomView(R.drawable.ic_info,"资讯")));
        tabLayout.addTab(tabLayout.newTab().setCustomView(setCustomView(R.drawable.ic_live,"直播")));

运行效果如下:

5.与Viewpager联动
xml设置

第一种:TabLayout放置在Viewpager的上方,放在AppbarLayout中会有阴影效果。

<LinearLayout 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"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <include layout="@layout/layout_toolbar" />

    <android.support.design.widget.TabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </android.support.design.widget.TabLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/vp"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </android.support.v4.view.ViewPager>
</LinearLayout>

第二种:TabLayout直接放在Viewpager,无阴影

    <android.support.v4.view.ViewPager
        android:id="@+id/vp"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <android.support.design.widget.TabLayout
            android:id="@+id/tab_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
        </android.support.design.widget.TabLayout>
    </android.support.v4.view.ViewPager>
简单绑定
        ViewPager vp = (ViewPager) findViewById(R.id.vp);
        MyPagerAdapter myPagerAdapter = new MyPagerAdapter(this, list);
        vp.setAdapter(myPagerAdapter);

        // 绑定,要在viewpager设置完数据后,调用此方法,否则不显示 tabs文本
        tabLayout.setupWithViewPager(vp);

        // 为绑定viewpager后的TabLayout的tabs设置自定义view,一定要在setupWithViewPager之后调用
        tabLayout.getTabAt(0).setCustomView(setCustomView(R.drawable.ic_home, "首页"));
        tabLayout.getTabAt(1).setCustomView(setCustomView(R.drawable.ic_info, "资讯"));
        tabLayout.getTabAt(2).setCustomView(setCustomView(R.drawable.ic_live, "直播"));

特别注意,setCustomView一定要在setupWithViewPager之后调用。
运行效果:

使用Fragment绑定

为Viewpager创建适配器

public class SectionsPagerAdapter extends FragmentPagerAdapter {

    Context mContext;
    String[] tabs = {"首页","资讯","直播"};
    int[] imgs = {R.drawable.ic_home,R.drawable.ic_info,R.drawable.ic_live};

    public SectionsPagerAdapter(Context context, FragmentManager fm) {
        super(fm);
        mContext = context;
    }

    @Override
    public Fragment getItem(int position) {
        return PlaceholderFragment.newInstance(tabs[position]);
    }

    @Override
    public int getCount() {
        return tabs.length;
    }

    @Nullable
    @Override
    public CharSequence getPageTitle(int position) {
 //           return tabs[position];
//            return setImageSpan(tabs[position],imgs[position]);
        return null;
    }

    public View setCustomView(int position) {
        View view = View.inflate(mContext, R.layout.item_tab, null);
        ImageView iv = (ImageView) view.findViewById(R.id.iv);
        TextView tv = (TextView) view.findViewById(R.id.tv);
        iv.setImageResource(imgs[position]);
        tv.setText(tabs[position]);
        return view;
    }

    public static class PlaceholderFragment extends Fragment {
        private static final String ARG_SECTION = "section";

        public PlaceholderFragment() {
        }

        public static PlaceholderFragment newInstance(String section) {
            PlaceholderFragment fragment = new PlaceholderFragment();
            Bundle args = new Bundle();
            args.putString(ARG_SECTION, section);
            fragment.setArguments(args);
            return fragment;
        }

        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_main, container, false);
            TextView textView = (TextView) rootView.findViewById(R.id.section_label);
            textView.setText(getArguments().getString(ARG_SECTION));
            return rootView;
        }
    }
}

fragment_main.xml定义了每个view关联的fragment模板:

<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">

    <TextView
        android:id="@+id/section_label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</RelativeLayout>

FragmentPagerAdapter是系统的库。

代码设置 TabLayout和Viewpager绑定

        ViewPager vp = (ViewPager) findViewById(R.id.vp);
        SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(getApplicationContext(),getSupportFragmentManager());
        vp.setAdapter(sectionsPagerAdapter);

        // 绑定,要在viewpager设置完数据后,调用此方法,否则不显示 tabs文本
        tabLayout.setupWithViewPager(vp);

        // 为绑定viewpager后的TabLayout的tabs设置自定义view
        for (int i = 0; i < sectionsPagerAdapter.getCount(); i++) {
            tabLayout.getTabAt(i).setCustomView(sectionsPagerAdapter.setCustomView(i));
        }

运行效果如下:

翻页动画

ViewPager有个方法叫做:setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) 用于设置ViewPager切换时的动画效果,并且google官方还给出了两个示例(因为使用的是属性动画,所以不兼容3.0以下)。

1. DepthPageTransformer

public class DepthPageTransformer implements ViewPager.PageTransformer {
    private static final float MIN_SCALE = 0.75f;

    public void transformPage(View view, float position) {
        int pageWidth = view.getWidth();
        if (position < -1) { // [-Infinity,-1)
            // This page is way off-screen to the left.
            view.setAlpha(0);
        } else if (position <= 0) { // [-1,0]
            // Use the default slide transition when moving to the left page
            view.setAlpha(1);
            view.setTranslationX(0);
            view.setScaleX(1);
            view.setScaleY(1);
        } else if (position <= 1) { // (0,1]
            // Fade the page out.
            view.setAlpha(1 - position);
            // Counteract the default slide transition
            view.setTranslationX(pageWidth * -position);
            // Scale the page down (between MIN_SCALE and 1)
            float scaleFactor = MIN_SCALE
                    + (1 - MIN_SCALE) * (1 - Math.abs(position));
            view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);
        } else { // (1,+Infinity]
            // This page is way off-screen to the right.
            view.setAlpha(0);
        }
    }
}

调用:

vp.setPageTransformer(false,new DepthPageTransformer());

运行效果:

2. ZoomOutPageTransformer

public class ZoomOutPageTransformer implements ViewPager.PageTransformer {
    private static final float MIN_SCALE = 0.85f;
    private static final float MIN_ALPHA = 0.5f;
    @SuppressLint("NewApi")
    public void transformPage(View view, float position)
    {
        int pageWidth = view.getWidth();
        int pageHeight = view.getHeight();
        if (position < -1)
        { // [-Infinity,-1)
            // This page is way off-screen to the left.
            view.setAlpha(0);
        } else if (position <= 1) //a页滑动至b页 ; a页从 0.0 -1 ;b页从1 ~ 0.0
        { // [-1,1]
            // Modify the default slide transition to shrink the page as well
            float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
            float vertMargin = pageHeight * (1 - scaleFactor) / 2;
            float horzMargin = pageWidth * (1 - scaleFactor) / 2;
            if (position < 0)
            {
                view.setTranslationX(horzMargin - vertMargin / 2);
            } else
            {
                view.setTranslationX(-horzMargin + vertMargin / 2);
            }
            // Scale the page down (between MIN_SCALE and 1)
            view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);
            // Fade the page relative to its size.
            view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE)
                    / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
        } else
        { // (1,+Infinity]
            // This page is way off-screen to the right.
            view.setAlpha(0);
        }
    }
}

调用:

vp.setPageTransformer(false,new ZoomOutPageTransformer());

运行效果:

3.RotateDownPageTransformer

public class RotateDownPageTransformer implements ViewPager.PageTransformer {
    private static final float ROT_MAX = 20.0f;
    private float mRot;
    public void transformPage(View view, float position)
    {
        Log.e("TAG", view + " , " + position + "");
        if (position < -1)
        { // [-Infinity,-1)
            // This page is way off-screen to the left.
            view.setRotation(0);
        } else if (position <= 1) // a页滑动至b页 ; a页从 0.0 ~ -1 ;b页从1 ~ 0.0
        { // [-1,1]
            // Modify the default slide transition to shrink the page as well
            if (position < 0)
            {
                mRot = (ROT_MAX * position);
                view.setPivotX(view.getMeasuredWidth() * 0.5f);
                view.setPivotY(view.getMeasuredHeight());
                view.setRotation( mRot);
            } else
            {
                mRot = (ROT_MAX * position);
                view.setPivotX(view.getMeasuredWidth() * 0.5f);
                view.setPivotY(view.getMeasuredHeight());
                view.setRotation( mRot);
            }
            // Scale the page down (between MIN_SCALE and 1)
            // Fade the page relative to its size.
        } else
        { // (1,+Infinity]
            // This page is way off-screen to the right.
            view.setRotation( 0);
        }
    }
}

调用:

vp.setPageTransformer(false,new RotateDownPageTransformer());

运行效果:

### 4. 开源框架ViewPagerTransforms

里面有十几种翻页动画,Github地址:ViewPagerTransforms

翻页监听

        vp.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                Log.e("vp","滑动中=====position:"+ position + "   positionOffset:"+ positionOffset + "   positionOffsetPixels:"+positionOffsetPixels);
            }

            @Override
            public void onPageSelected(int position) {
                Log.e("vp","显示页改变=====postion:"+ position);
            }

            @Override
            public void onPageScrollStateChanged(int state) {
                switch (state) {
                    case ViewPager.SCROLL_STATE_IDLE:
                        Log.e("vp", "状态改变=====SCROLL_STATE_IDLE====静止状态");
                        break;
                    case ViewPager.SCROLL_STATE_DRAGGING:
                        Log.e("vp", "状态改变=====SCROLL_STATE_DRAGGING==滑动状态");
                        break;
                    case ViewPager.SCROLL_STATE_SETTLING:
                        Log.e("vp", "状态改变=====SCROLL_STATE_SETTLING==滑翔状态");
                        break;
                }
            }
        });

1、onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
页面滑动状态停止前一直调用。
position:当前点击滑动页面的位置 。
positionOffset:当前页面偏移的百分比 。
positionOffsetPixels:当前页面偏移的像素位置。

2、onPageSelected(int position)
滑动后显示的页面和滑动前不同,调用。
position:选中显示页面的位置。

3、onPageScrollStateChanged(int state)

state:当前页面的状态,可取以下值:
SCROLL_STATE_IDLE:空闲状态 。
SCROLL_STATE_DRAGGING:滑动状态 。
SCROLL_STATE_SETTLING:滑动后滑翔的状态。

与Fragment结合使用

与Fragment结合使用其实也一样,只是用Fragment代替原先的View,填充Viewpager;然后就是Adapter不一样,配合Fragment使用的有两个Adapter:FragmentPagerAdapterFragmentStatePagerAdapter。

相同点: 都继承自PagerAdapter
不同点: 卸载不再需fragment时,各自采用的处理方法有所不同。
FragmentStatePagerAdapter会销毁不需要的fragment。事务提交后, activity的FragmentManager中的fragment会被彻底移除。 FragmentStatePagerAdapter类名中的“state”表明:在销毁fragment时,可在onSaveInstanceState(Bundle)方法中保存fragmentBundle信息。用户切换回来时,保存的实例状态可用来恢复生成新的fragment

FragmentPagerAdapter有不同的做法。对于不再需要的fragmentFragmentPagerAdapter会选择调用事务的detach(Fragment)方法来处理它,而非remove(Fragment)方法。也就是说, FragmentPagerAdapter只是销毁了fragment的视图, fragment实例还保留在FragmentManager中。因此,FragmentPagerAdapter创建的fragment永远不会被销毁。

也就是:在destroyItem()方法中,FragmentStatePagerAdapter调用的是remove()方法,适用于页面较多的情况;FragmentPagerAdapter调用的是detach()方法,适用于页面较少的情况。但是有页面数据需要刷新的情况,不管是页面少还是多,还是要用FragmentStatePagerAdapter,否则页面会因为没有重建得不到刷新。

简单示例

使用如下:
建一个fragment,fragment_pager.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">

    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:textSize="18sp"
        android:text="Hello blank fragment"/>

</FrameLayout>

创建PagerFragment类:

public class PagerFragment extends Fragment {
    String mContent;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        mContent = (String)getArguments().get("content");
        View view = inflater.inflate(R.layout.fragment_pager, container, false);
        TextView textView = (TextView) view.findViewById(R.id.tv);
        textView.setText(mContent);

        return view;
    }
}

调用绑定:

    private void setVp() {
        final List<PagerFragment> list = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            PagerFragment fragment = new PagerFragment();
            Bundle bundle = new Bundle();
            bundle.putString("content", "第" + i + "个Frament");
            fragment.setArguments(bundle);

            list.add(fragment);
        }

        ViewPager vp = (ViewPager) findViewById(R.id.vp);
        vp.setAdapter(new FragmentStatePagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
                return list.get(position);
            }

            @Override
            public int getCount() {
                return list.size();
            }
        });
    }

运行效果:

FragmentStatePagerAdapter函数解释

1、Fragment getItem (int position)

根据传来的参数position,来返回当前要显示的fragment

2、getCount()

返回用于滑动的fragment总数;

实现轮播图效果

介绍一个轮播图开源控件: Android-ConvenientBanner

实现画廊效果

viewpager布局:

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:clipChildren="false">

    <include layout="@layout/layout_toolbar"/>

    <android.support.v4.view.ViewPager
        android:id="@+id/vp"
        android:layout_width="match_parent"
        android:layout_height="180dp"
        android:layout_marginTop="100dp"
        android:layout_marginLeft="30dp"
        android:layout_marginRight="30dp"
        android:clipChildren="false">
    </android.support.v4.view.ViewPager>

</LinearLayout>

要点:
给viewpager和它的父布局都设置属性android:clipChildren=”false”
clipChild用来定义它的子控件是否要在它应有的边界内进行绘制。 默认情况下,clipChild被设置为true。 也就是不允许进行扩展绘制。如果不设置为false,就只会显示中间的图案,左右两边将被隐藏。
item_banner.xml:

<?xml version="1.0" encoding="utf-8"?>
<ImageView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/iv_banner"
    android:layout_width="match_parent"
    android:layout_height="180dp"
    android:background="#009999"
    android:scaleType="centerCrop"/>

Adapter

public class FourthPageAdapter extends PagerAdapter {

    private Context mContext;

    public FourthPageAdapter(Context context) {
        mContext = context;
    }

    @Override
    public int getCount() {
        return Integer.MAX_VALUE;
    }

    @Override
    public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
        return  view == object;
    }

    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
        // 就4张图片
        position %= 4;

        View view = View.inflate(mContext, R.layout.item_banner,null);
        ImageView iv = (ImageView) view.findViewById(R.id.iv_banner);
        int resourceId = mContext.getResources().getIdentifier("img" + (position + 1), "drawable", mContext.getPackageName());
        //https://www.cnblogs.com/guilin-hu/p/5706916.html
        Glide.with(mContext).load(resourceId).into(iv);// 加载图片到ImageView中

        container.addView(view);
        return view;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View)object);
    }
}

Glide是一套图片加载框架。
调用绑定:

    private void setVp() {

        final ViewPager vp = (ViewPager) findViewById(R.id.vp);

        // 设置适配器
        vp.setAdapter(new FourthPageAdapter(this));

        // page 边距
        vp.setPageMargin((int)(getResources().getDisplayMetrics().density * 15));

        // 显示在中间,且显示第一张
        int i = Integer.MAX_VALUE/2%4;
        vp.setCurrentItem(Integer.MAX_VALUE/2 + (4-i));
        }

运行效果:

当page宽度 < vp宽度,且page的数量较少,没有占满vp,这时滑动vp,会出现闪屏 解决办法:

1.当明确知道vp放不下2个page时,可以如下处理

@Override
public float getPageWidth(int position) {
    // 加上这句
    if(getCount() < 2){
        return super.getPageWidth(position);
    }

    float itemWidth =  (mContext.getResources().getDisplayMetrics().density * 200);
    float vpWidth = (mContext.getResources().getDisplayMetrics().widthPixels - mContext.getResources().getDisplayMetrics().density * 60);

    Log.e("比例",vpWidth+"==="+itemWidth+"==="+(int)(vpWidth/itemWidth));

    return  itemWidth / vpWidth;

}

2.当vp可以放置两个以上的page时,也是个通用的方法

vp.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // vp中最多能放下2个page,则让vp中page个数 < 3时,让vp不能滑动
        if(vp.getChildCount() < 3 && event.getAction() == MotionEvent.ACTION_MOVE){
            return true;
        }
        return false;
    }
});

参考
https://blog.csdn.net/weixin_39251617/article/details/79399592
https://blog.csdn.net/harvic880925/article/details/38487149
https://blog.csdn.net/weixin_39251617/article/details/79032641
https://blog.csdn.net/harvic880925/article/details/38660861

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值