给ViewPager加上滑动条


使用网易新闻的时候,如果左右滑动页面,会发现上面的Tab下面有条红条,可以随着下面页面的滑动而滑动,用来指明当前的页面。研究了一下,发现可以使用ViewPager和自定义View来实现类似的效果。

        在使用Viewpager的时候,我们一般都会注册一个OnPageChangeListener,来看一下它的代码:
   点击( 此处 )折叠或打开
  1. /**
  2.      * Callback interface for responding to changing state of the selected page.
  3.      */
  4.     public interface OnPageChangeListener {

  5.         /**
  6.          * This method will be invoked when the current page is scrolled, either as part
  7.          * of a programmatically initiated smooth scroll or a user initiated touch scroll.
  8.          *
  9.          * @param position Position index of the first page currently being displayed.
  10.          * Page position+1 will be visible if positionOffset is nonzero.
  11.          * @param positionOffset Value from [0, 1) indicating the offset from the page at position.
  12.          * @param positionOffsetPixels Value in pixels indicating the offset from position.
  13.          */
  14.         public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);

  15.         /**
  16.          * This method will be invoked when a new page becomes selected. Animation is not
  17.          * necessarily complete.
  18.          *
  19.          * @param position Position index of the new selected page.
  20.          */
  21.         public void onPageSelected(int position);

  22.         /**
  23.          * Called when the scroll state changes. Useful for discovering when the user
  24.          * begins dragging, when the pager is automatically settling to the current page,
  25.          * or when it is fully stopped/idle.
  26.          *
  27.          * @param state The new scroll state.
  28.          * @see ViewPager#SCROLL_STATE_IDLE
  29.          * @see ViewPager#SCROLL_STATE_DRAGGING
  30.          * @see ViewPager#SCROLL_STATE_SETTLING
  31.          */
  32.         public void onPageScrollStateChanged(int state);
  33.     }
    可以看到这个接口有三个回调的方法,其中onPageScrolled方法在滑动的时候会被调用。这个方法有三个参数,看其说明可以知道 position就是当前显示第一页的序号,positionOffset是一个0到1的数,用来表示当前页滑动的位置,数值越大,就表示滑动的幅度越大。就需要通过这个方法来知道滑动的位置。

   下面需要一个自定义的View,来画这个滑动条。当onPageScrolled方法被调用的时候,我们就需要重画来定位滑动条的位置。下面是自定义VIew的代码:

点击(此处)折叠或打开

  1. public class ScllorTabView extends View {

  2.     private int mTabNum, mCurrentNum;
  3.     private float mWidth, mTabWidth, mOffset;
  4.     private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  5.     private int mBeginColor;
  6.     private int mEndColor;
  7.     LinearGradient gradient;

  8.     public ScllorTabView(Context context, AttributeSet attrs) {
  9.         super(context, attrs);
  10.     }

  11.     public void setTabNum(int n) {
  12.         mTabNum = n;
  13.     }

  14.     public void setCurrentNum(int n) {
  15.         mCurrentNum = n;
  16.         mOffset = 0;
  17.     }

  18.     public void setOffset(int position, float offset) {
  19.         if (offset == 0) {
  20.             return;
  21.         }
  22.         mCurrentNum = position;
  23.         mOffset = offset;
  24.         invalidate();
  25.     }

  26.     @Override
  27.     protected void onDraw(Canvas canvas) {
  28.         super.onDraw(canvas);
  29.         if (mTabWidth == 0) {
  30.             mWidth = getWidth();
  31.             mTabWidth = mWidth / mTabNum;
  32.         }
  33.         //根据位置和偏移量来计算滑动条的位置
  34.         float left = (mCurrentNum + mOffset) * mTabWidth;
  35.         final float right = left + mTabWidth;
  36.         final float top = getPaddingTop();
  37.         final float bottom = getHeight() - getPaddingBottom();

  38.         // if (gradient == null) {
  39.         LinearGradient gradient = new LinearGradient(left, getHeight(), right,
  40.                 getHeight(), mBeginColor, mEndColor, Shader.TileMode.CLAMP);
  41.         mPaint.setShader(gradient);
  42.         // }
  43.         canvas.drawRect(left, top, right, bottom, mPaint);
  44.     }

  45.     public void setSelectedColor(int color, int color2) {
  46.         mBeginColor = color;
  47.         mEndColor = color2;

  48.     }
  49. }
    其中LinearGradient是用来设置渐变色的,也可以去掉。最后只需要加上调用更新的代码就可以了:

