仿百度手机助手中的ViewPagerIndicator

参照鸿洋大神博客:http://blog.csdn.net/lmj623565791/article/details/42160391

源码地址:https://github.com/zhangcaiqi/CommonDemo

public class ViewPagerIndicatorextends LinearLayoutimplements ViewPager.OnPageChangeListener {

private Contextcontext;

    //屏幕中可见的tab数量

    private int mVisibleCount =4;

    private PaintmPaint;

    //指示器颜色

    private int indicatorColor = Color.BLACK;

    //tab标题文字颜色

    private int textColor = Color.BLACK;

    //tab标题文字大小

    private int textSize =12;

    //tab标题放大比例

    private float textSizeRatio =0.8f;

    //tab宽度

    private int mTabWidth;

    //指示器默认的宽度

    private float minWidthRatio =1.0f/8;

    //指示器可扩展伸长mTabWidth的30%,再进行平移40%,最后缩小到minWidthRatio的尺寸

    private float stretchRatio =0.3f;

    //指示器高度

    private int indicatorHeight =8;

    //指示器和标题之间的间隙

    private int indicatorSpacing =8;

    private ViewPagerviewPager;

    private CanvasmCanvas;

    //viewpager回调中的的position

    private int position;

    //viewpager回调中的offset

    private float positionOffset;

    //指示器默认再tab中央时的偏移量

    private float centerOffset;

    //指示器宽度

    private float mIndicatorWidth;

    //viewpager回调中的position,上述position会随着offset改变,用于计算向左还是向右滑动

    private int selectedPosition;

    public ViewPagerIndicator(Context context) {

this(context,null);

    }

public ViewPagerIndicator(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

        this.context = context;

        if(null != attrs){

TypedArray typedArray = getContext().obtainStyledAttributes(attrs,R.styleable.ViewPagerIndicator);

            indicatorColor = typedArray.getColor(R.styleable.ViewPagerIndicator_indicatorColor,indicatorColor);

            mVisibleCount = typedArray.getInt(R.styleable.ViewPagerIndicator_visibleCount,mVisibleCount);

            textColor = typedArray.getColor(R.styleable.ViewPagerIndicator_textColor,textColor);

            indicatorHeight = typedArray.getDimensionPixelOffset(R.styleable.ViewPagerIndicator_indicatorHeight,indicatorHeight);

            indicatorSpacing = typedArray.getDimensionPixelOffset(R.styleable.ViewPagerIndicator_indicatorSpacing,indicatorSpacing);

            minWidthRatio = typedArray.getFloat(R.styleable.ViewPagerIndicator_minWidthRatio,minWidthRatio);

            textSize = typedArray.getDimensionPixelSize(R.styleable.ViewPagerIndicator_textSize,textSize);

            textSizeRatio = typedArray.getFloat(R.styleable.ViewPagerIndicator_textSizeRatio,textSizeRatio);

            mTabWidth = typedArray.getDimensionPixelOffset(R.styleable.ViewPagerIndicator_tabWidth,mTabWidth);

        }

mPaint =new Paint();

        mPaint.setAntiAlias(true);

        mPaint.setColor(indicatorColor);

        mPaint.setStyle(Paint.Style.FILL);

        mPaint.setStrokeWidth(indicatorHeight);

    }

@Override

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int mode = MeasureSpec.getMode(heightMeasureSpec);

        int measuredHeight = getMeasuredHeight();

        int newHeight =indicatorHeight +indicatorSpacing + measuredHeight;

        int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight,mode);

        setMeasuredDimension(widthMeasureSpec,newHeightMeasureSpec);

    }

@Override

    protected void dispatchDraw(Canvas canvas) {

this.mCanvas = canvas;

        drawIndicator();

        scrollAdapt();

        textAdapt();

        super.dispatchDraw(canvas);

    }

@Override

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

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

        centerOffset = ((1-minWidthRatio)*mTabWidth)/2;

        mIndicatorWidth =minWidthRatio *mTabWidth;

    }

private int getScreenWidth(){

return  ScreenUtil.getScreenWidth(context);

    }

@Override

    protected void onFinishInflate() {

super.onFinishInflate();

        int childrenCount = getChildCount();

        if(childrenCount ==0){

return;

        }

mTabWidth =mTabWidth ==0 ? (getScreenWidth()/mVisibleCount) :mTabWidth;

        for(int i=0; i

TextView view = (TextView) getChildAt(i);

            view.setTextSize(textSize);

            view.setTextColor(textColor);

            LinearLayout.LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();

            layoutParams.width =mTabWidth;

            view.setLayoutParams(layoutParams);

        }

setItemClickEvent();

    }

public void setViewPager(ViewPager viewPager) {

this.viewPager = viewPager;

        viewPager.addOnPageChangeListener(this);

    }

private void setItemClickEvent() {

int count = getChildCount();

        for(int i=0;i

View view = getChildAt(i);

            int finalI = i;

            view.setOnClickListener((v)->{

viewPager.setCurrentItem(finalI);

            });

        }

}

