利用HorizontalScrollView自己写一个viewPager指示器

目前滑动指示器最著名的是JakeWarton的ViewpagerIndicator,用别人的东西固然方便,但是也带来很多使用上的疑惑,这篇博客,我们使用HorizontalScrollView自己写一个viewPager指示器。

这里首先说一下很多自己写的indicator只限于可视范围内不能移动的指示器,所以tab的数量有限,一般最多五个就已经很拥挤了,可是我们发现开源的ViewpagerIndicator有一个很棒的效果就是不用限定tab的个数,并且当前选中的tab将处于中间位置(两边不可滑动范围除外),这一点我便想到了利用HorizontalScrollView来实现这个效果。而tab的显示我使用TextView就行动态加载,然后把tab放到HorizontalScrollView中,在这里注意一个问题,那就是HorizontalScrollView本身的子view个数是有限定的,只能是一个,这一点跟scrollview一样,源码是这样的:

[java]  view plain  copy
  1. @Override  
  2.     public void addView(View child) {  
  3.         if (getChildCount() > 0) {  
  4.             throw new IllegalStateException("HorizontalScrollView can host only one direct child");  
  5.         }  
  6.   
  7.         super.addView(child);  
  8.     }  

我们可以看到如果getChildCount()的个数大于零,就会抛出异常,所以这里我使用一个LinearLayout先包裹所有的textview然后再把LinearLayout放入HorizontalScrollView中,这样就不会抛异常了。代码如下:

[java]  view plain  copy
  1. LinearLayout linearLayout = new LinearLayout(context);  
  2.        linearLayout.setOrientation(LinearLayout.HORIZONTAL);  
  3.        linearLayout.setLayoutParams(new LinearLayout.LayoutParams(count*tabWidth, LinearLayout.LayoutParams.MATCH_PARENT));  
  4.        for (int i = 0; i < count; i++)  
  5.        {  
  6.            TextView tv = new TextView(getContext());  
  7.            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(tabWidth,  
  8.                    LinearLayout.LayoutParams.MATCH_PARENT);  
  9.            tv.setGravity(Gravity.CENTER);  
  10.            tv.setTextColor(COLOR_TEXT_NORMAL);  
  11.            tv.setText(titles[i]);  
  12.            tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);//字体大小  
  13.            tv.setLayoutParams(lp);  
  14.            final int finalI = i;  
  15.            tv.setOnClickListener(new OnClickListener()  
  16.            {  
  17.                @Override  
  18.                public void onClick(View v)  
  19.                {  
  20.                    if(viewPager!=null){  
  21.                        viewPager.setCurrentItem(finalI);  
  22.                    }  
  23.                }  
  24.            });  
  25.            linearLayout.addView(tv);  
  26.        }  
  27.        addView(linearLayout);  

而HorizontalScrollView中那个下划线效果,通过dispatchDraw方法实现

[java]  view plain  copy
  1. @Override  
  2.     protected void dispatchDraw(Canvas canvas)  
  3.     {  
  4.         super.dispatchDraw(canvas);  
  5.         canvas.save();  
  6.         canvas.translate(mTranslationX, getHeight() - lineheight);  
  7.         canvas.drawLine(00, tabWidth, 0, mPaint);//(startX, startY, stopX, stopY, paint)  
  8.         canvas.restore();  
  9.     }  

其滑动效果则通过监听viewpager滑动的OnPageChangeListener接口中的onPageScrolled函数实现,我们知道onPageScrolled有三个参数起源吗如下:

[java]  view plain  copy
  1. /** 
  2.          * This method will be invoked when the current page is scrolled, either as part 
  3.          * of a programmatically initiated smooth scroll or a user initiated touch scroll. 
  4.          * 
  5.          * @param position Position index of the first page currently being displayed. 
  6.          *                 Page position+1 will be visible if positionOffset is nonzero. 
  7.          * @param positionOffset Value from [0, 1) indicating the offset from the page at position. 
  8.          * @param positionOffsetPixels Value in pixels indicating the offset from position. 
  9.          */  
  10.         void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);  
