自定义一个背景可以滚动的tab栏

来源:互联网 发布:ld3320语音识别算法 编辑:程序博客网 时间:2024/06/05 20:37

原创文章

先上一个效果图,GIF录制的图片有严重的掉帧现象,其实效果还是很流畅的.

此文要说的是上方的切换的时候的白色背景滚动效果.其他内容本文没有说明.

可以看到上方有一个长方形的tab,有两个选项,分别为"美丽店","技术达人",

点击技术达人的时候,后面的白色背景会滚动到右边,点击美丽店的时候,又滚动到左边.

写这个空间的原因是因为要配合fragment的切换动画,这样看起来感觉效果好一点

此效果是通过自定义ViewGroup实现的,并不是通过动画实现,实现起来还是比较简单,本文最后会加上完整代码


首先先说下实现方式,继承一个ViewGroup,这里继承的是LinearLayout,(命名我命名为tabLinearLayout,不知道对不对,将就着用就行了)

然后根据大小画一个白色圆角描边,然后在左半边画纯白背景,右半边透明.

在点击的时候,只要改变一下白色背景的位置,还有上方的文字颜色和图标,其他不用动


1.定义四种状态,代码有注释

/** * 背景状态 */protected enum StateBG {    /**     * 静止在左边     */    LEFT_STATIC,    /**     * 静止在右边     */    RIGHT_STATIC,    /**     * 从左边滚动到右边     */    LEFT_TO_RIGHT,    /**     * 从右边滚动到左边     */    RIGHT_TO_LEFT;}

后面的onDraw()开始写自己的逻辑

2.绘制白色描边

