天天看點

安卓自定義控件:畫一個正五邊形

五邊形最後的效果圖:

安卓自定義控件:畫一個正五邊形
/**
 * 自定義一個五邊型,定義5個固定點,然後相連
 * @author guotianhui
 */
public class PentagonView extends View {


    private Paint paint;
    private Context mContext;
    private int mLinesColor;
    private Path path, pathTwo;
    private int mFirstMarginTop; // 設定第一個矩形距離頭部的高度
    private int mSecondMarginTop; //設定第二個矩形距離頭部的高度00
    private int mFirstRecHeight;//設定第一個矩形的高
    private int mSecondRecHight; //設定第二個矩形的高
    private int mDebugTopTextMargin;
    private int mDebugTextLeftMargin; //根據文字的長度,适配左邊文字位置
    private int mDebugTextRightMargin; //根據文字長度,适配右邊文字的間距
    private boolean mIsSetPointColor;
    private int mDebugMargin =dp2px(8);
    private int mHeadLayoutTopMargin ;
    private FrameLayout mHeaderImageView;
    private int mExpainTextColor,mPentagonTextSize;
    private String mPointOneText,mPointTowText,mPointThereText,mPointFourText,mPointFiveText;


    public PentagonView(Context context) {
        super(context);
        this.mContext = context;
    }

