Android selectTab

项目需求:带有动画的选择按钮
先上图:这里写图片描述

1.分析结构:只有左右两个选择条目,使用LinearLayout

public class SelectTabView extends LinearLayout{
                //这里使用xml,所以构造方法使用第二个即可
     public SelectTabView(Context context, AttributeSet attrs) {
         super(context, attrs);
        init(context, attrs);
    }
    private void init(Context context, AttributeSet attrs) {
          this.context = context;
          setWillNotDraw(false);//需要调用这个方法来清除flag,使之可以重写onDraw();
          setClipChildren(false);
          setClipToPadding(false);
          addTab();
    }
}

注:clipToPadding就是说控件的绘制区域是否在padding里面的,true的情况下如果你设置了padding那么绘制的区域就往里 缩,clipChildren是指子控件是否超过padding区域,这两个属性默认是true的。

private void addTab() {
        //这里是得到两个tab,当然你也可以用new TextView的方法,我这里方便省事
        View leftView = LayoutInflater.from(context).inflate(R.layout.layout_tab_selector, null);
        View rightView = LayoutInflater.from(context).inflate(R.layout.layout_tab_selector, null);
        TextView leftText = (TextView) leftView.findViewById(R.id.tv_tab_title);
        TextView rightText = (TextView) rightView.findViewById(R.id.tv_tab_title);
        leftView.setTag(0);
        rightView.setTag(1);
        leftText.setTextColor(selectorTabColor);
        rightText.setTextColor(noSelectorTabColor);
        leftText.setText(leftTab);
        rightText.setText(rightTab);
        setOrientation(HORIZONTAL);
        LayoutParams layoutParams = new LayoutParams(0, FrameLayout.LayoutParams.MATCH_PARENT, 1.0f);
        addView(leftView, 0, layoutParams);
        addView(rightView, 1, layoutParams);
        leftView.setOnClickListener(this);
        rightView.setOnClickListener(this);

        views.add(leftView);
        views.add(rightView);
    }

2.初始化完成后,执行onDraw()的方法;

     //绘制矩形,圆角矩形等图形的时候,使用GradientDrawable比较方便;
    private GradientDrawable mIndicatorDrawable = new GradientDrawable();//绘制Indicator
    private GradientDrawable mRectDrawable = new GradientDrawable();//绘制按钮外形
    private Rect mIndicatorRect = new Rect();//Indicator的显示区域
    private int currentItem = 0;//默认初始化左边
   @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        height = getHeight();//得到控件的高度
        width = getWidth();
        int paddingLeft = getPaddingLeft();
        //draw rect
        mRectDrawable.setColor(ContextCompat.getColor(context, android.R.color.white));
        mRectDrawable.setStroke(strokeWidth, strokeColor);
        mRectDrawable.setCornerRadius(getHeight() / 2);
        //设置外形的范围
        mRectDrawable.setBounds(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom());
        mRectDrawable.draw(canvas);
        if (mIsFirstDraw) {//判断是否是第一次加载(如果不执行动画,不需要判断)
            mIsFirstDraw = false;
            calcIndicatorRect();
        }
        //draw indicator
        mIndicatorDrawable.setColor(indicatorColor);
        //这里面的2是线宽
        mIndicatorDrawable.setBounds(paddingLeft + 2 + mIndicatorRect.left,
                getPaddingTop() + 2, (int) (paddingLeft + mIndicatorRect.right - 2),
                (getHeight() - getPaddingBottom() - 2));
        mIndicatorDrawable.setCornerRadii(mRadiusArr);
        mIndicatorDrawable.draw(canvas);
    }
  private void calcIndicatorRect() {
        //计算indicator的大小
        View currentTabView = getChildAt(currentItem);
        float left = currentTabView.getLeft();
        float right = currentTabView.getRight();
        mIndicatorRect.left = (int) left;
        mIndicatorRect.right = (int) right;
        int radio = height / 2;
        //使用GradientDrawable ,绘制圆角矩形的时候,需要设置上下左右四个角的大小
        mRadiusArr[0] = radio;
        mRadiusArr[1] = radio;
        mRadiusArr[2] = radio;
        mRadiusArr[3] = radio;
        mRadiusArr[4] = radio;
        mRadiusArr[5] = radio;
        mRadiusArr[6] = radio;
        mRadiusArr[7] = radio;
    }