private void drawIndicator(){

//        if(stretchRatio >= 0.5f){

//            throw new RuntimeException("非法stretchRatio");

//        }

        float indicatorOffsetX;

        float startX =0f,endX;

        if(positionOffset ==0){

indicatorOffsetX =centerOffset

                    +position*mTabWidth;

            endX =mIndicatorWidth;

        }else if(positionOffset <=stretchRatio){

//放大

            indicatorOffsetX =centerOffset

                    +position*mTabWidth;

            endX =mIndicatorWidth +positionOffset*mTabWidth;

        }else if(positionOffset >stretchRatio &&positionOffset <= (1-stretchRatio)){

//平移

            float translationPercent =1 -2*stretchRatio;

            indicatorOffsetX =centerOffset

                    + (positionOffset-stretchRatio)*((1-stretchRatio)*mTabWidth)/translationPercent

+position*mTabWidth;

            endX =mIndicatorWidth +stretchRatio*mTabWidth;

        }else {

//缩小

            indicatorOffsetX =2*mTabWidth

                    -centerOffset

                    - (mIndicatorWidth

                    +stretchRatio*mTabWidth)

+position*mTabWidth;;

            endX =mIndicatorWidth +stretchRatio*mTabWidth;

            startX = (positionOffset -1 +stretchRatio)*mTabWidth;

        }

mCanvas.save();

        mCanvas.translate(indicatorOffsetX,0);

        int y =  getMeasuredHeight() -indicatorHeight;

        mCanvas.drawLine(startX,y,endX,y,mPaint);

        mCanvas.restore();

    }

private void scrollAdapt(){

// 容器滚动,当移动到倒数最后一个的时候,开始滚动

        if (positionOffset >0

                &&position >= (mVisibleCount -2)

&& getChildCount() >mVisibleCount){

if (mVisibleCount !=1){

this.scrollTo((position - (mVisibleCount -2)) *mTabWidth + (int) (mTabWidth *positionOffset), 0);

            }else {

this.scrollTo(position *mTabWidth + (int) (mTabWidth *positionOffset), 0);

            }

}

}

private void textAdapt(){

TextView current = (TextView) getChildAt(selectedPosition);

        float changedSize =textSizeRatio*textSize;

        float selectedSize =textSize*(1+textSizeRatio);

        if(positionOffset !=0){

if(position >=selectedPosition){//向左滑动

                TextView next = (TextView) getChildAt(selectedPosition+1);

                float currentTextSize = selectedSize -positionOffset*changedSize;

                current.setTextSize(currentTextSize);

                float nextSize =textSize +positionOffset*changedSize;

                next.setTextSize(nextSize);

                if(positionOffset >0.5){

next.setTypeface(null, Typeface.BOLD);

                    current.setTypeface(null,Typeface.NORMAL);

                }else{

current.setTypeface(null, Typeface.BOLD);

                    next.setTypeface(null,Typeface.NORMAL);

                }

}else{//向右滑动

                TextView previous = (TextView) getChildAt(selectedPosition-1);

                float currentTextSize = selectedSize - (1-positionOffset)*changedSize;

                float previousSize =textSize + (1-positionOffset)*changedSize;

                current.setTextSize(currentTextSize);

                previous.setTextSize(previousSize);

                if(positionOffset <0.5){

previous.setTypeface(null, Typeface.BOLD);

                    current.setTypeface(null,Typeface.NORMAL);

                }else{

current.setTypeface(null, Typeface.BOLD);

                    previous.setTypeface(null,Typeface.NORMAL);

                }

}

}else{

//选中时

            current.setTextSize(selectedSize);

            current.setTypeface(null, Typeface.BOLD);

        }

}

@Override

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

this.position = position;

        this.positionOffset = positionOffset;

        invalidate();

        if(null !=pageChangeListener){

pageChangeListener.onPageScrolled(position,positionOffset,positionOffsetPixels);

        }

}

@Override

    public void onPageSelected(int position) {

this.position = position;

        this.positionOffset =0f;

        this.selectedPosition = position;

        invalidate();

        if(null !=pageChangeListener){

pageChangeListener.onPageSelected(position);

        }

}

@Override

    public void onPageScrollStateChanged(int state) {

if(null !=pageChangeListener){

pageChangeListener.onPageScrollStateChanged(state);

        }

}

public void setVisibleCount(int visibleCount){

this.mVisibleCount = visibleCount;

    }

public void setTabTitles(List titles){

if(null != titles && titles.size() >0){

removeAllViews();

            for(String title:titles){

addView(generateTab(title));

            }

setItemClickEvent();

        }

}

private ViewgenerateTab(String title){

mTabWidth =mTabWidth ==0 ? (getScreenWidth()/mVisibleCount) :mTabWidth;

        TextView view =new TextView(context);

        view.setTextSize(textSize);

        view.setTextColor(textColor);

        view.setText(title);

        view.setGravity(Gravity.CENTER);

        LayoutParams layoutParams =new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT);

        layoutParams.width =mTabWidth;

        view.setLayoutParams(layoutParams);

        return view;

    }

public interface PageChangeListener{

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

        void onPageSelected(int position);

        void onPageScrollStateChanged(int state);

    }

private PageChangeListenerpageChangeListener;

    public void setPageChangeListener(PageChangeListener pageChangeListener) {

this.pageChangeListener = pageChangeListener;

    }

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355