編輯:關於Android編程
關於自定義View,相信多數開發者都已經非常熟悉了,網絡上的例子也非常多,各種炫酷吊炸天的自定義View也層出不窮。本文只是一個初級學習教程,對於初學者有參考價值。
下面正式進入主題。
本文采用自定義View的方式實現柱狀統計圖BarGraphView,實現了柱狀統計圖的基本功能,因為本身是為了學習自定義View,因此擴展性比較差,只能作為自定義View的參考。
上效果圖:
View顯示到屏幕上主要經過這三個過程
(1)Measure(測量)
首先View需要測量自身的大小,包括長和寬。 當View類的成員函數measure決定要重新測量當前View的寬度和高度之後,會去調用另外一個成員函數onMeasure來真正執行測量寬度和高度的操作。因此,自定義View大多都需要覆寫onMeasure方法來測量View的大小。onMeasure方法如下:
@Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); }
(2)Layout(布局)
這個過程只在View容器(ViewGroup及其子類)有用,因為非容器類View在屏幕中的位置操作由父控件來決定,所以不需要覆寫onLayout()方法。
(3)Draw(繪制)
最後繪制View的過程,在這個過程裡主要通過Paint對象在Canvas上面繪制相應圖像,最終把View展現在屏幕上。 對於自定義View來說,通常需要覆寫onDraw()方法繪制View。
@Override public void onDraw(Canvas canvas) { }該方法提供了一塊畫布,我們只需要創建一個畫筆在畫布上繪圖案即可。
好了,了解了上述過程,接下來我們開始實現BarGraphView。
BarGraphView主要代碼集中在Draw的過程,通過onDraw方法把統計圖繪制到屏幕上來。
經過分析,把柱狀圖分為以下幾部分
1.橫/縱坐標軸
2.橫/縱坐標軸刻度線
3.橫/縱坐標軸刻度值
4.橫/縱坐標軸箭頭
5.標題
6.柱狀圖
針對不同部分利用drawLine()(畫直線)、drawText()(畫文字)、drawPath()(畫多邊形)以及drawRect()(畫矩形)的方法分別繪制相應圖案。
以下是BarGraphView類代碼,可以直接看注釋。
package com.eleven.demo.widget; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.util.AttributeSet; import android.view.View; import com.eleven.demo.R; /** * Created by Eleven on 2015/5/3. */ public class BarGraphView extends View { private final String TAG = BarGraphView.class.getName(); //畫筆 private Paint mPaint; //標題 private String title; //標題顏色 private int titleColor; //標題大小 private float titleSize; //X坐標軸最大值 private float maxAxisValueX = 900; //X坐標軸刻度線數量 private int axisDivideSizeX = 9; //Y坐標軸最大值 private float maxAxisValueY = 700; //Y坐標軸刻度線數量 private int axisDivideSizeY = 7; //視圖寬度 private int width; //視圖高度 private int height; //坐標原點位置 private final int originX = 100; private final int originY = 800; //柱狀圖數據 private int columnInfo[][]; public BarGraphView(Context context, AttributeSet attrs) { super(context, attrs); //創建畫筆 mPaint = new Paint(); //獲取配置的屬性值 TypedArray mArray = context.obtainStyledAttributes(attrs, R.styleable.BarGraphView); title = mArray.getString(R.styleable.BarGraphView_barGraph_title); titleColor = mArray.getColor(R.styleable.BarGraphView_barGraph_titleColor, Color.BLACK); titleSize = mArray.getDimension(R.styleable.BarGraphView_barGraph_titleSize, 36); } /** * 設置X軸的最大值及刻度線數量(包括0坐標刻度) * * @param maxValue X軸的最大值 * @param divideSize 刻度線數量 */ public void setAxisX(float maxValue, int divideSize) { maxAxisValueX = maxValue; axisDivideSizeX = divideSize; } /** * 設置Y軸的最大值及刻度線數量(包括0坐標刻度) * * @param maxValue Y軸的最大值 * @param divideSize 刻度線數量 */ public void setAxisY(float maxValue, int divideSize) { maxAxisValueY = maxValue; axisDivideSizeY = divideSize; } /** * 設置柱狀圖數據 * * @param columnInfo */ public void setColumnInfo(int[][] columnInfo) { this.columnInfo = columnInfo; } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); width = MeasureSpec.getSize(widthMeasureSpec) - 200; height = MeasureSpec.getSize(heightMeasureSpec) - 800; } @Override public void onDraw(Canvas canvas) { drawAxisX(canvas, mPaint); drawAxisY(canvas, mPaint); drawAxisScaleMarkX(canvas, mPaint); drawAxisScaleMarkY(canvas, mPaint); drawAxisArrowsX(canvas, mPaint); drawAxisArrowsY(canvas, mPaint); drawAxisScaleMarkValueX(canvas, mPaint); drawAxisScaleMarkValueY(canvas, mPaint); drawColumn(canvas, mPaint); drawTitle(canvas, mPaint); } /** * 繪制橫坐標軸(X軸) * * @param canvas * @param paint */ private void drawAxisX(Canvas canvas, Paint paint) { paint.setColor(Color.BLACK); //設置畫筆寬度 paint.setStrokeWidth(5); //設置畫筆抗鋸齒 paint.setAntiAlias(true); //畫橫軸(X) canvas.drawLine(originX, originY, originX + width, originY, paint); } /** * 繪制縱坐標軸(Y軸) * * @param canvas * @param paint */ private void drawAxisY(Canvas canvas, Paint paint) { //畫豎軸(Y) canvas.drawLine(originX, originY, originX, originY - height, paint);//參數說明:起始點左邊x,y,終點坐標x,y,畫筆 } /** * 繪制橫坐標軸刻度線(X軸) * * @param canvas * @param paint */ private void drawAxisScaleMarkX(Canvas canvas, Paint paint) { float cellWidth = width / axisDivideSizeX; for (int i = 0; i < axisDivideSizeX - 1; i++) { canvas.drawLine(cellWidth * (i + 1) + originX, originY, cellWidth * (i + 1) + originX, originY - 10, paint); } } /** * 繪制縱坐標軸刻度線(Y軸) * * @param canvas * @param paint */ private void drawAxisScaleMarkY(Canvas canvas, Paint paint) { float cellHeight = height / axisDivideSizeY; for (int i = 0; i < axisDivideSizeY - 1; i++) { canvas.drawLine(originX, (originY - cellHeight * (i + 1)), originX + 10, (originY - cellHeight * (i + 1)), paint); } } /** * 繪制橫坐標軸刻度值(X軸) * * @param canvas * @param paint */ private void drawAxisScaleMarkValueX(Canvas canvas, Paint paint) { //設置畫筆繪制文字的屬性 paint.setColor(Color.GRAY); paint.setTextSize(28); paint.setFakeBoldText(true); float cellWidth = width / axisDivideSizeX; float cellValue = maxAxisValueX / axisDivideSizeX; for (int i = 1; i < axisDivideSizeX; i++) { canvas.drawText(String.valueOf(cellValue * i), cellWidth * i + originX - 35, originY + 30, paint); } } /** * 繪制縱坐標軸刻度值(Y軸) * * @param canvas * @param paint */ private void drawAxisScaleMarkValueY(Canvas canvas, Paint paint) { float cellHeight = height / axisDivideSizeY; float cellValue = maxAxisValueY / axisDivideSizeY; for (int i = 1; i < axisDivideSizeY; i++) { canvas.drawText(String.valueOf(cellValue * i), originX - 80, originY - cellHeight * i + 10, paint); } } /** * 繪制橫坐標軸箭頭(X軸) * * @param canvas * @param paint */ private void drawAxisArrowsX(Canvas canvas, Paint paint) { //畫三角形(X軸箭頭) Path mPathX = new Path(); mPathX.moveTo(originX + width + 30, originY);//起始點 mPathX.lineTo(originX + width, originY - 10);//下一點 mPathX.lineTo(originX + width, originY + 10);//下一點 mPathX.close(); canvas.drawPath(mPathX, paint); } /** * 繪制縱坐標軸箭頭(Y軸) * * @param canvas * @param paint */ private void drawAxisArrowsY(Canvas canvas, Paint paint) { //畫三角形(Y軸箭頭) Path mPathX = new Path(); mPathX.moveTo(originX, originY - height - 30);//起始點 mPathX.lineTo(originX - 10, originY - height);//下一點 mPathX.lineTo(originX + 10, originY - height);//下一點 mPathX.close(); canvas.drawPath(mPathX, paint); } /** * 繪制柱狀圖 * * @param canvas * @param paint */ private void drawColumn(Canvas canvas, Paint paint) { if(columnInfo == null) return; float cellWidth = width / axisDivideSizeX; for (int i = 0; i < columnInfo.length; i++) { paint.setColor(columnInfo[i][1]); float leftTopY = originY - height * columnInfo[i][0] / maxAxisValueY; canvas.drawRect(originX + cellWidth * (i + 1), leftTopY, originX + cellWidth * (i + 2), originY, mPaint);//左上角x,y右下角x,y,畫筆 } } /** * 繪制標題 * * @param canvas * @param paint */ private void drawTitle(Canvas canvas, Paint paint) { //畫標題 if (title != null) { //設置畫筆繪制文字的屬性 mPaint.setColor(titleColor); mPaint.setTextSize(titleSize); mPaint.setFakeBoldText(true); canvas.drawText(title, 300, originY + 150, paint); } } }
MainActivity的布局文件:
public class MainActivity extends ActionBarActivity { private BarGraphView mBarGraphView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView(){ mBarGraphView = (BarGraphView)findViewById(R.id.custom_view); mBarGraphView.setAxisX(900, 9); mBarGraphView.setAxisY(700,7); int columnInfo[][] = new int[][]{{600, Color.BLUE},{500, Color.GREEN},{400, Color.RED},{300, Color.BLUE}, {500, Color.YELLOW},{300, Color.LTGRAY},{200, Color.BLUE}}; mBarGraphView.setColumnInfo(columnInfo); }
本想自己寫一個的,但是看到這篇之後,我想還是轉過來吧,實在是非常的詳細:在Android系統中,發一個狀態欄通知還是很方便的。下面我們就來看一下,怎麼發送狀態欄通知,狀態
前言:多年之前接觸過zxing實現二維碼,沒想到今日項目中再此使用竟然使用的還是zxing,百度之,竟是如此牛的玩意。當然,項目中我們也許只會用到二維碼的掃描和生成兩個功
WebSocket protocol 是HTML5一種新的協議。它實現了浏覽器與服務器全雙工通信(full-duplex)。WebSocket是Web2.0時代的新產物,
做過電商類應用的朋友可能都會遇到一個比較頭疼的問題:復雜的首頁布局如何實現。參考百度糯米,美團,bilibili等應用,都會發現其首頁的布局相對復雜,例如下圖bilibi