/** * 画圆角背景,画白色描边 * * @param canvas * @param height * @param width */private void drawBg(Canvas canvas, int height, int width) {    mPaint.setStyle(Paint.Style.STROKE);//设置空心    // 设置个新的长方形    if (lineBgRectF == null) {        lineBgRectF = new RectF(0, 0, width, height);    }    canvas.drawRoundRect(lineBgRectF, ROUND_SIZE, ROUND_SIZE, mPaint);//第二个参数是x半径,第三个参数是y半径}
这里圆角为10px
ROUND_SIZE = 10;

3.0判断状态,然后绘制半边白色的位置

mPaint.setStyle(Paint.Style.FILL);//设置实心if (oneHalfBg == null) {    oneHalfBg = new RectF(0, 0, width / 2, height);}switch (state) {    case LEFT_STATIC:        oneHalfBg.left = 0;        drawHalfBg(canvas, height, width);        break;    case RIGHT_STATIC:        oneHalfBg.left = width / 2;        drawHalfBg(canvas, height, width);        break;    case LEFT_TO_RIGHT:        oneHalfBg.left += MOVE_RATE_PX;        break;    case RIGHT_TO_LEFT:        oneHalfBg.left -= MOVE_RATE_PX;        break;}

此时判断状态,

3.1.

因为是有圆角效果的,所以在最左右静止和在最右边静止的时候,中间附近还是有圆角效果的,此时并不需要这个效果


所以会在中间贴一个没有圆角的白色矩形

private RectF whiteHalfBg;private void drawHalfBg(Canvas canvas, int height, int width) {    if (whiteHalfBg == null) {        whiteHalfBg = new RectF(0, 0, 0, height);    }    //直角矩形的宽度    int rectfWidth = 10;    if (state == LEFT_STATIC) {        whiteHalfBg.left = width / 2 - rectfWidth;        whiteHalfBg.right = width / 2;    } else if (state == RIGHT_STATIC) {        whiteHalfBg.left = width / 2;        whiteHalfBg.right = width / 2 + rectfWidth;    }    canvas.drawRect(whiteHalfBg, mPaint);}
3.2从左往右滑动,或者从右往左滑动

除了3.0内的代码,后面还需要加上

oneHalfBg.right = oneHalfBg.left + width / 2;//设置右边位置(显示宽)canvas.drawRoundRect(oneHalfBg, ROUND_SIZE, ROUND_SIZE, mPaint);//第二个参数是x半径,第三个参数是y半径if (state == LEFT_TO_RIGHT || state == RIGHT_TO_LEFT) {    invalidate();}if (oneHalfBg.left < 0) state = LEFT_STATIC;if (oneHalfBg.left > width / 2) state = RIGHT_STATIC;

也就是不断绘制白色,并且设置好白色下一次绘制的位置,等下一次绘制,直到到了最左边或者最右边的时候,把状态改一下,使其不再绘制.


到此白色背景滚动效果基本完成了,但是有一点要注意,因为这个是继承viewgroup的,所以onDraw方法不会被调用,所以要在layout的xml控件处添加

android:background="@color/transparent"

设置一个透明背景,使其调用ondraw()方法.或者用其他方式使其调用即可


下面贴上完整代码:

1.Java代码


import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.RectF;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.widget.LinearLayout;import com.orhanobut.logger.Logger;import static com.hoyar.beautyshop.view.TabLinearLayout.StateBG.LEFT_STATIC;import static com.hoyar.beautyshop.view.TabLinearLayout.StateBG.LEFT_TO_RIGHT;import static com.hoyar.beautyshop.view.TabLinearLayout.StateBG.RIGHT_STATIC;import static com.hoyar.beautyshop.view.TabLinearLayout.StateBG.RIGHT_TO_LEFT;/** * 可供标签切换的layout */public class TabLinearLayout extends LinearLayout {    public TabLinearLayout(Context context) {        super(context);    }    public TabLinearLayout(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);    }    private final Paint mPaint = new Paint();    {        mPaint.setAntiAlias(true);//设置抗锯齿        mPaint.setColor(Color.WHITE);    }    public TabLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    private StateBG state = StateBG.LEFT_STATIC;    //白色背景描边    private RectF lineBgRectF;    //一半的背景图片    private RectF oneHalfBg;    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        int height = getMeasuredHeight();        int width = getMeasuredWidth();        drawBg(canvas, height, width);        mPaint.setStyle(Paint.Style.FILL);//设置实心        if (oneHalfBg == null) {            oneHalfBg = new RectF(0, 0, width / 2, height);        }        switch (state) {            case LEFT_STATIC:                oneHalfBg.left = 0;                drawHalfBg(canvas, height, width);                break;            case RIGHT_STATIC:                oneHalfBg.left = width / 2;                drawHalfBg(canvas, height, width);                break;            case LEFT_TO_RIGHT:                oneHalfBg.left += MOVE_RATE_PX;                break;            case RIGHT_TO_LEFT:                oneHalfBg.left -= MOVE_RATE_PX;                break;        }        oneHalfBg.right = oneHalfBg.left + width / 2;//设置右边位置(显示宽)        canvas.drawRoundRect(oneHalfBg, ROUND_SIZE, ROUND_SIZE, mPaint);//第二个参数是x半径,第三个参数是y半径        if (state == LEFT_TO_RIGHT || state == RIGHT_TO_LEFT) {            invalidate();        }        if (oneHalfBg.left < 0) state = LEFT_STATIC;        if (oneHalfBg.left > width / 2) state = RIGHT_STATIC;        Logger.d("ondraw()了");    }    private static final int MOVE_RATE_PX = 8;    private RectF whiteHalfBg;    private void drawHalfBg(Canvas canvas, int height, int width) {        if (whiteHalfBg == null) {            whiteHalfBg = new RectF(0, 0, 0, height);        }        //直角矩形的宽度        int rectfWidth = 10;        if (state == LEFT_STATIC) {            whiteHalfBg.left = width / 2 - rectfWidth;            whiteHalfBg.right = width / 2;        } else if (state == RIGHT_STATIC) {            whiteHalfBg.left = width / 2;            whiteHalfBg.right = width / 2 + rectfWidth;        }        canvas.drawRect(whiteHalfBg, mPaint);    }    public void leftToRight() {        state = LEFT_TO_RIGHT;        invalidate();    }    public void rightToLeft() {        state = RIGHT_TO_LEFT;        invalidate();    }    /**     * 画圆角背景,画白色描边     *     * @param canvas     * @param height     * @param width     */    private void drawBg(Canvas canvas, int height, int width) {        mPaint.setStyle(Paint.Style.STROKE);//设置空心        // 设置个新的长方形        if (lineBgRectF == null) {            lineBgRectF = new RectF(0, 0, width, height);        }        canvas.drawRoundRect(lineBgRectF, ROUND_SIZE, ROUND_SIZE, mPaint);//第二个参数是x半径,第三个参数是y半径    }    /**     * 圆角的大小     */    private static final int ROUND_SIZE = 10;    /**     * 背景状态     */    protected enum StateBG {        /**         * 静止在左边         */        LEFT_STATIC,        /**         * 静止在右边         */        RIGHT_STATIC,        /**         * 从左边滚动到右边         */        LEFT_TO_RIGHT,        /**         * 从右边滚动到左边         */        RIGHT_TO_LEFT;    }}

使用控件的关键xml代码,中间平分自定义的tabLinearLayout:

<com.hoyar.beautyshop.view.TabLinearLayout    android:id="@+id/fragment_appointment_tab_linear_layout"    android:layout_width="190dp"    android:layout_height="25dp"    android:layout_centerHorizontal="true"    android:layout_marginTop="30dp"    android:background="@color/transparent"    android:orientation="horizontal">    <!--android:background="@drawable/appointment_tab_bg"-->    <!--字体没有标注-->    <RelativeLayout        android:layout_width="0dp"        android:layout_height="match_parent"        android:layout_weight="1">        <TextView            android:id="@+id/fragment_appointment_tv_beauty_shop"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerInParent="true"            android:drawableLeft="@mipmap/appointment_tab_store_sel"            android:drawablePadding="7dp"            android:includeFontPadding="false"            android:text="美丽店"            android:textColor="@color/appointment_blue_bg" />    </RelativeLayout>    <RelativeLayout        android:layout_width="0dp"        android:layout_height="match_parent"        android:layout_weight="1">        <TextView            android:id="@+id/fragment_appointment_tv_master"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerInParent="true"            android:drawableLeft="@mipmap/appointment_tab_master"            android:drawablePadding="7dp"            android:includeFontPadding="false"            android:text="技术达人"            android:textColor="@color/white" />    </RelativeLayout></com.hoyar.beautyshop.view.TabLinearLayout>

外部调用背景切换的代码

执行右往左动画:

tabLinearLayout.rightToLeft();
执行左往右动画:

tabLinearLayout.leftToRight();

记得在切换的时候要改相应的图标的文本颜色,这样看得到效果,这里不贴.



0 0
原创粉丝点击