(原来可以这么简单)实现变色TextView及ViewPager指示器(二)

上篇实现了FadeTextView可变色的textView,今天结合ViewPager做一个指示器,运行效果可以见上篇博客:实现变色TextView及ViewPager指示器(原来可以这么简单)

思路:
1、自定义一个叫SimpleViewPagerIndicator继承ViewGroup。
2、根据传入的titles创建FadeView,水平摆放置布局中,布局最底下用画笔绘制一条线,
3、监听ViewPager的滑动,setOnPageChangeListener,根据onPageScrolled方法计算线条绘制的位置以及FadeTextView的颜色变换

测试layout文件:

 <com.cisetech.customer.customer.Animation.SimpleViewPagerIndicator
        android:id="@id/id_stickylayout_nav"
        android:layout_width="match_parent"
        android:layout_height="50dp">
    </com.cisetech.customer.customer.Animation.SimpleViewPagerIndicator>
    <android.support.v4.view.ViewPager
        android:id="@id/id_stickylayout_viewpager"
        android:layout_width="match_parent"
        android:background="#44ff0000"
        android:layout_height="match_parent">

    </android.support.v4.view.ViewPager>

第一步:还是继承一个ViewGroup,覆盖三个构造方法,(有种东西叫熟能生巧,所以,骚年加油!!)

/**
     * 定义当点击每个FadeTextView的回调接口
     */
    public interface OnIndicatorClickListener{
        void indicatorClick(View view,int position);
    }
    private OnIndicatorClickListener onIndicatorClickListener;

    public void setOnIndicatorClickListener(OnIndicatorClickListener onIndicatorClickListener) {
        this.onIndicatorClickListener = onIndicatorClickListener;
    }

    /**
     * titles
     */
    private String[]titles;
    private Paint mPaint;
    /**
     * 线条的宽度=控件的宽度/子控件的个数
     */
    private float mLineWidth;
    /**
     * 距离底部的Padding值,可忽略
     */
    private int mLinePading= (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics());
    /**
     * 底部线条绘制的开始位置
     */
    private float mLineStartX;

    public SimpleViewPagerIndicator(Context context) {
        this(context, null);
    }

    public SimpleViewPagerIndicator(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SimpleViewPagerIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setDither(true);
        mPaint.setStrokeWidth(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mLinePading, getResources().getDisplayMetrics()));
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.RED);
        setOrientation(LinearLayout.HORIZONTAL);
    }
    }

第二步:设置titles,并获取线条的宽度=控件宽度/子控件个数

/**
     * 当控件的size发生变化的时候会调用此方法
     * 一般在这获取控件的宽高
     * 我们在这获取线条的宽度
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mLineWidth=w/titles.length;
    }
     /**
     * 设置titles
     */
    public void setTitles(String[] titles) {
        this.titles = titles;
        setupTitles();
    }

    /**
     *添加titles到父控件中,
     * 并给每个子控设置点击监听
     */
    private void setupTitles() {
        if (getChildCount() > 0)
            this.removeAllViews();
        setWeightSum(titles.length);
        for (int i = 0; i < titles.length; i++) {
            final int j=i;
            final FadeView textView=new FadeView(getContext());
            LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(0,LayoutParams.MATCH_PARENT);
            lp.weight=1;
            textView.setLayoutParams(lp);
            textView.setmText(titles[i]);
            textView.setOnClickListener(new View.OnClickListener(){
                @Override
                public void onClick(View v) {
                    if(onIndicatorClickListener!=null){
                        onIndicatorClickListener.indicatorClick(v, j);
                    }
                }
            });
            addView(textView);
        }
    }

第三步:也是重点一步,绘制line

/**
     * 重写dispatchDraw方法绘制底部线条
     */
    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        canvas.save();
        /**
         * 通过平移canvas移动线条位置
         * mLineStartX
         */
        canvas.translate(mLineStartX,getHeight()-mLinePading);
        canvas.drawLine(0, 0, mLineWidth, 0, mPaint);
        canvas.restore();
    }

