Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android自定義控件(狀態提示圖表)

Android自定義控件(狀態提示圖表)

編輯:關於Android編程

 

1 背景

前面分析那麼多系統源碼了,也該暫停下來休息一下,趁昨晚閒著看見一個有意思的需求就操練一下分析源碼後的實例演練—-自定義控件。

這個實例很適合新手入門自定義控件。先看下效果圖:

橫屏模式如下:
這裡寫圖片描述
豎屏模式如下:
這裡寫圖片描述

看見沒有,這個控件完全自定義的,連文字等都是自定義的,沒有任何圖片等資源,就僅僅是一個小的java文件,這個界面只有一個控件。如下咱們看下實現代碼。

!!!!!!! 下載Demo工程源碼點擊我<喎?/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPjwvcD4NCjxwPqG+uaS9s8j0y64gaHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFuYm9iZXIg16rU2Lezx+vXosP3s/a0pqOs1/DW2LfWz+2zybn7ob88L3A+DQo8aDIgaWQ9"2-實例代碼">2 實例代碼

如下就是整個工程的源碼了。

自定義上面展示的控件AreaChartsView源碼:

/**
 * Author       : yanbo
 * Date         : 2015-06-03
 * Time         : 09:22
 * Description  : 自定義區域描述圖表View
 */
public class AreaChartsView extends View {
    private Paint mPaint;

    private int[] mZeroPos = new int[2];
    private int[] mMaxYPos = new int[2];
    private int[] mMaxXPos = new int[2];

    private int mWidth, mHight;
    private int mRealWidth, mRealHight;
    private String mTitleY, mTitleX;

    private ArrayList mXLevel = new ArrayList<>();
    private ArrayList mYLevel = new ArrayList<>();
    private ArrayList mGridLevelText = new ArrayList<>();
    private ArrayList mGridColorLevel = new ArrayList<>();
    private ArrayList mGridTxtColorLevel = new ArrayList<>();

    private int mGridLevel = mXLevel.size() - 1;

    //title字符大小
    private int mXYTitleTextSize = 40;

    private int mMeasureXpos, mMeasureYpos;

    public AreaChartsView(Context context, AttributeSet attrs) {
        super(context, attrs);

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setAntiAlias(true);
        mPaint.setFilterBitmap(true);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        mWidth = getWidth();
        mHight = getHeight();
    }

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

