My Life with Android
Introduction Android Componets UserInterface Advanced UI Data Storage Advanced Concepts Others New Studio

TriangleRectangleLabelView

res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="TriangleRectangleLabelView">
        <attr name="trlvIsLeft" format="boolean" />
        <attr name="trlvIsShowCircle" format="boolean" />
        <attr name="trlvIsShowLine" format="boolean" />
        <attr name="trlvIsDrawRoundRect" format="boolean" />
        <attr name="trlvBgColor" format="color" />
        <attr name="trlvLineColor" format="color" />
        <attr name="trlvCircleColor" format="color" />
        <attr name="trlvCircleSpaceRectangle" format="dimension" />
        <attr name="trlvCircleRadius" format="dimension" />
        <attr name="trlvLineWidth" format="dimension" />
        <attr name="trlvRoundRectWidth" format="dimension" />
        <attr name="trlvRoundRectRadius" format="dimension" />
    </declare-styleable>
</resources>
package bytecoe.testyourjavaskill.ui;

/**
 * Created by Dell on 1/17/2016.
 */
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.widget.TextView;
import bytecoe.testyourjavaskill.R;

/**
 * Author:    ZhuWenWu
 * Version    V1.0
 * Date:      14-12-13 21:38
 * Description: ????????
 * Modification  History:
 * Date         	Author        		Version        	Description
 * -----------------------------------------------------------------------------------
 * 14-12-13      ZhuWenWu            1.0                    1.0
 * Why & What is modified:
 */
public class TriangleRectangleLabelView extends TextView {
    private static final String TAG = TriangleRectangleLabelView.class.getSimpleName();

    private static final int DEFAULT_BG_COLOR = 0xff41c7cd;
    private static final int DEFAULT_CIRCLE_COLOR = 0xffffffff;
    private static final int DEFAULT_LINE_COLOR = 0xfffb9ece;
    private static final int DEFAULT_HEIGHT = 30;//dp
    private static final int DEFAULT_WIDTH = 70;//dp
    private static final int DEFAULT_ROUND_RECT_RADIUS = 8;//px
    private static final int DEFAULT_ROUND_RECT_WIDTH = 8;//px

    private Paint mBgPaint;
    private Paint mCirclePaint;
    private Paint mLinePaint;

    private int mRoundRectWidth = DEFAULT_ROUND_RECT_WIDTH;//??????
    private int mRoundRectRadius = DEFAULT_ROUND_RECT_RADIUS;//??????
    private int mCircleRadius = 8;//????
    private int mCircleSpaceRectangle = 16;//????????
    private int mSpaceHeight = 8;//??????
    private int mLineWidth = 2;//????

    private int mBgColor = DEFAULT_BG_COLOR;//????
    private int mLineColor = DEFAULT_LINE_COLOR;//?????
    private int mCircleColor = DEFAULT_CIRCLE_COLOR;//????

    private LINE_MODE mLineMode = LINE_MODE.MIDDLE;//????

    private boolean isShowLine = false;//??????
    private boolean isShowCircle = true;//??????
    private boolean isDrawRoundRect = true;//????????
    private boolean isLeft = true;//????????

    private boolean isFirstPadding = true;

    public static enum LINE_MODE {
        START, MIDDLE, END
    }

    public TriangleRectangleLabelView(Context context) {
        this(context, null);
    }