以上的代码,显示了一个静态的画面,下面需要显示点击事件了

@Override
    public void onClick(View view) {
     //currentItem = position;这个是没有动画,直接交换位置
        //如果不需要动画的时,直接设置显示区域,绘制右边部分即可,这里不做介绍了,下面是点击动画显示
        int position = (Integer) view.getTag();
        //防止重复点击相同位置
        if (mCurrentTab != position) {
            setCurrentTab(position);
        }
        //选择监听事件
        if (onCheckedChangeListener != null)
            switch (((Integer) view.getTag())) {
                case 0:
                    onCheckedChangeListener.onCheckedChanged(leftTab, true);
                    break;
                case 1:
                    onCheckedChangeListener.onCheckedChanged(rightTab, false);
                    break;
            }
    }

下面的是更换显示区域:

      private void setCurrentTab(int position) {
        //因为是两个,交换下一次的position
        int mLastTab = mCurrentTab;
        mCurrentTab = position;

        //所点击的View,记录下当前的位置信息(即动画的到达位置)
        View clickView = getChildAt(position);
        initTextViewColor(position);//根据position,变换字体的颜色
        mCurrentP.left = clickView .getLeft();
        mCurrentP.right = clickView .getRight();

        //上一次的显示的View,记录位置信息(即动画的开始位置)
        View lastTabView = getChildAt(mLastTab);
        mLastP.left = lastTab.getLeft();
        mLastP.right = lastTab.getRight();

        //点击的时候执行动画
        mValueAnimator.setObjectValues(mLastP, mCurrentP);
        mValueAnimator.setDuration(260);
        mValueAnimator.start();
    }

上文中的mCurrentP和mLastP的来源:

  class IndicatorPoint {
        public float left;
        public float right;
    }
    private IndicatorPoint mCurrentP = new IndicatorPoint();
    private IndicatorPoint mLastP = new IndicatorPoint();

    注:为什么要创建这个类呢?原因:动画执行时,没有具体的对象,即所画的Indicator不是对象

下面开始执行动画了:

1.创建动画被执行的对象

在这里需要使用到动画的 TypeEvaluator 估值器这个类,目的:动画过程的平滑过渡。
如果想要的动画类型是Android系统所未知的,那么通过实现TypeEvaluator接口就能够创建自己的估值器。
(Android系统已知的类型是intfloat或颜色(color),分别有IntEvaluator、FloatEvaluator和ArgbEvaluator类型的评价器所支持)
/**
* fraction 从起始值到结束值的分数,即为根据时间变化的浮点数,从0到1
*/
 class PointEvaluator implements TypeEvaluator<IndicatorPoint> {
        @Override
        public IndicatorPoint evaluate(float fraction, IndicatorPoint startValue, IndicatorPoint endValue) {
            float left = startValue.left + fraction * (endValue.left - startValue.left);
            float right = startValue.right + fraction * (endValue.right - startValue.right);
            IndicatorPoint point = new IndicatorPoint();
            point.left = left;
            point.right = right;
            return point;
        }
    }

注:当ValueAnimator对 象(或ObjectAnimator对象)运行时,它会计算当前的动画播放比例(一个01之间的值),然后根据你所使用的插值类型来计算一个要插入的动 画的版本。插值比例是由TypeEvaluator对象通过fraction参数接收来的,因此在计算动画值的时候,不需要考虑插值。

2.创建动画
(这一步在构造函数中新建最好)
ValueAnimator mValueAnimator = ValueAnimator.ofObject(new PointEvaluator(), mLastP, mCurrentP);
mValueAnimator.addUpdateListener(this);
重写抽象方法:
    @Override
    public void onAnimationUpdate(ValueAnimator valueAnimator) {
        IndicatorPoint p = (IndicatorPoint) valueAnimator.getAnimatedValue();
        mIndicatorRect.left = (int) p.left;
        mIndicatorRect.right = (int) p.right;
        invalidate();
    }

完成

以上就是带有动画的选择按钮(如果有不正确的地方,帮忙指正)

最后参考源:FlycoTabLayout

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值