您的位置:首页 > 其它

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

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

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

[java] view
plain copy

@Override  

    public void addView(View child) {  

        if (getChildCount() > 0) {  

            throw new IllegalStateException("HorizontalScrollView can host only one direct child")
20000
;  

        }  

  

        super.addView(child);  

    }  

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

[java] view
plain copy

LinearLayout linearLayout = new LinearLayout(context);  

       linearLayout.setOrientation(LinearLayout.HORIZONTAL);  

       linearLayout.setLayoutParams(new LinearLayout.LayoutParams(count*tabWidth, LinearLayout.LayoutParams.MATCH_PARENT));  

       for (int i = 0; i < count; i++)  

       {  

           TextView tv = new TextView(getContext());  

           LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(tabWidth,  

                   LinearLayout.LayoutParams.MATCH_PARENT);  

           tv.setGravity(Gravity.CENTER);  

           tv.setTextColor(COLOR_TEXT_NORMAL);  

           tv.setText(titles[i]);  

           tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);//字体大小  

           tv.setLayoutParams(lp);  

           final int finalI = i;  

           tv.setOnClickListener(new OnClickListener()  

           {  

               @Override  

               public void onClick(View v)  

               {  

                   if(viewPager!=null){  

                       viewPager.setCurrentItem(finalI);  

                   }  

               }  

           });  

           linearLayout.addView(tv);  

       }  

       addView(linearLayout);  

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

[java] view
plain copy

@Override  

    protected void dispatchDraw(Canvas canvas)  

    {  

        super.dispatchDraw(canvas);  

        canvas.save();  

        canvas.translate(mTranslationX, getHeight() - lineheight);  

        canvas.drawLine(0, 0, tabWidth, 0, mPaint);//(startX, startY, stopX, stopY, paint)  

        canvas.restore();  

    }  

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

[java] view
plain copy

/** 

         * This method will be invoked when the current page is scrolled, either as part 

         * of a programmatically initiated smooth scroll or a user initiated touch scroll. 

         * 

         * @param position Position index of the first page currently being displayed. 

         *                 Page position+1 will be visible if positionOffset is nonzero. 

         * @param positionOffset Value from [0, 1) indicating the offset from the page at position. 

         * @param positionOffsetPixels Value in pixels indicating the offset from position. 

         */  

        void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);  

通过源码可知,第一个参数是当前的位置,第二个参数比较有意思,是指滑动距离相对于整个viewpager宽度的百分比,第三个是滑动的真正距离。这里我们利用第二个参数实现跟随滑动效果。这里我封装了一个函数如下:

[java] view
plain copy

public void scroll(int position, float offset)  

    {  

        mTranslationX = tabWidth * (position + offset);  

        scrollTo((int)mTranslationX-(SCREEN_WIDTH-tabWidth)/2, 0);  

        invalidate();  

    }  

解释一下,我们将position和offse(百分比)传进去首先计算下划线应该滑动到的初始位置,然后利用scrollTo函数将HorizontalScrollView进行移动,最后重绘,于是就到达了滑动跟随的效果。全部源码如下:

[java] view
plain copy

package com.zp.scrolltest;  

  

import android.content.Context;  

import android.graphics.Canvas;  

import android.graphics.Color;  

import android.graphics.Paint;  

import android.support.v4.view.ViewPager;  

import android.util.AttributeSet;  

import android.util.TypedValue;  

import android.view.Gravity;  

import android.view.View;  

import android.widget.HorizontalScrollView;  

import android.widget.LinearLayout;  

import android.widget.TextView;  

  

/** 

 * Created by ez on 2017/5/4. 

 */  

  

public class MyIndicator extends HorizontalScrollView implements ViewPager.OnPageChangeListener{  

  

    private static final int COLOR_TEXT_NORMAL = 0xFF000000;  

    private static final int COLOR_INDICATOR_COLOR = Color.BLACK;  

  

    private Context context;  

    private  int tabWidth;  

    private String[] titles;  

    private int count;  

    private Paint mPaint;  

    private float mTranslationX;  

    private ViewPager viewPager;  

    private int SCREEN_WIDTH;  

    private float lineheight = 2.0f;  

  

    public MyIndicator(Context context) {  

        this(context, null);  

    }  

  

    public MyIndicator(Context context, AttributeSet attrs) {  

        super(context, attrs);  

        init(context);  

    }  

  