通过源码可知,第一个参数是当前的位置,第二个参数比较有意思,是指滑动距离相对于整个viewpager宽度的百分比,第三个是滑动的真正距离。这里我们利用第二个参数实现跟随滑动效果。这里我封装了一个函数如下:

[java]  view plain  copy
  1. public void scroll(int position, float offset)  
  2.     {  
  3.         mTranslationX = tabWidth * (position + offset);  
  4.         scrollTo((int)mTranslationX-(SCREEN_WIDTH-tabWidth)/20);  
  5.         invalidate();  
  6.     }  
解释一下,我们将position和offse(百分比)传进去首先计算下划线应该滑动到的初始位置,然后利用scrollTo函数将HorizontalScrollView进行移动,最后重绘,于是就到达了滑动跟随的效果。全部源码如下:

[java]  view plain  copy
  1. package com.zp.scrolltest;  
  2.   
  3. import android.content.Context;  
  4. import android.graphics.Canvas;  
  5. import android.graphics.Color;  
  6. import android.graphics.Paint;  
  7. import android.support.v4.view.ViewPager;  
  8. import android.util.AttributeSet;  
  9. import android.util.TypedValue;  
  10. import android.view.Gravity;  
  11. import android.view.View;  
  12. import android.widget.HorizontalScrollView;  
  13. import android.widget.LinearLayout;  
  14. import android.widget.TextView;  
  15.   
  16. /** 
  17.  * Created by ez on 2017/5/4. 
  18.  */  
  19.   
  20. public class MyIndicator extends HorizontalScrollView implements ViewPager.OnPageChangeListener{  
  21.   
  22.     private static final int COLOR_TEXT_NORMAL = 0xFF000000;  
  23.     private static final int COLOR_INDICATOR_COLOR = Color.BLACK;  
  24.   
  25.     private Context context;  
  26.     private  int tabWidth;  
  27.     private String[] titles;  
  28.     private int count;  
  29.     private Paint mPaint;  
  30.     private float mTranslationX;  
  31.     private ViewPager viewPager;  
  32.     private int SCREEN_WIDTH;  
  33.     private float lineheight = 2.0f;  
  34.   
  35.     public MyIndicator(Context context) {  
  36.         this(context, null);  
  37.     }  
  38.   
  39.     public MyIndicator(Context context, AttributeSet attrs) {  
  40.         super(context, attrs);  
  41.         init(context);  
  42.     }  
  43.   
  44.     public MyIndicator(Context context, AttributeSet attrs, int defStyleAttr) {  
  45.         super(context, attrs, defStyleAttr);  
  46.         init(context);  
  47.     }  
  48.   
  49.     private void init(Context context){  
  50.         this.context = context;  
  51.         mPaint = new Paint();  
  52.         mPaint.setColor(COLOR_INDICATOR_COLOR);  
  53.         mPaint.setStrokeWidth(lineheight);//底部指示线的宽度  
  54.         setHorizontalScrollBarEnabled(false);  
  55.         SCREEN_WIDTH = context.getResources().getDisplayMetrics().widthPixels;  
  56.     }  
  57.   
  58.     public void setLineheight(float height){  
  59.         this.lineheight = height;  
  60.         mPaint.setStrokeWidth(lineheight);//底部指示线的宽度  
  61.     }  
  62.   
  63.     public void setViewPager(ViewPager viewPager){  
  64.         this.viewPager = viewPager;  
  65.         viewPager.addOnPageChangeListener(this);  
  66.     }  
  67.   
  68.     public void setTitles(String[] titles){  
  69.         this.titles = titles;  
  70.         count = titles.length;  
  71.         tabWidth = SCREEN_WIDTH/4;  
  72.         generateTitleView();  
  73.     }  
  74.   
  75.     @Override  
  76.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
  77.         super.onSizeChanged(w, h, oldw, oldh);  
  78.         tabWidth = SCREEN_WIDTH/4;  
  79.     }  
  80.   
  81.     @Override  
  82.     protected void dispatchDraw(Canvas canvas)  
  83.     {  
  84.         super.dispatchDraw(canvas);  
  85.         canvas.save();  
  86.         canvas.translate(mTranslationX, getHeight() - lineheight);  
  87.         canvas.drawLine(00, tabWidth, 0, mPaint);//(startX, startY, stopX, stopY, paint)  
  88.         canvas.restore();  
  89.     }  
  90.   
  91.     public void scroll(int position, float offset)  
  92.     {  
  93.         mTranslationX = tabWidth * (position + offset);  
  94.         scrollTo((int)mTranslationX-(SCREEN_WIDTH-tabWidth)/20);  
  95.         invalidate();  
  96.     }  
  97.   
  98.     private void generateTitleView()  
  99.     {  
  100.         if (getChildCount() > 0)  
  101.             this.removeAllViews();  
  102.         count = titles.length;  
  103.   
  104.         LinearLayout linearLayout = new LinearLayout(context);  
  105.         linearLayout.setOrientation(LinearLayout.HORIZONTAL);  
  106.         linearLayout.setLayoutParams(new LinearLayout.LayoutParams(count*tabWidth, LinearLayout.LayoutParams.MATCH_PARENT));  
  107.         for (int i = 0; i < count; i++)  
  108.         {  
  109.             TextView tv = new TextView(getContext());  
  110.             LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(tabWidth,  
  111.                     LinearLayout.LayoutParams.MATCH_PARENT);  
  112.             tv.setGravity(Gravity.CENTER);  
  113.             tv.setTextColor(COLOR_TEXT_NORMAL);  
  114.             tv.setText(titles[i]);  
  115.             tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);//字体大小  
  116.             tv.setLayoutParams(lp);  
  117.             final int finalI = i;  
  118.             tv.setOnClickListener(new OnClickListener()  
  119.             {  
  120.                 @Override  
  121.                 public void onClick(View v)  
  122.                 {  
  123.                     if(viewPager!=null){  
  124.                         viewPager.setCurrentItem(finalI);  
  125.                     }  
  126.                 }  
  127.             });  
  128.             linearLayout.addView(tv);  
  129.         }  
  130.         addView(linearLayout);  
  131.     }  
  132.   
  133.     @Override  
  134.     public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {  
  135.         scroll(position, positionOffset);  
  136.     }  
  137.   
  138.     @Override  
  139.     public void onPageSelected(int position) {  
  140.   
  141.     }  
  142.   
  143.     @Override  
  144.     public void onPageScrollStateChanged(int state) {  
  145.   
  146.     }  
  147. }  

