点击下载源码
简介
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
返回的对象应该已添加到ViewGroup
。 destroyItem
返回的对象应该被ViewGroup
删除。
4.isViewFromObject
(View, Object)代表了当前的View
是否与给定的Object(key
)相关联。
每个滑动
View
都对应一个Key
,而且这个Key
值是用来唯一追踪这个View
的,也就是说每个滑动View
都与一个唯一的Key
一一对应。
对于非常简单的PagerAdapter
或许你可以选择用View
本身作为键,在创建并且添加到ViewGroup
后instantiateItem
方法里返回该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
属性设置为top
或bottom
来将它显示在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());
运行效果:

里面有十几种翻页动画,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:FragmentPagerAdapter
和FragmentStatePagerAdapter。
相同点: 都继承自PagerAdapter
。
不同点: 卸载不再需fragment时,各自采用的处理方法有所不同。
FragmentStatePagerAdapter
会销毁不需要的fragment
。事务提交后, activity的FragmentManager中的fragment会被彻底移除。 FragmentStatePagerAdapter
类名中的“state”表明:在销毁fragment时,可在onSaveInstanceState(Bundle)
方法中保存fragment
的Bundle
信息。用户切换回来时,保存的实例状态可用来恢复生成新的fragment
。
FragmentPagerAdapter
有不同的做法。对于不再需要的fragment
, FragmentPagerAdapter
会选择调用事务的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));
}
运行效果:

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