原创文章
先上一个效果图,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();
记得在切换的时候要改相应的图标的文本颜色,这样看得到效果,这里不贴.