    public PentagonView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
    }

    public PentagonView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //動态設定頭像布局距離頂部的距離/
        FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(-2, -2);
        layoutParams.topMargin = mHeadLayoutTopMargin;
        layoutParams.gravity = Gravity.CENTER_HORIZONTAL;
        mHeaderImageView.setLayoutParams(layoutParams);

        //設定五邊形距離頂部的高度,讓頭像始終在布局中間
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(-2, -2);
        params.topMargin =  mHeadLayoutTopMargin -dp2px(75);
        params.gravity = Gravity.CENTER_HORIZONTAL;
        setLayoutParams(params);

        //設定五邊形的外形
        mFirstMarginTop = dp2px(25);
        mSecondMarginTop = mFirstMarginTop +dp2px(15);
        mFirstRecHeight = mHeaderImageView.getWidth()+dp2px( 60);
        mSecondRecHight = mHeaderImageView.getWidth()+dp2px(35);
        //建立一支畫筆
        paint = new Paint();
        paint.setColor(mLinesColor);
        paint.setAntiAlias(true);
        paint.setStrokeWidth(2);
        paint.setStyle(Paint.Style.STROKE);
        //擷取螢幕的寬高
        WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        Display defaultDisplay = windowManager.getDefaultDisplay();
        DisplayMetrics displayMetrics = new DisplayMetrics();
        defaultDisplay.getMetrics(displayMetrics);
        int width = displayMetrics.widthPixels;


        //建立一個路徑
        path = new Path();
        path.moveTo(width/2,mFirstMarginTop+mDebugMargin+dp2px(8)); // 第一個點
        path.lineTo((width/2)-(mFirstRecHeight/2),mFirstRecHeight/2+mFirstMarginTop);//第二個點
        path.lineTo(width/2 -(mFirstRecHeight/3),mFirstMarginTop+mFirstRecHeight+mDebugMargin);//第三個點
        path.lineTo(width/2+(mFirstRecHeight/3) ,mFirstMarginTop+mFirstRecHeight+mDebugMargin);//第四個點
        path.lineTo((width/2)+(mFirstRecHeight/2),mFirstRecHeight/2+mFirstMarginTop);//第五個點
        path.close();
        canvas.drawPath(path,paint);

        //畫一個更大的五邊形
        pathTwo = new Path();
        pathTwo.moveTo(width/2,mSecondMarginTop+mDebugMargin+dp2px(5)); // 第一個點
        pathTwo.lineTo((width/2)-(mSecondRecHight/2),mSecondRecHight/2+mSecondMarginTop);//第二個點
        pathTwo.lineTo(width/2 -(mSecondRecHight/3),mSecondMarginTop+mSecondRecHight+mDebugMargin);//第三個點
        pathTwo.lineTo(width/2+(mSecondRecHight/3) ,mSecondMarginTop+mSecondRecHight+mDebugMargin);//第四個點
        pathTwo.lineTo((width/2)+(mSecondRecHight/2),mSecondRecHight/2+mSecondMarginTop);//第五個點
        pathTwo.close();
        canvas.drawPath(pathTwo,paint);


        //畫五個不同顔色的點
        paint.setStyle(Paint.Style.FILL);
        //是否設定點的不同顔色
        if(mIsSetPointColor) {
            paint.setColor(Color.parseColor("#C84D17"));
            canvas.drawCircle(width / 2, mFirstMarginTop+mDebugMargin+dp2px(8), dp2px(4), paint); // 第一個點
            paint.setAlpha(30);
            canvas.drawCircle(width / 2, mFirstMarginTop+mDebugMargin+dp2px(8), dp2px(8), paint); // 第一個點

            paint.setColor(Color.parseColor("#F9B89B"));
            canvas.drawCircle((width / 2) - (mFirstRecHeight / 2), mFirstRecHeight / 2 + mFirstMarginTop, dp2px(4), paint); //第二個點
            paint.setAlpha(30);
            canvas.drawCircle((width / 2) - (mFirstRecHeight / 2), mFirstRecHeight / 2 + mFirstMarginTop, dp2px(8), paint); //第二個點

            paint.setColor(Color.parseColor("#F19A74"));
            canvas.drawCircle(width / 2 - (mFirstRecHeight / 3), mFirstMarginTop + mFirstRecHeight+mDebugMargin, dp2px(4), paint);//第三個點
            paint.setAlpha(30);
            canvas.drawCircle(width / 2 - (mFirstRecHeight / 3), mFirstMarginTop + mFirstRecHeight+mDebugMargin, dp2px(8), paint);//第三個點

            paint.setColor(Color.parseColor("#E7865B"));
            canvas.drawCircle(width / 2 + (mFirstRecHeight / 3), mFirstMarginTop + mFirstRecHeight+mDebugMargin, dp2px(4), paint);//第四個點
            paint.setAlpha(30);
            canvas.drawCircle(width / 2 + (mFirstRecHeight / 3), mFirstMarginTop + mFirstRecHeight+mDebugMargin, dp2px(8), paint);//第四個點


            paint.setColor(Color.parseColor("#E07140"));
            canvas.drawCircle((width / 2) + (mFirstRecHeight / 2), mFirstRecHeight / 2 + mFirstMarginTop, dp2px(4), paint); //第五個點
            paint.setAlpha(30);
            canvas.drawCircle((width / 2) + (mFirstRecHeight / 2), mFirstRecHeight / 2 + mFirstMarginTop, dp2px(8), paint); //第五個點
        }else{
            paint.setColor(Color.WHITE);
            canvas.drawCircle(width / 2, mFirstMarginTop+mDebugMargin+dp2px(8), dp2px(4), paint); // 第一個點
            canvas.drawCircle((width / 2) - (mFirstRecHeight / 2), mFirstRecHeight / 2 + mFirstMarginTop, dp2px(4), paint); //第二個點
            canvas.drawCircle(width / 2 - (mFirstRecHeight / 3), mFirstMarginTop + mFirstRecHeight+mDebugMargin, dp2px(4), paint);//第三個點
            canvas.drawCircle(width / 2 + (mFirstRecHeight / 3), mFirstMarginTop + mFirstRecHeight+mDebugMargin, dp2px(4), paint);//第四個點
            canvas.drawCircle((width / 2) + (mFirstRecHeight / 2), mFirstRecHeight / 2 + mFirstMarginTop, dp2px(4), paint); //第五個點
        }



        //頂部文字和左邊的文字之間的間距使用mDebugTextMargin參數來微調,文字從左往右逆時針設定的
        paint.setColor(mExpainTextColor); //設定文字顔色
        paint.setTextSize(mPentagonTextSize);//設定文字的大小,文字設定從左往右,逆時針設定
        if(!"".equals(mPointOneText) && mPointOneText != null) {
            getDebugMarginByTextLength(mPointOneText);
            canvas.drawText(mPointOneText, width / 2 -(dp2px(20)+mDebugTopTextMargin), mFirstMarginTop+dp2px(8)-dp2px(5), paint);//青少年
        }
        if(!"".equals(mPointTowText) && mPointTowText != null) {
            getDebugMarginByTextLength(mPointTowText);
            canvas.drawText(mPointTowText,(width / 2 - (mFirstRecHeight/ 2)-mDebugTextLeftMargin),mFirstRecHeight/2+mFirstMarginTop+dp2px(3),paint);//古人
        }
        if(!"".equals(mPointThereText) && mPointThereText != null) {
            getDebugMarginByTextLength(mPointThereText);
            canvas.drawText(mPointThereText,(width / 2 - (mFirstRecHeight/ 2)-mDebugTextLeftMargin)+dp2px(20),mFirstMarginTop+mFirstRecHeight+mDebugMargin+dp2px(3),paint);//繪畫
        }

        //右邊的文字設定間距使用@mDebugLeftTextMargin,來微調右邊文字的間距
        if(!"".equals(mPointFourText) && mPointFourText != null) {
            getDebugMarginByTextLength(mPointFourText);
            canvas.drawText(mPointFourText,width/2+(mFirstRecHeight/3)+mDebugTextRightMargin,mFirstMarginTop+mFirstRecHeight+mDebugMargin+dp2px(3),paint);//實體
        }
        if(!"".equals(mPointFiveText) && mPointFiveText != null) {
            getDebugMarginByTextLength(mPointFiveText);
            canvas.drawText(mPointFiveText,(width/2)+(mFirstRecHeight/2)+mDebugTextRightMargin,mFirstRecHeight/2+mFirstMarginTop+dp2px(3),paint);//科學研究
        }
    }
    /**
     * 根據标簽的長度,微調文字的繪制位置
     */
    private void getDebugMarginByTextLength(String textLength){
        switch (textLength.length()){
            case 2: //标簽兩個文字
                mDebugTopTextMargin = dp2px(-2);
                mDebugTextLeftMargin = dp2px(39);
                mDebugTextRightMargin = dp2px(10);
                break;
            case 3:
                mDebugTopTextMargin = dp2px(2);
                mDebugTextLeftMargin = dp2px(52);
                mDebugTextRightMargin = dp2px(10);
                break;
            case 4: //标簽四個文字
                mDebugTopTextMargin = dp2px(5);
                mDebugTextLeftMargin = dp2px(68);
                mDebugTextRightMargin = dp2px(10);
                break;
                default:{
                    if(textLength.length() >4){
                        mDebugTopTextMargin = dp2px(30);
                        mDebugTextLeftMargin = dp2px(107);
                        mDebugTextRightMargin = dp2px(10);
                    }
                }
                    break;
        }
    }
    /**
     * dp轉px
     * @param dpValue
     * @return
     */
    protected int dp2px(int dpValue){
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dpValue,getResources().getDisplayMetrics());
    }
    /**
     * 提供一個方法,拿到中間的頭像
     */
    public void getHeadPictureMarginTop(FrameLayout headImageView,int topMargin){
         this.mHeaderImageView = headImageView;
         this.mHeadLayoutTopMargin = topMargin;
    }
    /**
     * 定義一個方法,設定五邊形連線的顔色
     */
    public void setPentagonLinesColor(int linesColor){
        this.mLinesColor = linesColor;
    }
    /**
     * 設定五邊形說明文字
     * @param textString
     */
    public void setPentagonViewText(String[] textString){
        if(ObjectUtils.isNotEmpty(textString)) {
            if(textString.length >=1){
                this.mPointOneText = textString[0];
                if(textString.length >= 2){
                    this.mPointFiveText = textString[1];
                    if(textString.length >=3){
                        this.mPointFourText = textString[2];
                        if(textString.length >= 4){
                            this.mPointThereText = textString[3];
                            if(textString.length >=5){
                                this.mPointTowText = textString[4];
                            }
                        }
                    }
                }
            }
        }
    }
    /**
     * 設定五邊形說明文字的字型大小和顔色
     */
    public void setPentagonTextColor(int textColor){
        this.mExpainTextColor = textColor;
    }
    /**
     * 設定五邊形說明文字的大小
     */
    public void setPentagonTextSize(int textSize){
        this.mPentagonTextSize = textSize;
    }
    /**
     * 判斷是否顯示不同點的顔色
     */
    public void isSetFivePointDifferentColor(boolean isDiffColor){
        this.mIsSetPointColor = isDiffColor;
    }
}
           

實作的總體思路是,

1)畫點、連線,主要是這五個點的選擇非常重要,要注意觀察,發現第一個點在螢幕的最中央,還有就是點二、五和三、四是項目對稱的,然後可以根據螢幕的寬和高來确定點的位置,最後定義一個畫筆,把線連起來,最後再各個端點畫一個更大的圓點。

2)點旁邊的文字也是畫出來的,也不難,最主要的是需要調試,文字和點之間的間距。

最後的調用代碼:

if(ObjectUtils.isNotEmpty(label)){
                    String[] labels = label.split(",");
                    //測試資料
                  //  String[]  labelString = {"你好","地方","啥事","好的","近平"};
                    mPentagonView.setPentagonViewText(labels); //标簽逆時針展示
                }
           

我好久沒有寫部落格了,希望對大家有用,謝謝!