第四步:暴露方法供外部调用,从而不断切换item

/**
     * 通过监听ViewParger传进来当前ViewPager位置,
     * 以及偏移量(0-1)
     * 当从第0页切换到第一页的时候 position(int 0-1)offset(float 0-1)
     */
    public void setOffset(final int position, final float positionOffset) {
        /**
         * 线条开始的位置=线条的宽度*position+mLineWidth*positionOffset
         * 数学一样跟我不是很好的同学可以打个log看看值就懂了
         */
        float startX = mLineWidth * (position + positionOffset);
        setmLineStartX(startX);
        /**
         * 为什么是小于0.1呢,mPager.setCurrentItem(position,true);
         * 比如当前ViewPager位置是3,然后切换到0,跨了一个item,
         * 有点小bug,所以测试了一下当《0.1的,状态都重新切换一次就不会有bug了
         * 如果是mPager.setCurrentItem(position,false);不用动画切换的是不会有bug的
         */
        if (positionOffset < 0.1) {
            for (int k = 0; k < getChildCount(); k++) {
                FadeView fade = (FadeView) getChildAt(k);
                if (position == k) {
                    fade.setmProgress(1.0f);
                } else {
                    fade.setmProgress(0f);
                }
            }
        } else {
            FadeView left = (FadeView) getChildAt(position);
            FadeView right = (FadeView) getChildAt(position + 1);
            if (left != null) {
                left.setmDirection(FadeView.DIRECTION.RIGHT);
                left.setmProgress(1 - positionOffset);
            }
            if (right != null) {
                right.setmDirection(FadeView.DIRECTION.LEFT);
                right.setmProgress(positionOffset);
            }
        }
    }

第五步:测试成果

 private SimpleViewPagerIndicator mIndicator;
    private ViewPager mPager;
    private List<Fragment> mViews=new ArrayList<Fragment>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test4);
        mIndicator= (SimpleViewPagerIndicator) findViewById(R.id.id_stickylayout_nav);
        mPager= (ViewPager) findViewById(R.id.id_stickylayout_viewpager);
        initData();
    }
    private String titles[]={"简介","评价","相关"};
    private void initData() {
        mIndicator.setTitles(titles);
        for (int i = 0; i < 3; i++) {
            TabFragment frag=TabFragment.newInstance(titles[i]);
            Bundle bundle=new Bundle();
            bundle.putString(TabFragment.TITLE,titles[i]);
            frag.setArguments(bundle);
            mViews.add(frag);
        }
        mPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
                return mViews.get(position);
            }

            @Override
            public int getCount() {
                return mViews.size();
            }
        });
        mPager.setOnPageChangeListener(this);
        mIndicator.setOnIndicatorClickListener(this);
    }

    @Override
    public void onPageScrolled(final int position, final float positionOffset, int positionOffsetPixels) {
        mIndicator.setOffset(position, positionOffset);
    }

    @Override
    public void onPageSelected(int position) {

    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }

    @Override
    public void indicatorClick(View view, final int position) {
        mPager.setCurrentItem(position,false);
    }

是不是so easy啊!!只要坚持,并不断的总结,我相信你会成为大神的,哈哈~!!

最后附上SimpleViewPagerIndicator的源码:

package com.cisetech.customer.customer.Animation;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.widget.LinearLayout;

import com.cisetech.customer.customer.View.FadeView;

/**
 * Author:Yqy
 * Date:2016-08-05
 * Desc:
 * Company:cisetech
 */
public class SimpleViewPagerIndicator extends LinearLayout {
    /**
     * 定义当点击每个FadeTextView的回调接口
     */
    public interface OnIndicatorClickListener{
        void indicatorClick(View view,int position);
    }
    private OnIndicatorClickListener onIndicatorClickListener;

    public void setOnIndicatorClickListener(OnIndicatorClickListener onIndicatorClickListener) {
        this.onIndicatorClickListener = onIndicatorClickListener;
    }