点击(此处)折叠或打开

  1. @Override
  2.             public void onPageScrolled(int position, float positionOffset,
  3.                     int positionOffsetPixels) {
  4.                 mScllorTabView.setOffset(position, positionOffset);
  5.             }
    好了,来看一下实现的效果吧



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现 ViewPager 的循环滑动,可以通过以下步骤: 1. 继承 ViewPager 类,重写 `onTouchEvent` 方法,使其支持循环滑动。 ```java public class LoopViewPager extends ViewPager { public LoopViewPager(Context context) { super(context); } public LoopViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); if (action == MotionEvent.ACTION_DOWN) { stopAutoScroll(); } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { startAutoScroll(); } return super.onTouchEvent(event); } } ``` 2. 重写 `onMeasure` 方法,使其支持 wrap_content。 ```java @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height = 0; for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); int h = child.getMeasuredHeight(); if (h > height) { height = h; } } heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } ``` 3. 重写 `setAdapter` 方法,使其支持循环滑动。 ```java @Override public void setAdapter(PagerAdapter adapter) { super.setAdapter(adapter); setCurrentItem(0); } @Override public void setCurrentItem(int item) { int realCount = getRealCount(); if (realCount == 0) { super.setCurrentItem(item); return; } int position = getRealPosition(item); super.setCurrentItem(position); } private int getRealCount() { PagerAdapter adapter = getAdapter(); if (adapter == null) { return 0; } return adapter.getCount(); } private int getRealPosition(int position) { int realCount = getRealCount(); if (realCount == 0) { return 0; } return position % realCount; } ``` 4. 在 `onPageSelected` 回调中处理循环滑动的逻辑。 ```java @Override public void onPageSelected(int position) { int realCount = getRealCount(); if (realCount == 0) { return; } int realPosition = getRealPosition(position); if (realPosition == 0) { setCurrentItem(realCount, false); } else if (realPosition == realCount - 1) { setCurrentItem(1, false); } } ``` 5. 在 `startAutoScroll` 和 `stopAutoScroll` 方法中处理自动滑动的逻辑。 ```java private void startAutoScroll() { stopAutoScroll(); mHandler.postDelayed(mAutoScrollTask, mInterval); } private void stopAutoScroll() { mHandler.removeCallbacks(mAutoScrollTask); } private Runnable mAutoScrollTask = new Runnable() { @Override public void run() { int currentItem = getCurrentItem(); setCurrentItem(currentItem + 1, true); mHandler.postDelayed(this, mInterval); } }; ``` 完整的实现代码如下: ```java public class LoopViewPager extends ViewPager { private static final int DEFAULT_INTERVAL = 3000; private Handler mHandler = new Handler(); private int mInterval = DEFAULT_INTERVAL; public LoopViewPager(Context context) { super(context); init(); } public LoopViewPager(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { setPageTransformer(true, new DefaultTransformer()); } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); if (action == MotionEvent.ACTION_DOWN) { stopAutoScroll(); } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { startAutoScroll(); } return super.onTouchEvent(event); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height = 0; for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); int h = child.getMeasuredHeight(); if (h > height) { height = h; } } heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override public void setAdapter(PagerAdapter adapter) { super.setAdapter(adapter); setCurrentItem(0); } @Override public void setCurrentItem(int item) { int realCount = getRealCount(); if (realCount == 0) { super.setCurrentItem(item); return; } int position = getRealPosition(item); super.setCurrentItem(position); } @Override public void setCurrentItem(int item, boolean smoothScroll) { int realCount = getRealCount(); if (realCount == 0) { super.setCurrentItem(item, smoothScroll); return; } int position = getRealPosition(item); super.setCurrentItem(position, smoothScroll); } @Override public int getCurrentItem() { int realCount = getRealCount(); if (realCount == 0) { return super.getCurrentItem(); } int position = super.getCurrentItem(); return getRealPosition(position); } private int getRealCount() { PagerAdapter adapter = getAdapter(); if (adapter == null) { return 0; } return adapter.getCount(); } private int getRealPosition(int position) { int realCount = getRealCount(); if (realCount == 0) { return 0; } return position % realCount; } @Override public void onPageSelected(int position) { int realCount = getRealCount(); if (realCount == 0) { return; } int realPosition = getRealPosition(position); if (realPosition == 0) { setCurrentItem(realCount, false); } else if (realPosition == realCount - 1) { setCurrentItem(1, false); } } public void setInterval(int interval) { mInterval = interval; } public void startAutoScroll() { stopAutoScroll(); mHandler.postDelayed(mAutoScrollTask, mInterval); } public void stopAutoScroll() { mHandler.removeCallbacks(mAutoScrollTask); } private Runnable mAutoScrollTask = new Runnable() { @Override public void run() { int currentItem = getCurrentItem(); setCurrentItem(currentItem + 1, true); mHandler.postDelayed(this, mInterval); } }; private static class DefaultTransformer implements ViewPager.PageTransformer { @Override public void transformPage(View page, float position) { if (position < -1) { page.setAlpha(0); } else if (position <= 1) { float scaleFactor = Math.max(0.75f, 1 - Math.abs(position - 0.125f)); page.setScaleX(scaleFactor); page.setScaleY(scaleFactor); } else { page.setAlpha(0); } } } } ``` 使用方式: ```xml <com.example.LoopViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="wrap_content" /> ``` ```java LoopViewPager viewPager = findViewById(R.id.view_pager); PagerAdapter adapter = new MyPagerAdapter(); viewPager.setAdapter(adapter); viewPager.setInterval(3000); viewPager.startAutoScroll(); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值