Android自定義View:帶背景顏色的TextView和條形圖--(1)
阿新 • • 發佈:2019-02-14
初始:
最近在看《Android群英傳》一書,程式碼自己敲了一遍,想想之前敲了又忘記的慘痛經歷,決定在部落格上記錄自己敲的程式碼,有幾個寫幾篇,放在一個系列裡邊,就這樣,以後看就能一下子找到了。自定義View
自定義View我們大致可以從是三個方面著手:
(1)對現有的控制元件進行擴充套件
(2)通過組合實現全新的控制元件
(3)重寫View來實現全新的
沒怎麼彙總,用到什麼知識就註解解釋了。對現有的控制元件進行擴充套件
基於TextView,繪製邊框和背景顏色
關於Paint和Canvas,他們就相當於畫畫時候的畫筆和畫板,沒有他們我們就不能改變任何東西。
/**
* 基於已有空間上進行修改
* 寫一個TextView 繪製邊框 繪製背景顏色
* @author fanshenxia
* 一個自定義類繼承TextView 重寫構造方法
*/
public class MyTextView extends TextView{
private Paint mPaint,mPaint2;
//這個不太清楚,重寫了就重寫了
public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
//這個構造用於xml檔案中的構造
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
//這個構造方法用於在程式碼中定義控制元件
public MyTextView(Context context) {
super(context);
init();
}
/**
* 初始化畫筆
*/
private void init() {
//例項化畫筆
mPaint = new Paint();
//設定畫筆顏色
mPaint.setColor(Color.CYAN);
//設定它的填充方法,用的多的是FILL 和 STORKE
mPaint.setStyle(Paint.Style.FILL);
mPaint2 = new Paint();
mPaint2.setColor(Color.LTGRAY);
mPaint2.setStyle(Style.FILL);
}
/**
* 重寫onDraw方法 可以在繪製文字前後進行一些自己的操作
* super.onDraw(canvas);呼叫父類方法繪製文字
* 如果繪製矩形的程式碼寫在它的後邊,文字就會被覆蓋
*/
@Override
protected void onDraw(Canvas canvas) {
//在回撥父類方法之前,對TextView來說是繪製文字內容之前
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
//繪製裡層矩形 引數:左、上、右、下、畫筆
//除了繪製矩形,用的多的還可以繪製線,圓,扇形,Path等
canvas.drawRect(10, 10, getMeasuredWidth()-10, getMeasuredHeight()-10, mPaint2);
super.onDraw(canvas);
//繪製文字之後
}
}
XML中MyTextView內容:
<custom.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:padding="10dp"
android:text="我是自定義的控制元件哦~"
android:textSize="20sp"
android:visibility="visible" >
</custom.MyTextView>
執行效果:
總結:可以看到,上述xml中TextView的相關屬性保留著,我們沒有自定義其他的任何屬性,只是添加了邊框和背景。 自定義屬性在下邊呢~
通過組合來實現新的控制元件
這個應該用過吧,平時如果UI給我們的原型圖有好多地方搜尋框都是一樣的,我們會自定義一個控制元件,將它的大體佈局寫好,到用的地方就不用一次一次的寫了。
這個簡單,我沒寫程式碼,以後把它補上。自定義全新的View
這裡實現了三個自定義View,一個條形圖,一個鐘錶繪製,一個百分比圖。先說條形圖。
/**
* 自定義條形圖
*
* @author fanshenxia
*
*/
public class MyBarChartView extends View {
private Context mContext;
// 柱狀的數值
private int mNum = 15;
private Paint mPaint;
public MyBarChartView(Context context) {
super(context);
this.mContext = context;
init();
}
public MyBarChartView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
init();
}
public MyBarChartView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
init();
}
private void init() {
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(2);
mPaint.setAntiAlias(true);
mPaint.setStyle(Style.FILL);
}
/**
重寫onMeasure()方法重新測量控制元件的寬高
測量方式有三種
MeasureSpec.EXACTLY:相當xml中控制元件layout_width="match_parent/固定XXdp"
MeasureSpec.AT_MOST:想當wrap_content,它不能大於父控制元件的寬/高
MeasureSpec.UNSPECIFIED:不指定其大小測量模式,View想多大就多大,一般用於自定義View
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
}
private int measureWidth(int measureSpec) {
int result = 300;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// 指定數值或者match_parent
result = specSize;
} else if (specMode == MeasureSpec.AT_MOST) {
// 為warp_content時
result = Math.min(result, specSize);
} else {
// view想多大就多大
result = 300;
}
return result;
}
private int measureHeight(int measureSpec) {
int result = 400;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// 指定數值或者match_parent
result = specSize;
} else if (specMode == MeasureSpec.AT_MOST) {
// 為warp_content時
result = Math.min(result, specSize);
} else {
// view想多大就多大
result = 400;
}
return result;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
int rectWidth = (width - 60) / mNum - 20;
// 繪製座標線
canvas.drawLine(20, 20, 20, height - 20, mPaint);
canvas.drawLine(getWidth() - 20, getHeight() - 20, 20, getHeight() - 20, mPaint);
int min = 50;
int max = getHeight()-50;
Random random = new Random();
int num = random.nextInt(max) % (max - min + 1) + min;
// 繪製柱體 這裡給的值不是很邏輯的,用的時候需要自己計算後給出相應的值。
for (int i = 0; i < mNum; i++) {
canvas.drawRect(20 + rectWidth * i + 20 * (i + 1), num, 20 + rectWidth * (i + 1) + 20 * (i + 1),
getHeight() - 20, mPaint);
num = random.nextInt(max) % (max - min + 1) + min;
}
//延時重繪,讓條形圖每1s重新整理一次,它走這個方法時 ,只會執行onDraw方法 init那些不執行,Paint的顏色值等都會保留
postInvalidateDelayed(1*1000);
}
}
xml佈局:
<custom.MyBarChartView
android:id="@+id/myBarChartView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
效果:
模擬器效果錄屏效果不太好