    /**
     * titles
     */
    private String[]titles;
    private Paint mPaint;
    /**
     * 线条的宽度=控件的宽度/子控件的个数
     */
    private float mLineWidth;
    /**
     * 距离底部的Padding值,可忽略
     */
    private int mLinePading= (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics());
    /**
     * 底部线条绘制的开始位置
     */
    private float mLineStartX;

    public SimpleViewPagerIndicator(Context context) {
        this(context, null);
    }

    public SimpleViewPagerIndicator(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SimpleViewPagerIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setDither(true);
        mPaint.setStrokeWidth(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mLinePading, getResources().getDisplayMetrics()));
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.RED);
        setOrientation(LinearLayout.HORIZONTAL);
    }

    public String[] getTitles() {
        return titles;
    }

    /**
     * 设置titles
     */
    public void setTitles(String[] titles) {
        this.titles = titles;
        setupTitles();
    }

    public float getmLineStartX() {
        return mLineStartX;
    }

    public void setmLineStartX(float mLineStartX) {
        this.mLineStartX = mLineStartX;
        if(Looper.getMainLooper()==Looper.myLooper()){
            invalidate();
        }else{
            postInvalidate();
        }
    }

    /**
     *添加titles到父控件中,
     * 并给每个子控设置点击监听
     */
    private void setupTitles() {
        if (getChildCount() > 0)
            this.removeAllViews();
        setWeightSum(titles.length);
        for (int i = 0; i < titles.length; i++) {
            final int j=i;
            final FadeView textView=new FadeView(getContext());
            LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(0,LayoutParams.MATCH_PARENT);
            lp.weight=1;
            textView.setLayoutParams(lp);
            textView.setmText(titles[i]);
            textView.setOnClickListener(new View.OnClickListener(){
                @Override
                public void onClick(View v) {
                    if(onIndicatorClickListener!=null){
                        onIndicatorClickListener.indicatorClick(v, j);
                    }
                }
            });
            addView(textView);
        }
    }

    /**
     * 当控件的size发生变化的时候会调用此方法
     * 一般在这获取控件的宽高
     * 我们在这获取线条的宽度
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mLineWidth=w/titles.length;
    }

    /**
     * 重写dispatchDraw方法绘制底部线条
     */
    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        canvas.save();
        /**
         * 通过平移canvas移动线条位置
         * mLineStartX
         */
        canvas.translate(mLineStartX,getHeight()-mLinePading);
        canvas.drawLine(0, 0, mLineWidth, 0, mPaint);
        canvas.restore();
    }

    /**
     * 通过监听ViewParger传进来当前ViewPager位置,
     * 以及偏移量(0-1)
     * 当从第0页切换到第一页的时候 position(int 0-1)offset(float 0-1)
     */
    public void setOffset(final int position, final float positionOffset) {
        /**
         * 线条开始的位置=线条的宽度*position+mLineWidth*positionOffset
         * 数学一样跟我不是很好的同学可以打个log看看值就懂了
         */
        float startX = mLineWidth * (position + positionOffset);
        setmLineStartX(startX);
        /**
         * 为什么是小于0.1呢,mPager.setCurrentItem(position,true);
         * 比如当前ViewPager位置是3,然后切换到0,跨了一个item,
         * 有点小bug,所以测试了一下当《0.1的,状态都重新切换一次就不会有bug了
         * 如果是mPager.setCurrentItem(position,false);不用动画切换的是不会有bug的
         */
        if (positionOffset < 0.1) {
            for (int k = 0; k < getChildCount(); k++) {
                FadeView fade = (FadeView) getChildAt(k);
                if (position == k) {
                    fade.setmProgress(1.0f);
                } else {
                    fade.setmProgress(0f);
                }
            }
        } else {
            FadeView left = (FadeView) getChildAt(position);
            FadeView right = (FadeView) getChildAt(position + 1);
            if (left != null) {
                left.setmDirection(FadeView.DIRECTION.RIGHT);
                left.setmProgress(1 - positionOffset);
            }
            if (right != null) {
                right.setmDirection(FadeView.DIRECTION.LEFT);
                right.setmProgress(positionOffset);
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值