    public MyIndicator(Context context, AttributeSet attrs, int defStyleAttr) {  

        super(context, attrs, defStyleAttr);  

        init(context);  

    }  

  

    private void init(Context context){  

        this.context = context;  

        mPaint = new Paint();  

        mPaint.setColor(COLOR_INDICATOR_COLOR);  

        mPaint.setStrokeWidth(lineheight);//底部指示线的宽度  

        setHorizontalScrollBarEnabled(false);  

        SCREEN_WIDTH = context.getResources().getDisplayMetrics().widthPixels;  

    }  

  

    public void setLineheight(float height){  

        this.lineheight = height;  

        mPaint.setStrokeWidth(lineheight);//底部指示线的宽度  

    }  

  

    public void setViewPager(ViewPager viewPager){  

        this.viewPager = viewPager;  

        viewPager.addOnPageChangeListener(this);  

    }  

  

    public void setTitles(String[] titles){  

        this.titles = titles;  

        count = titles.length;  

        tabWidth = SCREEN_WIDTH/4;  

        generateTitleView();  

    }  

  

    @Override  

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {  

        super.onSizeChanged(w, h, oldw, oldh);  

        tabWidth = SCREEN_WIDTH/4;  

    }  

  

    @Override  

    protected void dispatchDraw(Canvas canvas)  

    {  

        super.dispatchDraw(canvas);  

        canvas.save();  

        canvas.translate(mTranslationX, getHeight() - lineheight);  

        canvas.drawLine(0, 0, tabWidth, 0, mPaint);//(startX, startY, stopX, stopY, paint)  

        canvas.restore();  

    }  

  

    public void scroll(int position, float offset)  

    {  

        mTranslationX = tabWidth * (position + offset);  

        scrollTo((int)mTranslationX-(SCREEN_WIDTH-tabWidth)/2, 0);  

        invalidate();  

    }  

  

    private void generateTitleView()  

    {  

        if (getChildCount() > 0)  

            this.removeAllViews();  

        count = titles.length;  

  

        LinearLayout linearLayout = new LinearLayout(context);  

        linearLayout.setOrientation(LinearLayout.HORIZONTAL);  

        linearLayout.setLayoutParams(new LinearLayout.LayoutParams(count*tabWidth, LinearLayout.LayoutParams.MATCH_PARENT));  

        for (int i = 0; i < count; i++)  

        {  

            TextView tv = new TextView(getContext());  

            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(tabWidth,  

                    LinearLayout.LayoutParams.MATCH_PARENT);  

            tv.setGravity(Gravity.CENTER);  

            tv.setTextColor(COLOR_TEXT_NORMAL);  

            tv.setText(titles[i]);  

            tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);//字体大小  

            tv.setLayoutParams(lp);  

            final int finalI = i;  

            tv.setOnClickListener(new OnClickListener()  

            {  

                @Override  

                public void onClick(View v)  

                {  

                    if(viewPager!=null){  

                        viewPager.setCurrentItem(finalI);  

                    }  

                }  

            });  

            linearLayout.addView(tv);  

        }  

        addView(linearLayout);  

    }  

  

    @Override  

    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {  

        scroll(position, positionOffset);  

    }  

  

    @Override  

    public void onPageSelected(int position) {  

  

    }  

  

    @Override  

    public void onPageScrollStateChanged(int state) {  

  

    }  

}  

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

[html] view
plain copy

<?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:id="@+id/activity_main"  

    android:orientation="vertical"  

    android:layout_width="match_parent"  

    android:layout_height="match_parent"  

    tools:context="com.zp.scrolltest.MainActivity">  

  

    <com.zp.scrolltest.MyIndicator  

        android:layout_width="wrap_content"  

        android:layout_height="40dp"  

        android:background="@android:color/holo_blue_bright"  

        android:id="@+id/indicador"/>  

  

    <android.support.v4.view.ViewPager  

        android:layout_width="match_parent"  

        android:layout_height="match_parent"  

        android:id="@+id/pager"/>  

  

</LinearLayout>  

接下来在Java代码中:

[java] view
plain copy

indicador = (MyIndicator) findViewById(R.id.indicador);  

        titles = new String[]{"a", "b", "c", "d", "e", "f"};  

        indicador.setTitles(titles);  

  

        viewPager = (ViewPager) findViewById(R.id.pager);  

          

        viewPager.setAdapter(mAdapter);  

        indicador.setViewPager(viewPager);  

以上就是全部实现。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: