赞
踩
ViewPager 指示器框架 —— MagicIndicator
添加依赖
dependencies {
compile project(':magicindicator')
}
在布局文件中添加MagicIndicator
<?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="net.lucode.hackware.magicindicatordemo.MainActivity"> <net.lucode.hackware.magicindicator.MagicIndicator android:id="@+id/magic_indicator" android:layout_width="match_parent" android:layout_height="@dimen/navigator_common_height" android:background="#d43d3d" /> <android.support.v4.view.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:background="@android:color/white" /> </LinearLayout>
在代码中简单设置
final MagicIndicator magicIndicator = (MagicIndicator) findViewById(R.id.magic_indicator); final CommonNavigator commonNavigator = new CommonNavigator(this); commonNavigator.setAdapter(new CommonNavigatorAdapter() { @Override public int getCount() { return mDataList == null ? 0 : mDataList.size(); } @Override public IPagerTitleView getItemView(Context context, final int index) { ClipPagerTitleView clipPagerTitleView = new ClipPagerTitleView(context); clipPagerTitleView.setText(mDataList.get(index)); clipPagerTitleView.setTextColor(Color.parseColor("#f2c4c4")); clipPagerTitleView.setClipColor(Color.WHITE); clipPagerTitleView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mPager.setCurrentItem(index); } }); return clipPagerTitleView; } @Override public IPagerIndicator getIndicator(Context context) { return null; // 没有指示器,因为title的指示作用已经很明显了 } }); magicIndicator.setNavigator(commonNavigator);
上面这代码明显没有和 ViewPager 相关联,因此滑动 ViewPager 时是看不到切换效果的,给 ViewPager 添加一个监听器:
mPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { magicIndicator.onPageScrolled(position, positionOffset, positionOffsetPixels); } @Override public void onPageSelected(int position) { magicIndicator.onPageSelected(position); } @Override public void onPageScrollStateChanged(int state) { magicIndicator.onPageScrollStateChanged(state); } });
MagicIndicator 中目前内置了两个 IPagerNavigator (后续不断增多),分别是:
CommonNavigator 是一个通用的指示器,也就是指我们常见的横向的、带有很多子元素的的指示器。子元素中可带文本、图标以及你想要的任何View。
/**
* 提供给外部的参数配置
*/
/****************************************************/
private boolean mAdjustMode; // 自适应模式,为true表示title均分宽度,适用于数目固定的、少量的title
private boolean mEnablePivotScroll; // 启动中心点滚动
private float mScrollPivotX = 0.5f; // 滚动中心点 0.0f - 1.0f
private boolean mSmoothScroll = true; // 是否平滑滚动,适用于 !mAdjustMode && !mFollowTouch
private boolean mFollowTouch = true; // 是否手指跟随滚动
private int mRightPadding;
private int mLeftPadding;
/****************************************************/
自适应模式,默认为 false,适用于数目固定的、子元素较少的指示器,比如讯飞输入法的皮肤界面:
自适应模式下,每个子元素的宽度默认是均分的。
如果你不想均分,重写 CommonNavigatorAdapter 的 getTitleWeight 方法吧。同时,其余6个属性都不生效了。
手指跟随滚动,默认为true,此模式下,只要 ViewPager 滚动,子元素也会跟着滚动,否则要等手指抬起后(onPageSelected)才开始滚动,效果如小飞读报:
滚动的中心点,默认为0.5f,也就是居中,就像刚才小飞读报的效果,如果你设置为0.15f,就是网易新闻的效果啦:
是否开启中心点滚动,默认为 false,开启后,选中某一个子元素时,将会根据 mScrollPivotX 滚动到合适的位置,否则,只有当子元素不完全可见时,才会触发滚动,使得子元素完全可见。
是否平滑滚动,默认为 true,在 !mAdjustMode && !mFollowTouch 下生效。也就是当子元素不完全可见时,触发滚动使之完全可见时是否平滑滚动。
CommonNavigator 内部的 HorizontalScrollView 的 左右padding,默认为0。今日头条的效果:
可以看到,添加频道按钮和搜索按钮是悬在指示器上边的,但是指示器中的最后一个元素却可以滚出来。
MagicIndicator 目前内建了好几种指示器,基本可以满足绝大部分需求,并且每一种指示器都支持通过 插值器(Interpolator) 来微调效果。
如果你想换一个效果,只需在 getItemView 里返回不同的指示器标题(IPagerTitleView),在 getIndicator 里返回不同的指示器(IPagerIndicator)
下面演示一下使用内建的指示器实现效果图中的小尖角式切换效果:
final MagicIndicator magicIndicator = (MagicIndicator) findViewById(R.id.magic_indicator); final CommonNavigator commonNavigator = new CommonNavigator(this); commonNavigator.setAlwaysScrollToCenter(true); commonNavigator.setAdapter(new CommonNavigatorAdapter() { @Override public int getCount() { return mDataList == null ? 0 : mDataList.size(); } @Override public IPagerTitleView getItemView(Context context, final int index) { SimplePagerTitleView simplePagerTitleView = new SimplePagerTitleView(context); simplePagerTitleView.setText(mDataList.get(index)); simplePagerTitleView.setNormalColor(Color.parseColor("#333333")); simplePagerTitleView.setSelectedColor(Color.parseColor("#e94220")); simplePagerTitleView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mPager.setCurrentItem(index); } }); return simplePagerTitleView; } @Override public IPagerIndicator getIndicator(Context context) { TriangularPagerIndicator indicator = new TriangularPagerIndicator(context); indicator.setLineColor(Color.parseColor("#e94220")); return indicator; } }); magicIndicator.setNavigator(commonNavigator);
在getItemView()方法中,用CommonPagerTitleView自定义指示器标题的滑动效果。
final MagicIndicator magicIndicator = (MagicIndicator) findViewById(R.id.magic_indicator); CommonNavigator commonNavigator = new CommonNavigator(this); commonNavigator.setAdapter(new CommonNavigatorAdapter() { @Override public int getCount() { return mDataList == null ? 0 : mDataList.size(); } @Override public IPagerTitleView getItemView(Context context, final int index) { CommonPagerTitleView commonPagerTitleView = new CommonPagerTitleView(MainActivity.this); commonPagerTitleView.setContentView(R.layout.simple_pager_title_layout); // 初始化 final ImageView titleImg = (ImageView) commonPagerTitleView.findViewById(R.id.title_img); titleImg.setImageResource(R.mipmap.ic_launcher); final TextView titleText = (TextView) commonPagerTitleView.findViewById(R.id.title_text); titleText.setText(mDataList.get(index)); commonPagerTitleView.setOnPagerTitleChangeListener(new CommonPagerTitleView.OnPagerTitleChangeListener() { @Override public void onSelected(int index) { titleText.setTextColor(Color.RED); } @Override public void onDeselected(int index) { titleText.setTextColor(Color.BLACK); } @Override public void onLeave(int index, float leavePercent, boolean leftToRight) { titleImg.setScaleX(1.3f + (0.8f - 1.3f) * leavePercent); titleImg.setScaleY(1.3f + (0.8f - 1.3f) * leavePercent); } @Override public void onEnter(int index, float enterPercent, boolean leftToRight) { titleImg.setScaleX(0.8f + (1.3f - 0.8f) * enterPercent); titleImg.setScaleY(0.8f + (1.3f - 0.8f) * enterPercent); } }); commonPagerTitleView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mPager.setCurrentItem(index); } }); return commonPagerTitleView; } @Override public IPagerIndicator getIndicator(Context context) { return null; } }); magicIndicator.setNavigator(commonNavigator);
效果如下:
MagicIndicator 同样考虑到了 ViewPager 内容变化的情况,当 ViewPager 内容发生变化时,除了调用 PagerAdapter.notifyDataSetChanged ,还记得先调用 IPagerNavigator.notifyDataSetChanged
// 导航栏datalist发生变化时
mDataList.clear();
mDataList.add("欢迎关注");
mDataList.add("我的博客");
mDataList.add("hackware.lucode.net");
// 调用 IPagerNavigator.notifyDataSetChanged
commonNavigator.notifyDataSetChanged();
// 调用 PagerAdapter.notifyDataSetChanged
mAdapter.notifyDataSetChanged();
继承 IPagerNavigator 打造任意的指示效果
继承 IPagerTitleView 打造任意效果的指示器标题
继承 IPagerIndicator 打造任意效果的指示器
使用 CommonPagerTitleView 加载自定义布局
实现 IPagerNavigator 接口,使用 Canvas 实现,具体效果如下:
public class DummyCircleNavigator extends View implements IPagerNavigator { public DummyCircleNavigator(Context context) { super(context); } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { } @Override public void onPageScrollStateChanged(int state) { } // 被添加到 magicindicator 时调用 @Override public void onAttachToMagicIndicator() { } // 从 magicindicator 上移除时调用 @Override public void onDetachFromMagicIndicator() { } // 当指示数目改变时调用 @Override public void notifyDataSetChanged() { } }
根据用户设置的 mCircleSpacing,mRadius,mCircleCount,结合当前的宽度,我们可以计算出每一个圆的圆心位置:
private List<PointF> mCirclePoints = new ArrayList<PointF>(); @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { prepareCirclePoints(); } private void prepareCirclePoints() { mCirclePoints.clear(); if (mCircleCount > 0) { int y = getHeight() / 2; int measureWidth = mCircleCount * mRadius * 2 + (mCircleCount - 1) * mCircleSpacing; int centerSpacing = mRadius * 2 + mCircleSpacing; int startX = (getWidth() - measureWidth) / 2 + mRadius; for (int i = 0; i < mCircleCount; i++) { PointF pointF = new PointF(startX, y); mCirclePoints.add(pointF); startX += centerSpacing; } } }
绘制圆形
@Override protected void onDraw(Canvas canvas) { drawDeselectedCircles(canvas); drawSelectedCircle(canvas); } private void drawDeselectedCircles(Canvas canvas) { mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(mStrokeWidth); mPaint.setColor(mCircleColor); for (int i = 0, j = mCirclePoints.size(); i < j; i++) { PointF pointF = mCirclePoints.get(i); canvas.drawCircle(pointF.x, pointF.y, mRadius, mPaint); } } private void drawSelectedCircle(Canvas canvas) { mPaint.setStyle(Paint.Style.FILL); if (mCirclePoints.size() > 0) { float selectedCircleX = mCirclePoints.get(mCurrentIndex).x; canvas.drawCircle(selectedCircleX, getHeight() / 2, mRadius, mPaint); } }
给 mCurrentIndex 赋值,同时,mCircleCount 变化时需要重新计算圆心位置:
@Override
public void onPageSelected(int position) {
mCurrentIndex = position;
invalidate();
}
public void setCircleCount(int circleCount) {
mCircleCount = circleCount;
}
@Override
public void notifyDataSetChanged() {
prepareCirclePoints();
invalidate();
}
我们来实现这种效果:在滑动一段距离后且手指未抬起时去改变颜色。
直接继承 TextView 并实现 IPagerTitleView,在 onEnter 回调中做判断,如果 enterPercent 大于设定的阈值,就将文字颜色设为选中颜色,否则,设为未选中颜色,代码如下:
public class ColorFlipPagerTitleView extends TextView implements IPagerTitleView { private int mNormalColor; private int mSelectedColor; private float mChangePercent = 0.45f; public ColorFlipPagerTitleView(Context context) { super(context); setGravity(Gravity.CENTER); int padding = UIUtil.dip2px(context, 10); setPadding(padding, 0, padding, 0); setSingleLine(); setEllipsize(TextUtils.TruncateAt.END); } @Override public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) { if (leavePercent >= mChangePercent) { setTextColor(mNormalColor); } else { setTextColor(mSelectedColor); } } @Override public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) { if (enterPercent >= mChangePercent) { setTextColor(mSelectedColor); } else { setTextColor(mNormalColor); } } // 部分 setter、getter 略 }
还想提供内容的边界,那就继承 IMeasuablePagerTitleView 吧,并实现以下方法:
@Override public int getContentLeft() { Rect bound = new Rect(); getPaint().getTextBounds(getText().toString(), 0, getText().length(), bound); int contentWidth = bound.width(); return getLeft() + getWidth() / 2 - contentWidth / 2; } @Override public int getContentTop() { Paint.FontMetrics metrics = getPaint().getFontMetrics(); float contentHeight = metrics.bottom - metrics.top; return (int) (getHeight() / 2 - contentHeight / 2); } @Override public int getContentRight() { Rect bound = new Rect(); getPaint().getTextBounds(getText().toString(), 0, getText().length(), bound); int contentWidth = bound.width(); return getLeft() + getWidth() / 2 + contentWidth / 2; } @Override public int getContentBottom() { Paint.FontMetrics metrics = getPaint().getFontMetrics(); float contentHeight = metrics.bottom - metrics.top; return (int) (getHeight() / 2 + contentHeight / 2); }
目前内置的 IPagerIndicator 全是跟随手指滑动的,我们来打造一个简单的、不跟随的指示器。这个指示器会在被选中的 IPagerTitleView 下方显示一个小点。
public class DotPagerIndicator extends View implements IPagerIndicator { private List<PositionData> mDataList; private float mRadius; private float mYOffset; private float mCircleCenterX; private int mDotColor; private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); public DotPagerIndicator(Context context) { super(context); } @Override public void onPageSelected(int position) { if (mDataList == null || mDataList.isEmpty()) { return; } PositionData data = mDataList.get(position); mCircleCenterX = data.mLeft + data.width() / 2; invalidate(); } @Override public void onPositionDataProvide(List<PositionData> dataList) { mDataList = dataList; } @Override protected void onDraw(Canvas canvas) { mPaint.setColor(mDotColor); canvas.drawCircle(mCircleCenterX, getHeight() - mYOffset - mRadius, mRadius, mPaint); } // 一些 getter、setter 略 }
CommonPagerTitleView 继承 FrameLayout 并实现了 IMeasurablePagerTitleView,它支持将自定义的布局文件设置进来,并且把 onEnter、onLeave . . . getContentLeft、getContentTop 等方法都回调出去
public class CommonPagerTitleView extends FrameLayout implements IMeasurablePagerTitleView { private OnPagerTitleChangeListener mOnPagerTitleChangeListener; private ContentPositionDataProvider mContentPositionDataProvider; public CommonPagerTitleView(Context context) { super(context); } public void setContentView(int layoutId) { View child = LayoutInflater.from(getContext()).inflate(layoutId, null); setContentView(child, null); } @Override public void onSelected(int index, int totalCount) { if (mOnPagerTitleChangeListener != null) { mOnPagerTitleChangeListener.onSelected(index, totalCount); } } // 省略一部分方法 public interface OnPagerTitleChangeListener { void onSelected(int index, int totalCount); void onDeselected(int index, int totalCount); void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight); void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight); } public interface ContentPositionDataProvider { int getContentLeft(); int getContentTop(); int getContentRight(); int getContentBottom(); } }
定义布局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" android:paddingLeft="10dp" android:paddingRight="10dp"> <ImageView android:id="@+id/title_img" android:layout_width="20dp" android:layout_height="20dp" /> <TextView android:id="@+id/title_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" /> </LinearLayout>
布局文件设置到 CommonPagerTitleView 并进行初始化:
@Override public IPagerTitleView getTitleView(Context context, final int index) { CommonPagerTitleView commonPagerTitleView = new CommonPagerTitleView(MainActivity.this); commonPagerTitleView.setContentView(R.layout.simple_pager_title_layout); // 初始化 final ImageView titleImg = (ImageView) commonPagerTitleView.findViewById(R.id.title_img); titleImg.setImageResource(R.mipmap.ic_launcher); final TextView titleText = (TextView) commonPagerTitleView.findViewById(R.id.title_text); titleText.setText(mDataList.get(index)); commonPagerTitleView.setOnPagerTitleChangeListener(new CommonPagerTitleView.OnPagerTitleChangeListener() { @Override public void onSelected(int index, int totalCount) { titleText.setTextColor(Color.RED); } @Override public void onDeselected(int index, int totalCount) { titleText.setTextColor(Color.BLACK); } @Override public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) { titleImg.setScaleX(1.3f + (0.8f - 1.3f) * leavePercent); titleImg.setScaleY(1.3f + (0.8f - 1.3f) * leavePercent); } @Override public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) { titleImg.setScaleX(0.8f + (1.3f - 0.8f) * enterPercent); titleImg.setScaleY(0.8f + (1.3f - 0.8f) * enterPercent); } }); return commonPagerTitleView; }
效果如下:
新建一个Layout布局,用来容纳三个子界面。这里面要引入viewPager组件
<?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" android:background="@color/new_broad_list_bg" android:clickable="true"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorPrimary" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:navigationIcon="@drawable/ic_menu" app:title="智能互动" app:titleTextColor="@color/c_ffffff" /> <net.lucode.hackware.magicindicator.MagicIndicator android:id="@+id/magic_indicator" android:layout_width="match_parent" android:layout_height="@dimen/dp_45" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/toolbar" /> <androidx.viewpager.widget.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="@dimen/dp_0" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/magic_indicator" /> </androidx.constraintlayout.widget.ConstraintLayout>
新建在以上view pager中展示的子界面
信息采集子界面,布局界面如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="信息采集"
android:id="@+id/textView"
android:textSize="18dp" />
</LinearLayout>
信息采集子界面的加载代码:
public class DataCollectFragment extends BaseFragment implements View.OnClickListener {
@Override
protected int setContentView() {
return R.layout.fragment_data_collect;
}
...
服务器监测子界面
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="服务器监测"
android:id="@+id/textView"
android:textSize="18dp" />
</LinearLayout>
服务器监测子界面的加载代码:
public class ServerMonitorFragment extends BaseFragment implements View.OnClickListener {
@Override
protected int setContentView() {
return R.layout.fragment_server_monitor;
}
...
编写adapter类,继承FragmentPagerAdapter类:
public class ServerPagerAdapter extends FragmentPagerAdapter { private List<Fragment> fragmentList; public ServerPagerAdapter(FragmentManager fm,List<Fragment> fragmentList) { super(fm); this.fragmentList = fragmentList; } @Override public Fragment getItem(int position) { return fragmentList.get(position); } @Override public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) { super.setPrimaryItem(container, position, object); } @Override public int getCount() { return fragmentList.size(); } }
public class ServerFragment extends BaseFragment { @Nullable @BindView(R.id.toolbar) Toolbar toolbar; @BindView(R.id.magic_indicator) MagicIndicator magicIndicator; @BindView(R.id.view_pager) ViewPager viewPager; private List<String> navStrList = Arrays.asList(new String[]{ "信息采集", "服务器监测"}); private List<Fragment> serverFragmentList = new ArrayList<>(); private ServerPagerAdapter serverPagerAdapter; final static String TAG = ServerFragment.class.getSimpleName(); @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); initViewPager(); initMagicIndicator(); } private void initViewPager() { serverFragmentList.add(new DataCollectFragment()); serverFragmentList.add(new ServerMonitorFragment()); serverPagerAdapter = new ServerPagerAdapter(getChildFragmentManager(), serverFragmentList); viewPager.setAdapter(serverPagerAdapter); } // magicIndicator初始化,和view pager的绑定 private void initMagicIndicator() { magicIndicator.setBackgroundResource(R.color.colorPrimary); CommonNavigator commonNavigator = new CommonNavigator(mContext); commonNavigator.setAdjustMode(true); commonNavigator.setAdapter(new CommonNavigatorAdapter() { @Override public int getCount() { return navStrList == null ? 0 : navStrList.size(); } @Override public IPagerTitleView getTitleView(Context context, int index) { SimplePagerTitleView pagerTitleView = new SimplePagerTitleView(mContext); pagerTitleView.setText(navStrList.get(index)); pagerTitleView.setTextSize(16); pagerTitleView.setNormalColor(Color.parseColor("#295B69")); pagerTitleView.setSelectedColor(Color.parseColor("#8A9CA3")); pagerTitleView.setOnClickListener(v -> { viewPager.setCurrentItem(index); }); return pagerTitleView; } @Override public IPagerIndicator getIndicator(Context context) { LinePagerIndicator linePagerIndicator = new LinePagerIndicator(mContext); linePagerIndicator.setStartInterpolator(new AccelerateInterpolator()); linePagerIndicator.setEndInterpolator(new DecelerateInterpolator(1.6f)); linePagerIndicator.setYOffset(UIUtil.dip2px(mContext, 39)); linePagerIndicator.setLineHeight(UIUtil.dip2px(mContext, 3)); linePagerIndicator.setColors(Color.parseColor("#7DA0AA")); return linePagerIndicator; } @Override public float getTitleWeight(Context context, int index) { return 2.0f; } }); magicIndicator.setNavigator(commonNavigator); ViewPagerHelper.bind(magicIndicator, viewPager); } ...
ViewPager有个方法叫做:
setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) 用于设置ViewPager切换时的动画效果。
position说明:
当前显示页为0,前一页为-1,后一页为1,滑动过程中数值不断变大或变小,所以为float类型。
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());
效果如下:
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(); Log.e("TAG", view + " , " + position + ""); 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); } } }
效果如下:
Github地址:ViewPagerTransforms
效果如下:
// 调用方法,在监听器中重写以下三个方法即可对翻页不同状态监听 addOnPageChangeListener() ViewPager.OnPageChangeListener() /** * 页面滑动状态停止前一直调用 * position:当前点击滑动页面的位置 * positionOffset:当前页面偏移的百分比 * positionOffsetPixels:当前页面偏移的像素位置 */ onPageScrolled(int position, float positionOffset, int positionOffsetPixels) /** * 滑动后显示的页面和滑动前不同,调用 * position:选中显示页面的位置 */ onPageSelected(int position) /** * 页面状态改变时调用 * state:当前页面的状态 * SCROLL_STATE_IDLE:空闲状态 * SCROLL_STATE_DRAGGING:滑动状态 * SCROLL_STATE_SETTLING:滑动后滑翔的状态 */ onPageScrollStateChanged(int state)
简单使用示例:
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; } } });
轮播图开源控件:banner
参考文章:
MagicIndicato系列之一 —— 使用MagicIndicator打造千变万化的ViewPager指示器
MagicIndicator系列之二 —— MagicIndicator使用指南
MagicIndicator系列之三 —— MagicIndicator原理浅析及扩展MagicIndicator的4种方式
ViewPager+Fragment实现多个子界面滑动
ViewPager 全面总结
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。