編輯:關於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開發 -- 狀態欄通知Notification、NotificationManager詳解
本想自己寫一個的,但是看到這篇之後,我想還是轉過來吧,實在是非常的詳細:在Android系統中,發一個狀態欄通知還是很方便的。下面我們就來看一下,怎麼發送狀態欄通知,狀態
Android項目實戰(二十八):使用Zxing實現二維碼及優化實例
前言:多年之前接觸過zxing實現二維碼,沒想到今日項目中再此使用竟然使用的還是zxing,百度之,竟是如此牛的玩意。當然,項目中我們也許只會用到二維碼的掃描和生成兩個功
Android中使用WebSocket實現群聊和消息推送功能(不使用WebView)
WebSocket protocol 是HTML5一種新的協議。它實現了浏覽器與服務器全雙工通信(full-duplex)。WebSocket是Web2.0時代的新產物,
android開發游記:RecycleView 實現復雜首頁布局三種方式
做過電商類應用的朋友可能都會遇到一個比較頭疼的問題:復雜的首頁布局如何實現。參考百度糯米,美團,bilibili等應用,都會發現其首頁的布局相對復雜,例如下圖bilibi