        initPosition();
        drawXYTitle(canvas);
        drawXYLine(canvas);
        drawContent(canvas);
    }

    private void initPosition() {
        //初始化坐標圖的xy交點原點坐標
        mZeroPos[0] = mXYTitleTextSize * 2;
        mZeroPos[1] = mHight - mXYTitleTextSize * 4;
        //初始化坐標圖的X軸最大值坐標
        mMaxXPos[0] = mWidth;
        mMaxXPos[1] = mHight - mXYTitleTextSize * 4;
        //初始化坐標圖的Y軸最大值坐標
        mMaxYPos[0] = mXYTitleTextSize * 2;
        mMaxYPos[1] = mXYTitleTextSize * 2;
    }

    private void drawXYTitle(Canvas canvas) {
        mPaint.setColor(Color.parseColor(#1FB0E7));
        mPaint.setTextSize(mXYTitleTextSize);
        mPaint.setTextAlign(Paint.Align.LEFT);
        //畫Y軸頂的title
        canvas.drawText(mTitleY, mMaxYPos[0] - mXYTitleTextSize * 2, mMaxYPos[1] - mXYTitleTextSize, mPaint);
        mPaint.setTextAlign(Paint.Align.RIGHT);
        //畫X軸頂的title
        canvas.drawText(mTitleX, mMaxXPos[0], mMaxXPos[1] + mXYTitleTextSize * 2, mPaint);
    }

    private void drawXYLine(Canvas canvas) {
        mPaint.setColor(Color.DKGRAY);
        mPaint.setTextAlign(Paint.Align.RIGHT);
        //畫XY軸
        canvas.drawLine(mMaxYPos[0], mMaxYPos[1], mZeroPos[0], mZeroPos[1], mPaint);
        canvas.drawLine(mZeroPos[0], mZeroPos[1], mMaxXPos[0], mMaxXPos[1], mPaint);
    }

    private void drawContent(Canvas canvas) {
        mGridLevel = mXLevel.size() - 1;
        //計算出偏移title等顯示尺標後的真實XY軸長度,便於接下來等分
        mRealWidth = (mWidth - mXYTitleTextSize * 2);
        mRealHight = (mHight - mXYTitleTextSize * 4);
        //算出等分間距
        int offsetX = mRealWidth/(mGridLevel);
        int offsetY = mRealHight/(mGridLevel+1);
        //循環繪制content
        for (int index=0; index= mXLevel.get(index) && mMeasureXpos < mXLevel.get(index+1)) {
                int subValue = mMeasureXpos - mXLevel.get(index);
                int offset = mXLevel.get(index+1) - mXLevel.get(index);
                realPosX = mZeroPos[0] + index*offsetX + (subValue / offset);
                break;
            }
        }
        //計算傳入的y值與真實屏幕坐標的像素值的百分比差值轉換
        for (int index=0; index= mYLevel.get(index) && mMeasureYpos < mYLevel.get(index+1)) {
                int subValue = mMeasureYpos - mYLevel.get(index);
                int offset = mYLevel.get(index+1) - mYLevel.get(index);
                realPosY = mZeroPos[1] - index*offsetY - (offsetY - (subValue / offset));
                break;
            }
        }
        //畫我們傳入的坐標點的標記小紅點
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(realPosX, realPosY, 8, mPaint);

        int[] centerPos = {mZeroPos[0] + mRealWidth/2, mZeroPos[1] - mRealHight/2};

        mPaint.setColor(Color.WHITE);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        RectF rectF = null;
        Path path = new Path();
        //畫紅點旁邊的提示框和文字,有四個區域,然後提示框的小三角指標方位不同
        if (realPosX <= centerPos[0] && realPosY >= centerPos[1]) {
            //left-bottom
            //畫三角形
            path.moveTo(realPosX+5, realPosY+5);
            path.lineTo(realPosX+15, realPosY+15);
            path.lineTo(realPosX+15, realPosY-15);
            //畫矩形背景
            rectF = new RectF(realPosX+15, realPosY-40, realPosX+200, realPosY + 30);
            canvas.drawRoundRect(rectF, 15, 15, mPaint);
            //畫提示框的文字
            mPaint.reset();
            mPaint.setColor(Color.RED);
            mPaint.setTextSize(mXYTitleTextSize - 5);
            canvas.drawText((+mMeasureXpos+, +mMeasureYpos+), realPosX+30, realPosY, mPaint);
        }
        else if (realPosX <= centerPos[0] && realPosY < centerPos[1]) {
            //left-top
            path.moveTo(realPosX+5, realPosY+5);
            path.lineTo(realPosX+15, realPosY+15);
            path.lineTo(realPosX + 15, realPosY - 15);

            rectF = new RectF(realPosX+15, realPosY - 20, realPosX+200, realPosY + 50);
            canvas.drawRoundRect(rectF, 15, 15, mPaint);

            mPaint.reset();
            mPaint.setColor(Color.RED);
            mPaint.setTextSize(mXYTitleTextSize - 5);
            canvas.drawText((+mMeasureXpos+, +mMeasureYpos+), realPosX+30, realPosY+20, mPaint);
        }
        else if (realPosX > centerPos[0] && realPosY >= centerPos[1]) {
            //right-bottom
            path.moveTo(realPosX-5, realPosY+5);
            path.lineTo(realPosX-15, realPosY+15);
            path.lineTo(realPosX - 15, realPosY - 15);

            rectF = new RectF(realPosX-200, realPosY-40, realPosX-15, realPosY + 30);
            canvas.drawRoundRect(rectF, 15, 15, mPaint);

            mPaint.reset();
            mPaint.setColor(Color.RED);
            mPaint.setTextSize(mXYTitleTextSize - 5);
            canvas.drawText((+mMeasureXpos+, +mMeasureYpos+), realPosX-180, realPosY, mPaint);
        }
        else if (realPosX > centerPos[0] && realPosY < centerPos[1]) {
            //right-top
            path.moveTo(realPosX-5, realPosY+5);
            path.lineTo(realPosX-15, realPosY+15);
            path.lineTo(realPosX - 15, realPosY - 15);

            rectF = new RectF(realPosX-200, realPosY - 20, realPosX-15, realPosY + 50);
            canvas.drawRoundRect(rectF, 15, 15, mPaint);

            mPaint.reset();
            mPaint.setColor(Color.RED);
            mPaint.setTextSize(mXYTitleTextSize - 5);
            canvas.drawText((+mMeasureXpos+, +mMeasureYpos+), realPosX-180, realPosY+30, mPaint);
        }

        path.close();
        mPaint.setColor(Color.WHITE);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        canvas.drawPath(path, mPaint);
    }

    //設置當前比值
    public void updateValues(int x, int y) {
        mMeasureXpos = x;
        mMeasureYpos = y;

        postInvalidate();
    }

    //設置XY軸頂角的title字體大小
    public void setTitleTextSize(int size) {
        mXYTitleTextSize = size;
    }

    //初始化X軸的坐標區間點值,可以不均等分
    public void initXLevelOffset(ArrayList list) {
        mXLevel.clear();
        mXLevel.addAll(list);
    }

    //初始化Y軸的坐標區間點值,可以不均等分
    public void initYLevelOffset(ArrayList list) {
        mYLevel.clear();
        mYLevel.addAll(list);
    }

    //初始化每個區間的提示文字,如果不想顯示可以設置
    public void initGridLevelText(ArrayList list) {
        mGridLevelText.clear();
        mGridLevelText.addAll(list);
    }

    //初始化每個區間的顏色
    public void initGridColorLevel(ArrayList list) {
        mGridColorLevel.clear();
        mGridColorLevel.addAll(list);
    }

    //初始化每個區間的提示文字顏色
    public void initGridTxtColorLevel(ArrayList list) {
        mGridTxtColorLevel.clear();
        mGridTxtColorLevel.addAll(list);
    }

    //初始化XY軸title
    public void initTitleXY(String x, String y) {
        mTitleX = x;
        mTitleY = y;
    }
}