最后说一下使用,首先在XML中像普通组件一样使用:

[html]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:tools="http://schemas.android.com/tools"  
  4.     android:id="@+id/activity_main"  
  5.     android:orientation="vertical"  
  6.     android:layout_width="match_parent"  
  7.     android:layout_height="match_parent"  
  8.     tools:context="com.zp.scrolltest.MainActivity">  
  9.   
  10.     <com.zp.scrolltest.MyIndicator  
  11.         android:layout_width="wrap_content"  
  12.         android:layout_height="40dp"  
  13.         android:background="@android:color/holo_blue_bright"  
  14.         android:id="@+id/indicador"/>  
  15.   
  16.     <android.support.v4.view.ViewPager  
  17.         android:layout_width="match_parent"  
  18.         android:layout_height="match_parent"  
  19.         android:id="@+id/pager"/>  
  20.   
  21. </LinearLayout>  

接下来在Java代码中:

[java]  view plain  copy
  1. indicador = (MyIndicator) findViewById(R.id.indicador);  
  2.         titles = new String[]{"a""b""c""d""e""f"};  
  3.         indicador.setTitles(titles);  
  4.   
  5.         viewPager = (ViewPager) findViewById(R.id.pager);  
  6.           
  7.         viewPager.setAdapter(mAdapter);  
  8.         indicador.setViewPager(viewPager);  

以上就是全部实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值