    public TriangleRectangleLabelView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TriangleRectangleLabelView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        initAttrs(attrs);
        init();
    }

    private void initAttrs(AttributeSet attrs) {
        if (attrs != null) {
            TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.TriangleRectangleLabelView);

            mBgColor = a.getColor(R.styleable.TriangleRectangleLabelView_trlvBgColor, mBgColor);
            mLineColor = a.getColor(R.styleable.TriangleRectangleLabelView_trlvLineColor, mLineColor);
            mCircleColor = a.getColor(R.styleable.TriangleRectangleLabelView_trlvCircleColor, mCircleColor);

            isLeft = a.getBoolean(R.styleable.TriangleRectangleLabelView_trlvIsLeft, isLeft);
            isShowLine = a.getBoolean(R.styleable.TriangleRectangleLabelView_trlvIsShowLine, isShowLine);
            isShowCircle = a.getBoolean(R.styleable.TriangleRectangleLabelView_trlvIsShowCircle, isShowCircle);
            isDrawRoundRect = a.getBoolean(R.styleable.TriangleRectangleLabelView_trlvIsDrawRoundRect, isDrawRoundRect);

            mCircleRadius = a.getDimensionPixelSize(R.styleable.TriangleRectangleLabelView_trlvCircleRadius, mCircleRadius);
            mCircleSpaceRectangle = a.getDimensionPixelSize(R.styleable.TriangleRectangleLabelView_trlvCircleSpaceRectangle, mCircleSpaceRectangle);
            mLineWidth = a.getDimensionPixelSize(R.styleable.TriangleRectangleLabelView_trlvLineWidth, mLineWidth);
            mRoundRectWidth = a.getDimensionPixelSize(R.styleable.TriangleRectangleLabelView_trlvRoundRectWidth, mRoundRectWidth);
            mRoundRectRadius = a.getDimensionPixelSize(R.styleable.TriangleRectangleLabelView_trlvRoundRectRadius, mRoundRectRadius);

            DisplayMetrics dm = getResources().getDisplayMetrics();
            int minHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_HEIGHT, dm);
            int minWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_WIDTH, dm);
            setMinHeight(minHeight);
            setMinWidth(minWidth);
            a.recycle();
        }
    }

    private void init() {
        mBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mBgPaint.setStrokeWidth(4);
        mBgPaint.setStyle(Paint.Style.FILL);
        mBgPaint.setColor(mBgColor);
        mBgPaint.setAntiAlias(true);

        mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mCirclePaint.setStrokeWidth(1);
        mCirclePaint.setStyle(Paint.Style.FILL);
        mCirclePaint.setColor(mCircleColor);
        mCirclePaint.setAntiAlias(true);

        mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mLinePaint.setStrokeWidth(mLineWidth);
        mLinePaint.setStyle(Paint.Style.FILL);
        mLinePaint.setColor(mLineColor);
        mLinePaint.setAntiAlias(true);
    }

    /**
     * ????????
     *
     * @param roundRectWidth px
     */
    public void setRoundRectWidth(int roundRectWidth) {
        this.mRoundRectWidth = roundRectWidth;
        postInvalidate();
    }

    /**
     * ??????????
     *
     * @param roundRectRadius px
     */
    public void setRoundRectRadius(int roundRectRadius) {
        this.mRoundRectRadius = roundRectRadius;
        postInvalidate();
    }

    public void setBgColor(int color) {
        mBgColor = color;
        mBgPaint.setColor(mBgColor);
        postInvalidate();
    }

    public void setLineColor(int color) {
        mLineColor = color;
        mLinePaint.setColor(getContext().getResources().getColor(mLineColor));
        postInvalidate();
    }

    /**
     * ???????
     *
     * @param lineMode LINE_MODE: START, MIDDLE, END
     */
    public void setLineMode(LINE_MODE lineMode) {
        this.mLineMode = lineMode;
        postInvalidate();
    }

    /**
     * ???????
     *
     * @param isLeft true:left false:right
     */
    public void setLeft(boolean isLeft) {
        this.isLeft = isLeft;
        postInvalidate();
    }

    /**
     * ?? View ????
     *
     * @param spaceHeight px
     */
    public void setSpaceHeight(int spaceHeight) {
        this.mSpaceHeight = spaceHeight;
        isFirstPadding = true;
        postInvalidate();
    }

    /**
     * ??????????
     *
     * @param circleSpaceRectangle px
     */
    public void setCircleSpaceRectangle(int circleSpaceRectangle) {
        this.mCircleSpaceRectangle = circleSpaceRectangle;
        isFirstPadding = true;
        postInvalidate();
    }

    /**
     * ??????
     *
     * @param circleRadius px
     */
    public void setCircleRadius(int circleRadius) {
        this.mCircleRadius = circleRadius;
        isFirstPadding = true;
        postInvalidate();
    }

    /**
     * ???????
     *
     * @param lineWidth px
     */
    public void setLineWidth(int lineWidth) {
        this.mLineWidth = lineWidth;
        mLinePaint.setStrokeWidth(mLineWidth);
        postInvalidate();
    }

    public void setShowLine(boolean isShowLine) {
        this.isShowLine = isShowLine;
        postInvalidate();
    }

    public void setShowCircle(boolean isShowCircle) {
        this.isShowCircle = isShowCircle;
        postInvalidate();
    }

    public void setDrawRoundRect(boolean isDrawRoundRect) {
        this.isDrawRoundRect = isDrawRoundRect;
        postInvalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        drawBackground(canvas);
        super.onDraw(canvas);
    }

    private void drawBackground(Canvas canvas) {
        int height = getHeight();
        int width = getWidth();
        Log.d(TAG, "height = " + height);
        Log.d(TAG, "width = " + width);

        Log.d(TAG, "isFirstPadding = " + isFirstPadding);
        //-------------------Set Text Padding Begin----------------------------//
        if (isFirstPadding) {
            int paddingLeft = mCircleRadius * 2 + mCircleSpaceRectangle + (height - mSpaceHeight) / 2 + 2;
            setPadding(isLeft ? paddingLeft : mRoundRectWidth, mSpaceHeight + 4, isLeft ? mRoundRectWidth + 4 : paddingLeft, mSpaceHeight + 4);
            setGravity(Gravity.CENTER_VERTICAL);
            isFirstPadding = false;
        }
        //-------------------Set Text Padding End----------------------------//

        //-------------------Draw Line Begin----------------------------//
        int startLineX = isShowLine ? (isLeft ? mCircleRadius : width - mCircleRadius) : 0;
        if (isShowLine) {
            if (mLineMode == LINE_MODE.START) {
                canvas.drawLine(startLineX, height / 2, startLineX, height, mLinePaint);
            } else if (mLineMode == LINE_MODE.MIDDLE) {
                canvas.drawLine(startLineX, height, startLineX, 0, mLinePaint);
            } else if (mLineMode == LINE_MODE.END) {
                canvas.drawLine(startLineX, height / 2, startLineX, 0, mLinePaint);
            }
        }
        //-------------------Draw Line End----------------------------//

        //-------------------Draw Circle Begin----------------------------//
        int startCircleX = isShowCircle ? (isLeft ? mCircleRadius : width - mCircleRadius) : 0;
        if (isShowCircle) {
            canvas.drawCircle(startCircleX, height / 2, mCircleRadius, mCirclePaint);
        }
        //-------------------Draw Circle End----------------------------//


        //-------------------Draw RoundRect Begin----------------------------//
        int roundLeft = isDrawRoundRect ? (isLeft ? width - mRoundRectWidth : 0) : 0;
        int roundRight = isDrawRoundRect ? (isLeft ? width : mRoundRectWidth) : 0;

        if (isDrawRoundRect) {
            //draw RoundRect
            RectF rect = new RectF();
            rect.left = roundLeft;
            rect.top = mSpaceHeight;
            rect.right = roundRight;
            rect.bottom = height - mSpaceHeight;
            canvas.drawRoundRect(rect, mRoundRectRadius, mRoundRectRadius, mBgPaint);
        }
        //-------------------Draw RoundRect End----------------------------//

        //-------------------Draw Triangle And Rectangle Begin----------------------------//
        if (isLeft) {
            //draw Triangle And Rectangle
            int startX = mCircleSpaceRectangle + 2 * mCircleRadius;
            Point a = new Point(startX, height / 2);
            Point b = new Point(startX + (height - mSpaceHeight) / 2, height - mSpaceHeight);
            Point c = new Point(width - (isDrawRoundRect ? mRoundRectWidth / 2 : 0), height - mSpaceHeight);
            Point d = new Point(width - (isDrawRoundRect ? mRoundRectWidth / 2 : 0), mSpaceHeight);
            Point e = new Point(startX + (height - mSpaceHeight) / 2, mSpaceHeight);
            Point f = new Point(startX, height / 2);

            Path path = new Path();
            path.moveTo(a.x, a.y);
            path.lineTo(b.x, b.y);
            path.lineTo(c.x, c.y);
            path.lineTo(d.x, d.y);
            path.lineTo(e.x, e.y);
            path.lineTo(f.x, f.y);

            canvas.drawPath(path, mBgPaint);

        } else {
            //draw Triangle And Rectangle
            int startX = width - (mCircleSpaceRectangle + 2 * mCircleRadius);
            Point a = new Point(startX, height / 2);
            Point b = new Point(startX - (height - mSpaceHeight) / 2, height - mSpaceHeight);
            Point c = new Point((isDrawRoundRect ? mRoundRectWidth / 2 : 0), height - mSpaceHeight);
            Point d = new Point((isDrawRoundRect ? mRoundRectWidth / 2 : 0), mSpaceHeight);
            Point e = new Point(startX - (height - mSpaceHeight) / 2, mSpaceHeight);
            Point f = new Point(startX, height / 2);

            Path path = new Path();
            path.moveTo(a.x, a.y);
            path.lineTo(b.x, b.y);
            path.lineTo(c.x, c.y);
            path.lineTo(d.x, d.y);
            path.lineTo(e.x, e.y);
            path.lineTo(f.x, f.y);

            canvas.drawPath(path, mBgPaint);
        }
        //-------------------Draw Triangle And Rectangle End----------------------------//
    }
}

res/layout/main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center_horizontal"
    android:background="#842ff4"
    tools:context=".MainActivity">

    <bytecoe.testyourjavaskill.ui.TriangleRectangleLabelView
        android:id="@+id/trv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#fff"
        android:singleLine="true"
        android:text="Nice"
        app:trlvIsLeft="false"
        app:trlvCircleRadius="4dp"
        android:textSize="16sp"
        android:layout_marginLeft="48dp"
        android:layout_marginTop="50dp"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <bytecoe.testyourjavaskill.ui.TriangleRectangleLabelView
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#fff"
        android:singleLine="true"
        android:text="Label 1"
        android:layout_below="@id/trv_name"
        android:textSize="16sp"
        android:layout_toEndOf="@id/trv_name"
        android:layout_toRightOf="@id/trv_name"
        app:trlvIsLeft="true"
        app:trlvCircleRadius="4dp"
        app:trlvBgColor="#ff000000"
        app:trlvCircleColor="#ffffff"
        app:trlvRoundRectRadius="12dp"
        app:trlvRoundRectWidth="10dp" />

    <bytecoe.testyourjavaskill.ui.TriangleRectangleLabelView
        android:id="@+id/trlv1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#fff"
        android:singleLine="true"
        android:text="Label2"
        android:textSize="16sp"
        android:layout_centerVertical="true"
        android:layout_toEndOf="@id/trv_name"
        android:layout_toRightOf="@id/trv_name"
        app:trlvIsLeft="true"
        app:trlvCircleRadius="4dp"
        app:trlvBgColor="#72ddbf"
        app:trlvCircleColor="#95e8cd"
        app:trlvIsShowLine="true" />

    <bytecoe.testyourjavaskill.ui.TriangleRectangleLabelView
        android:id="@+id/trlv2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#fff"
        android:singleLine="true"
        android:text="Label3"
        android:textSize="16sp"
        android:layout_below="@id/trlv1"
        android:layout_toEndOf="@id/trv_name"
        android:layout_toRightOf="@id/trv_name"
        app:trlvIsLeft="true"
        app:trlvCircleRadius="4dp"
        app:trlvBgColor="#a596d6"
        app:trlvCircleColor="#b6b2db"
        app:trlvIsShowLine="true" />

    <bytecoe.testyourjavaskill.ui.TriangleRectangleLabelView
        android:id="@+id/trlv3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#fff"
        android:singleLine="true"
        android:text="Label4"
        android:textSize="16sp"
        android:layout_below="@id/trlv2"
        android:layout_toEndOf="@id/trv_name"
        android:layout_toRightOf="@id/trv_name"
        app:trlvIsLeft="true"
        app:trlvCircleRadius="4dp"
        app:trlvBgColor="#efbe78"
        app:trlvCircleColor="#f1cf9e"
        app:trlvIsShowLine="true" />

    <bytecoe.testyourjavaskill.ui.TriangleRectangleLabelView
        android:id="@+id/trlv4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#fff"
        android:singleLine="true"
        android:text="Label5"
        android:textSize="16sp"
        android:layout_below="@id/trlv3"
        android:layout_toEndOf="@id/trv_name"
        android:layout_toRightOf="@id/trv_name"
        app:trlvIsLeft="true"
        app:trlvCircleRadius="4dp"
        app:trlvBgColor="#f96bbc"
        app:trlvCircleColor="#fc9dcf"
        app:trlvIsShowLine="true" />
</RelativeLayout>
src/MainActivity.java
package bytecoe.testyourjavaskill.ui;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;

import bytecoe.testyourjavaskill.R;

/**
 * Created by Dell on 1/17/2016.
 */
public class Example  extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.example);
        ((TriangleRectangleLabelView)findViewById(R.id.trlv1)).setLineMode(TriangleRectangleLabelView.LINE_MODE.START);
        ((TriangleRectangleLabelView)findViewById(R.id.trlv2)).setLineMode(TriangleRectangleLabelView.LINE_MODE.MIDDLE);
        ((TriangleRectangleLabelView)findViewById(R.id.trlv3)).setLineMode(TriangleRectangleLabelView.LINE_MODE.MIDDLE);
        ((TriangleRectangleLabelView)findViewById(R.id.trlv4)).setLineMode(TriangleRectangleLabelView.LINE_MODE.END);
    }
}

App types