編輯:關於Android編程
從現在開始,將認真對待寫博客這件事,以前自己寫的博客大多都是作為自己對知識的記錄,可讀性不強,現在不僅作為記錄,也希望把自己知道的一些知識共享,共同進步。
對於Android自定義控件,這是Android開發進階的一個重要技能,從此踏入自定義的門檻。今天就先繼承自View,實現兩個比較基本的自定義控件。先看效果圖:

自定義控件一般需要如下幾步:
1、自定義屬性。因為在自定義控件的過程中往往需要在控件上添加我們自己希望的屬性。
2、在自定義控件中獲取我們自定義的屬性。
3、自定義OnMeasure()方法。(可選,因為系統默認了一個實現方法,許多時候我們並不需要處理這個方法)
4、自定義onDraw()方法。(在屏幕上繪制出控件的模樣)
5、在布局文件中引用類型
由於上面兩個控件自定義的操作步驟是相同的,所以兩個控件就一起說了。
第一步自定義屬性:
每個自定義的屬性都需要給定一個屬性值得類型,幾種類型已經在下面代碼中標識出來<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;">
下面是第二三四步的代碼,首先來看第一個自定義控件的代碼。說明已經在代碼中標注出來,主要實現的是onDraw()方法用來繪制控件,這部分有時候需要考慮的是數學問題,而在這個控件中實現不斷向右滑動就是利用科count的不斷連續性的改變實現的。
public class ProgressView extends View {
//下面的幾個變量用來存儲各個屬性值。
int colorWidth;
int noColorWidth;
int color;
Paint paint;
int count = 0;
int screenWidth;
int speed;
int width;
public ProgressView(Context context) {
super(context);
}
public ProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public ProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
//通過typedArray來獲取各個屬性值
TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.ProgressView);
colorWidth = array.getDimensionPixelSize(R.styleable.ProgressView_colorWidth,20);
noColorWidth = array.getDimensionPixelSize(R.styleable.ProgressView_noColorWidth,20);
color = array.getColor(R.styleable.ProgressView_color, Color.BLUE);
speed = array.getInt(R.styleable.ProgressView_speed,3);
width = array.getDimensionPixelSize(R.styleable.ProgressView_width,10);
//初始化畫筆
paint = new Paint();
paint.setColor(color);
paint.setStrokeWidth(width);
}
@Override
protected void onDraw(Canvas canvas) {
screenWidth = getWidth();
int start = count % (colorWidth + noColorWidth);
start = start - (colorWidth + noColorWidth);
while (start < screenWidth) {
canvas.drawLine(start,getHeight()/2,start+colorWidth,getHeight()/2,paint);
start += colorWidth+noColorWidth;
}
count += speed;
count %= (colorWidth+noColorWidth);
/*
每當繪制一次count增加,然後調用invalidate(),會重新執行onDraw方法,而每次繪制會根據count的值繪制
到不同的位置,從而就達到了動態的效果。
這裡有兩個方法postInvalidate()和invalidate()方法.其中前者是在工作線程中被調用,
而後者在UI線程中被調用
*/
invalidate();
}
}
下面的代碼是實現那個時鐘控件。
package com.zwbin.custom;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;
/**
* Created by wenbin on 16/9/14.
*/
public class ClockView extends View {
int hourColor;
int minuteColor;
int secondColor;
int tableColor;
Paint paint;
public ClockView(Context context) {
super(context);
}
public ClockView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.ClockView);
hourColor = typedArray.getColor(R.styleable.ClockView_hourColor, Color.RED);
minuteColor = typedArray.getColor(R.styleable.ClockView_minuteColor, Color.BLUE);
secondColor = typedArray.getColor(R.styleable.ClockView_secondColor, Color.GREEN);
tableColor = typedArray.getColor(R.styleable.ClockView_tableColor, Color.GRAY);
paint = new Paint();
}
public ClockView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
//開始畫表盤
paint.setColor(tableColor);
paint.setStrokeWidth(3);
paint.setStyle(Paint.Style.STROKE);
int width = getWidth();
int height = getHeight();
int radius = Math.min(width/2,height/2);
canvas.drawCircle(width/2,height/2,radius,paint);
paint.setStrokeWidth(8);
//表盤最長的四條線
for (int i = 0;i < 4;i++) {
double degree = Math.PI/2 * i;
double sin = Math.sin(degree);
double cos = Math.cos(degree);
canvas.drawLine((int)(radius*sin + width/2),
(int)(height/2-radius*cos),
(int)((radius-60)*sin + width/2),
(int)(height/2 - (radius-60)*cos),
paint);
}
//表盤第二長的12條線
for (int i = 0;i < 12;i++) {
double degree = Math.PI/6 * i;
double sin = Math.sin(degree);
double cos = Math.cos(degree);
canvas.drawLine((int)(radius*sin + width/2),
(int)(height/2-radius*cos),
(int)((radius-40)*sin + width/2),
(int)(height/2 - (radius-40)*cos),
paint);
}
//表盤最短的60條線
for (int i = 0;i < 60;i++) {
double degree = Math.PI/30 * i;
double sin = Math.sin(degree);
double cos = Math.cos(degree);
canvas.drawLine((int)(radius*sin + width/2),
(int)(height/2-radius*cos),
(int)((radius-20)*sin + width/2),
(int)(height/2 - (radius-20)*cos),
paint);
}
//開始畫中心點
paint.setStrokeWidth(30);
canvas.drawPoint(width/2,height/2,paint);
Calendar calendar = Calendar.getInstance();
int hour = calendar.get(Calendar.HOUR);
int mimute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
//開始畫時針
int hourRadius = radius/3;
paint.setStrokeWidth(30);
paint.setColor(hourColor);
canvas.drawLine(width/2,
height/2,
(int)(width/2+hourRadius*Math.sin(hour*Math.PI/6)),
(int)(height/2-hourRadius*Math.cos(hour*Math.PI/6)),
paint);
//開始畫分針
int minuteRadius = radius/2;
paint.setStrokeWidth(20);
paint.setColor(minuteColor);
canvas.drawLine(width/2,
height/2,
(int)(width/2+minuteRadius*Math.sin(mimute*Math.PI/30)),
(int)(height/2-minuteRadius*Math.cos(mimute*Math.PI/30)),
paint);
//開始畫秒針
int secondRadius = radius*2/3;
paint.setStrokeWidth(10);
paint.setColor(secondColor);
canvas.drawLine(width/2,
height/2,
(int)(width/2+secondRadius*Math.sin(second*Math.PI/30)),
(int)(height/2-secondRadius*Math.cos(second*Math.PI/30)),
paint);
invalidate();
}
}
可以很明顯得看到,代碼的相似度很高,最主要的區別就是在onDraw中繪制表的部分,這部分是根據相關坐標來繪制圓圈、直線、點組成的。也和上一個自定義控件一樣,每次繪制完成會調用invalidate()來進行重新繪制,表盤位置不變,時針、分針、秒針會根據時間繪制到不同的位置,連續進行繪制就會出現動態移動的效果。
下面進行最後一步,在布局文件中使用。
至此這兩個基礎的控件繪制完成了,下一篇會對這一篇的代碼進行詳解。
ListView的Adapter使用(綁定數據) 之 自定義每一項的布局去綁定數據
大家先看第一個例子顯示: 這個界面相信大家都看到過的,這次比上一個例子多的是ListView 的每一項綁定的是不再是單純的一個字符串了,ListView 的每一個條目我們
Android使用SQLite數據庫的簡單實例
先畫個圖,了解下Android下數據庫操作的簡單流程:1.首先,寫一個自己的數據庫操作幫助類,這個類繼承自Android自帶的SQLiteOpenHelper.2.在自己
【React Native開發】React Native控件之ProgressBarAndroid進度條講解(12)
(一)前言今天我們一起來看一下進度加載條ProgressBarAndroid控件的講解與基本使用。剛創建的React Native技術交流群(282693535),歡迎各
Gradle自定義插件
Gradle自定義插件在Gradle中創建自定義插件,Gradle提供了三種方式:在build.gradle腳本中直接使用 在buildSrc中使用 在獨立Module中