android:自定义view--MyTabView

android:自定义view--MyTabView_第1张图片

如果标题分割线是竖直的就非常简单了,可以直接使用TabLayout实现;

其实上面的圆角不用咱们考虑,因为activity中间部分整体是一个CardView

只需将title部分自己画出来即可;整个view由四个图形绘制而成:

android:自定义view--MyTabView_第2张图片

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);
    }

}

设置自定义属性需要在styles.xml中声明:

    
        
        
        
        
        
        
    

然后在布局文件中赋值:

            

最后在页面使用非常简单:

        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("当前点击右边");
            }
        });



点击打开链接免费下载源码

你可能感兴趣的:(自定义view)