如果标题分割线是竖直的就非常简单了,可以直接使用TabLayout实现;
其实上面的圆角不用咱们考虑,因为activity中间部分整体是一个CardView
只需将title部分自己画出来即可;整个view由四个图形绘制而成:
android自定义view:Paint和Canvas
真个view代码比较连贯,虽然整个view粘贴上来有点乱,但是分开粘贴看上去更乱;
public class MyTabView extends View {
private Paint mPaint;
//左右两遍显示的文字,默认显示左右,setTitle(String leftTitle, String rightTitle)可设置
private String leftText = "左";
private String rightText = "右";
//选中文字颜色、非选中文字颜色、选中背景的颜色、非选中背景的颜色
private int selectedColor, unSelectedColor, selectedBg, unSelectedBg;
//标记选中了那边
private boolean isRightSelected;
//文字大小、尖端宽度
private float textSize, middleWidth;
//左右矩形和左右三角形(在点击事件中要判断点击坐标是否在leftRect,leftPath中,所以需要提为成员变量)
private RectF leftRect, rightRect;
private Path leftPath, rightPath;
//在代码中直接new一个MyTabView实例的时候调用
public MyTabView(Context context) {
this(context, null);
}
//在xml布局文件中调用MyTabView的时候调用
public MyTabView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
/**
* android中可以配置一个主题,从而使一些View即使你不对其进行任何配置,它都会有一些已经默认赋值的属性,这就是主题的功劳。
* View类的后两个构造函数都是与主题相关的,也就是说,在你自定义View时,如果不需要你的View随着主题变化而变化,
* 有前两个构造函数就OK了,但是如果你想你的View随着主题变化而变化,就需要利用后两个构造函数了。
*
* 一个属性可以在多个地方赋值,xml定义,xml中引入style,theme中直接指定,defStyleAttr,defStyleRes 这5个地方。
* 优先级:Xml定义 > xml的style定义 > defStyleAttr > defStyleRes> theme直接定义
*
* @param attrs 属性集合
* @param defStyleAttr
*/
public MyTabView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initXmlAttrs(context, attrs);
initPaint();
}
private void initXmlAttrs(Context context, AttributeSet attrs) {
//获取自定义属性
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyTabView);
if (typedArray == null) return;
selectedColor = typedArray.getColor(R.styleable.MyTabView_selected_text_color, Color.parseColor("#17acf6"));
unSelectedColor = typedArray.getColor(R.styleable.MyTabView_un_select_text_color, Color.parseColor("#7d7d7d"));
selectedBg = typedArray.getColor(R.styleable.MyTabView_selected_bg, Color.parseColor("#ff0000"));
unSelectedBg = typedArray.getColor(R.styleable.MyTabView_un_selected_bg, Color.parseColor("#aa00ff00"));
textSize = typedArray.getDimension(R.styleable.MyTabView_text_size, 36);
middleWidth = typedArray.getDimension(R.styleable.MyTabView_middle_path_width, 100);
}
//初始化画笔
private void initPaint() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(3);
}
@Override
//对视图进行绘制
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
initPaintColor(unSelectedBg, selectedBg);
/**
* ①在整个view左边画一个矩形,宽度是view的一半减去中间path宽度的一半
*/
leftRect = new RectF(0, 0, (getWidth() - middleWidth) / 2.0f, getHeight());
canvas.drawRect(leftRect, mPaint);
/**
* ②按着第一个矩形绘制一个三角形
*/
leftPath = new Path();
//将起点移至矩形右上角位置 绘制三角形
leftPath.moveTo((getWidth() - middleWidth) / 2.0f, 0);
leftPath.lineTo((getWidth() - middleWidth) / 2.0f, getHeight());
leftPath.lineTo((getWidth() + middleWidth) / 2.0f, getHeight());
//回到初始点形成封闭的曲线
leftPath.close();
//将path画到画布上,到此为止左边一半已经画好
canvas.drawPath(leftPath, mPaint);
//切换画笔颜色
initPaintColor(selectedBg, unSelectedBg);
/**
* ③按着第一个三角形绘制第二个三角形
*/
rightPath = new Path();
rightPath.moveTo((getWidth() - middleWidth) / 2.0f, 0);
rightPath.lineTo((getWidth() + middleWidth) / 2.0f, 0);
rightPath.lineTo((getWidth() + middleWidth) / 2.0f, getHeight());
rightPath.close();
canvas.drawPath(rightPath, mPaint);
/**
* ④按着第二个三角形绘制第二个矩形
* getWidth()/2.0f + middleWidth/2.0f
*/
rightRect = new RectF((getWidth() + middleWidth) / 2.0f, 0, getWidth(), getHeight());
canvas.drawRect(rightRect, mPaint);
//到此位置左右模块搞定,切换画笔颜色,画文字
initPaintColor(unSelectedColor, selectedColor);
//设置字体大小
mPaint.setTextSize(textSize);
//测量文字最小范围
Rect leftTextRect = new Rect();
mPaint.getTextBounds(leftText, 0, leftText.length(), leftTextRect);
//设置居中
mPaint.setTextAlign(Paint.Align.CENTER);
//在左半边找到居中点画文本
canvas.drawText(leftText, getWidth() / 2.0f / 2.0f, getHeight() / 2.0f + leftTextRect.height() / 2.0f, mPaint);
//因为右边和左边文字颜色正好相反,所以需要切换颜色
initPaintColor(selectedColor, unSelectedColor);
Rect roundTextRect = new Rect();
mPaint.getTextBounds(rightText, 0, rightText.length(), roundTextRect);
canvas.drawText(rightText, getWidth() / 2.0f + getWidth() / 2.0f / 2.0f, getHeight() / 2.0f + leftTextRect.height() / 2.0f, mPaint);
}
//上面已经把所有的图形文本画完了,下面需要自定义监听,监听左右点击时间,自定义监听还是老三步
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
float x = event.getX();
float y = event.getY();
Point point = new Point((int) x, (int) y);
//选中了左边
if (leftRect.contains(x, y) || pointInPath(leftPath, point)) {
isRightSelected = false;
//自定义监听第三步
mListener.isLeftClicked(true);
} else {//选中了右边
isRightSelected = true;
mListener.isLeftClicked(false);
}
//在主线程中刷新view
invalidate();
}
return true;
}
private OnTabClickedListener mListener;
//自定义监听第二步
public void setOnTabClickListener(OnTabClickedListener mListener) {
this.mListener = mListener;
}
//自定义监听第一步
public interface OnTabClickedListener {
void isLeftClicked(boolean isLeft);
}
//设置title,刷新布局
public void setTitle(String leftTitle, String rightTitle) {
this.leftText = leftTitle;
this.rightText = rightTitle;
/**
* 两个方法都是刷新View,前者只能在主线程使用,后者无限制
*/
invalidate();
// postInvalidate();
}
//初始化画笔画笔的颜色
private void initPaintColor(int colorTrue, int colorFalse) {
if (isRightSelected)
mPaint.setColor(colorTrue);
else
mPaint.setColor(colorFalse);
}
//判断path是否包含point
private boolean pointInPath(Path path, Point point) {
RectF bounds = new RectF();
path.computeBounds(bounds, true);
Region region = new Region();
region.setPath(path, new Region((int) bounds.left, (int) bounds.top, (int) bounds.right, (int) bounds.bottom));
return region.contains(point.x, point.y);
}
}
myTabView= (MyTabView) findViewById(R.id.mytabview);
myTabView.setTitle("签约单查询","签约单到期");
myTabView.setOnTabClickListener(new MyTabView.OnTabClickedListener() {
@Override
public void isLeftClicked(boolean isLeft) {
if (isLeft)
etOrg.setText("当前点击左边");
else
etOrg.setText("当前点击右边");
}
});
点击打开链接免费下载源码