再來看下布局文件:



    

再看看主界面:

public class MainActivity extends AppCompatActivity {
    private AreaChartsView mAreaChartsView;
    private Timer timer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mAreaChartsView = (AreaChartsView) this.findViewById(R.id.area_charts_view);

        //初始化自定義圖表的規格和屬性
        ArrayList mXLevel = new ArrayList<>();
        ArrayList mYLevel = new ArrayList<>();
        ArrayList mGridLevelText = new ArrayList<>();
        ArrayList mGridColorLevel = new ArrayList<>();
        ArrayList mGridTxtColorLevel = new ArrayList<>();
        //初始化x軸坐標區間
        mXLevel.add(0);
        mXLevel.add(60);
        mXLevel.add(90);
        mXLevel.add(100);
        mXLevel.add(110);
        mXLevel.add(120);
        //初始化y軸坐標區間
        mYLevel.add(0);
        mYLevel.add(90);
        mYLevel.add(140);
        mYLevel.add(160);
        mYLevel.add(180);
        mYLevel.add(200);
        //初始化區間顏色
        mGridColorLevel.add(Color.parseColor(#1FB0E7));
        mGridColorLevel.add(Color.parseColor(#4FC7F4));
        mGridColorLevel.add(Color.parseColor(#4FDDF2));
        mGridColorLevel.add(Color.parseColor(#90E9F4));
        mGridColorLevel.add(Color.parseColor(#B2F6F1));
        //初始化區間文字提示顏色
        mGridTxtColorLevel.add(Color.parseColor(#EA8868));
        mGridTxtColorLevel.add(Color.parseColor(#EA8868));
        mGridTxtColorLevel.add(Color.parseColor(#EA8868));
        mGridTxtColorLevel.add(Color.WHITE);
        mGridTxtColorLevel.add(Color.BLACK);
        //初始化區間文字
        mGridLevelText.add(異常);
        mGridLevelText.add(過高);
        mGridLevelText.add(偏高);
        mGridLevelText.add(正常);
        mGridLevelText.add(偏低);

        mAreaChartsView.initGridColorLevel(mGridColorLevel);
        mAreaChartsView.initGridLevelText(mGridLevelText);
        mAreaChartsView.initGridTxtColorLevel(mGridTxtColorLevel);
        mAreaChartsView.initXLevelOffset(mXLevel);
        mAreaChartsView.initYLevelOffset(mYLevel);
        mAreaChartsView.initTitleXY(投入量(H), 產出量(H));
    }

    @Override
    protected void onStart() {
        super.onStart();
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                Random random = new Random();
                int x = random.nextInt(120) % (120 + 1) + 0;
                Random randomy = new Random();
                int y = randomy.nextInt(200) % (200 + 1) + 0;
                //隨機模擬賦值
                mAreaChartsView.updateValues(x, y);
            }
        }, 0, 1000);
    }

    @Override
    protected void onPause() {
        super.onPause();
        timer.cancel();
    }
}

 

3 總結

上面代碼很簡單,核心的都已經注釋了,不需要過多解釋。核心思路就是一些坐標點的計算。該控件支持設置mergin及width與hight等屬性,支持自定義所有顏色及顯示及坐標區分等,唯一缺陷就是沒來得及寫attr屬性xml設置這些值,有興趣的自己實現吧,我是沒時間了。

可以發現,自定義View無非就是重寫前面文章分析的那三個方法而已。

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved