編輯:關於Android編程
先來看看我們今天要實現的一個效果圖:

整個效果很簡單,就是在屏幕上顯示一個鐘表,該鐘表可以自動走動。
OK,那就開始動工吧。
首先,要實現這個時鐘,我得繼承自View來自己繪制時鐘,因為這種效果沒有辦法繼承已有控件去完善功能。然後我們來看看我們這裡需要哪些變量?在這篇博客中我暫時不打算介紹自定義屬性以及View的測量,這裡我只想介紹繪圖API,所以View的大小以及鐘表表針的顏色等我都暫時先給一個固定的值。OK,那麼我們需要的變量主要就是下面幾個:
/**
* 繪制表盤的畫筆
*/
private Paint circlePaint;
/**
* 繪制表盤數字
*/
private Paint numPaint;
/**
* 繪制表心
*/
private Paint dotPaint;
/**
* 時針
*/
private Paint hourPaint;
/**
* 分針
*/
private Paint minutePaint;
/**
* 秒針
*/
private Paint secondPaint;
/**
* View寬度,默認256dp
*/
private int width;
/**
* View高度,默認256dp
*/
private int height;
/**
* 日歷類,用來獲取當前時間
*/
private Calendar calendar;
/**
* 當前時針顏色
*/
private int hourColor;
/**
* 當前分針顏色
*/
private int minuteColor;
/**
* 當前秒針顏色
*/
private int secondColor;
/**
* 時針寬度
*/
private int hourWidth;
/**
* 分針寬度
*/
private int minuteWidth;
/**
* 秒針寬度
*/
private int secondWidth;
大家看到,當我繼承View之後,系統要求我實現它的構造方法,構造方法主要有四個,如下:
1.
public ClockView(Context context)
2.
public ClockView(Context context, AttributeSet attrs)
3.
public ClockView(Context context, AttributeSet attrs, int defStyleAttr)
很多筒子看到第三個參數defStyleAttr之後,誤以為如果我在布局文件中寫了style就會調用該構造方法,其實不然,這個構造方法系統並不會自己去調用(大家有興趣可以自己寫一個style,然後在這個方法中打印日志,看看該方法究竟會不會調用),要由我們自己顯式調用(可以在第二個構造方法中調用)。那麼這裡的defStyleAttr究竟是什麼意思呢?正如這個參數的字面意思,它是我們為自定義的View指定的一個默認樣式。(後面博客我們再來詳細說一下這個方法)。
另外,還有一個高版本使用的構造方法,我們這裡暫不做介紹。
一般情況下,我們需要在構造方法中完成一些初始化的操作,比如讀取在XML文件中定義的屬性,或者初始化畫筆等等,因為我們的控件既有可能是通過Java代碼實例化的,也有可能是在布局文件中通過xml添加的。如前所述,如果我們在Java代碼中初始化控件,那麼將調用第一個構造方法,如果我們在xml布局文件中添加控件,那麼將調用第二個構造方法。這時問題來了,那我們的初始化控件的方法應該寫在那個構造方法中呢?你可以按下面這種方式來寫:
public ClockView(Context context) {
super(context);
initView();
}
public ClockView(Context context, AttributeSet attrs) {
super(context,attrs);
initView();
}
//在代碼中創建控件時調用
public ClockView(Context context) {
this(context, null);
}
//在布局文件中創建View時調用
public ClockView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ClockView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
我們在准備工作中定義了許多變量,包括鐘表的顏色,指針的顏色等等許多變量,那麼接下來我們需要在initView這個方法中來初始化這些變量,以供下一步使用,OK,我們來看一看初始化代碼:
private void initView() {
//獲取當前時間的實例
calendar = Calendar.getInstance();
//時鐘默認寬高
width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 256, getResources().getDisplayMetrics());
height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 256, getResources().getDisplayMetrics());
//初始化表針的顏色
hourColor = Color.RED;
minuteColor = Color.GREEN;
secondColor = Color.BLUE;
//初始化表針的寬度
hourWidth = 8;
minuteWidth = 5;
secondWidth = 2;
//初始化各種畫筆
circlePaint = new Paint();
//去鋸齒
circlePaint.setAntiAlias(true);
//設置畫筆顏色
circlePaint.setColor(Color.GREEN);
//設置畫筆style為描邊
circlePaint.setStyle(Paint.Style.STROKE);
//設置描邊的寬度
circlePaint.setStrokeWidth(6);
dotPaint = new Paint();
dotPaint.setAntiAlias(true);
dotPaint.setColor(Color.RED);
dotPaint.setStyle(Paint.Style.FILL);
numPaint = new Paint();
numPaint.setColor(Color.RED);
numPaint.setAntiAlias(true);
//文本對齊方式
numPaint.setTextAlign(Paint.Align.CENTER);
hourPaint = new Paint();
hourPaint.setColor(hourColor);
hourPaint.setStyle(Paint.Style.FILL);
hourPaint.setStrokeWidth(hourWidth);
minutePaint = new Paint();
minutePaint.setColor(minuteColor);
minutePaint.setStyle(Paint.Style.FILL);
minutePaint.setStrokeWidth(minuteWidth);
secondPaint = new Paint();
secondPaint.setColor(secondColor);
secondPaint.setStyle(Paint.Style.FILL);
secondPaint.setStrokeWidth(secondWidth);
}
上面所有的工作做完之後,接下來就是繪制鐘表了,繪制工作我們放在了onDraw方法中執行,在自定義控件時,如果該控件是我們繼承自View來實現的,那麼基本上這個控件就是需要我們自己來繪制了。
OK,那我們來看看鐘表的繪制吧。
鐘表不算復雜,但是我們也需要一步一步來:
首先是繪制表盤,這個最簡單:
//1.圓心X軸坐標,2.圓心Y軸坐標,3.半徑,4.畫筆
int radius = width / 2 - 10;
//畫表盤
canvas.drawCircle(width / 2, height / 2, radius, circlePaint);
圓環畫好之後,那麼接下來就是繪制表心了,也就是表盤正中心那個紅色的圓心。
canvas.drawCircle(width / 2, height / 2, 15, dotPaint);
OK,兩個最簡單的東東畫完之後,那麼接下來就是繪制表盤的時間刻度了,時間刻度的繪制除了數字之外,還有一個綠色的短線,我們一共要畫十二個這種東西,那麼這個要怎麼繪制呢?思路有很多,你可以按照高中的數學知識,計算出每一個數字的坐標以及每一個短線起始位置和結束位置的坐標,然後繪制出來,毫無疑問,這種方式的計算量太大,那我們這裡采取一個簡單的方式:我每次只在十二點的那個位置上進行繪制,如果需要繪制一點,那麼我把畫布逆時針旋轉30度到十二點的位置,然後畫上1和一個短線之後再將畫布順時針旋轉30度,如果是繪制2點,那麼我把畫布逆時針旋轉60度到十二點的位置,然後繪制上2和一個短線,繪制完成之後再將畫布順時針旋轉60度,思路就是這樣,下面我們來看看代碼:
for (int i = 1; i < 13; i++) {
//在旋轉之前保存畫布狀態
canvas.save();
canvas.rotate(i * 30, width / 2, height / 2);
//1.2表示起點坐標,3.4表示終點坐標,5.畫筆
canvas.drawLine(width / 2, height / 2 - radius, width / 2, height / 2 - radius + 10, circlePaint);
//畫表盤數字1.要繪制的文本,2.文本x軸坐標,3.文本基線,4.文本畫筆
canvas.drawText(i + "", width / 2, height / 2 - radius + 22, numPaint);
//恢復畫布狀態
canvas.restore();
}
OK,這些東西都繪制完成之後,接下來就該繪制表針了,表針的繪制思路和上面一樣,也是先旋轉表盤,然後繪制表針,繪制完成之後,再把表盤旋轉回之前的狀態。這裡我就不再詳細說明了,大家看代碼:
//獲得當前小時
int hour = calendar.get(Calendar.HOUR);
canvas.save();
//旋轉屏幕
canvas.rotate(hour * 30, width / 2, height / 2);
//畫時針
canvas.drawLine(width / 2, height / 2 + 20, width / 2, height / 2 - 90, hourPaint);
canvas.restore();
int minute = calendar.get(Calendar.MINUTE);
canvas.save();
canvas.rotate(minute * 6, width / 2, height / 2);
canvas.drawLine(width / 2, height / 2 + 30, width / 2, height / 2 - 110, minutePaint);
canvas.restore();
int second = calendar.get(Calendar.SECOND);
canvas.save();
canvas.rotate(second * 6, width / 2, height / 2);
canvas.drawLine(width / 2, height / 2 + 40, width / 2, height / 2 - 130, secondPaint);
canvas.restore();
1.開始處添加:
calendar = Calendar.getInstance();
2.結束處添加:
postInvalidateDelayed(1000);
OK,至此,我們的自定義鐘表就完成了,完整的代碼應該是這個樣子:
/**
* Created by wangsong on 2016/3/29.
*/
public class ClockView extends View {
/**
* 繪制表盤的畫筆
*/
private Paint circlePaint;
/**
* 繪制表盤數字
*/
private Paint numPaint;
/**
* 繪制表心
*/
private Paint dotPaint;
/**
* 時針
*/
private Paint hourPaint;
/**
* 分針
*/
private Paint minutePaint;
/**
* 秒針
*/
private Paint secondPaint;
/**
* View寬度,默認256dp
*/
private int width;
/**
* View高度,默認256dp
*/
private int height;
/**
* 日歷類,用來獲取當前時間
*/
private Calendar calendar;
/**
* 當前時針顏色
*/
private int hourColor;
/**
* 當前分針顏色
*/
private int minuteColor;
/**
* 當前秒針顏色
*/
private int secondColor;
/**
* 時針寬度
*/
private int hourWidth;
/**
* 分針寬度
*/
private int minuteWidth;
/**
* 秒針寬度
*/
private int secondWidth;
//在代碼中創建控件時調用
public ClockView(Context context) {
this(context, null);
}
//在布局文件中創建View時調用
public ClockView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ClockView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
//獲取當前時間的實例
calendar = Calendar.getInstance();
//時鐘默認寬高
width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 256, getResources().getDisplayMetrics());
height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 256, getResources().getDisplayMetrics());
//初始化表針的顏色
hourColor = Color.RED;
minuteColor = Color.GREEN;
secondColor = Color.BLUE;
//初始化表針的寬度
hourWidth = 8;
minuteWidth = 5;
secondWidth = 2;
//初始化各種畫筆
circlePaint = new Paint();
//去鋸齒
circlePaint.setAntiAlias(true);
//設置畫筆顏色
circlePaint.setColor(Color.GREEN);
//設置畫筆style為描邊
circlePaint.setStyle(Paint.Style.STROKE);
//設置描邊的寬度
circlePaint.setStrokeWidth(6);
dotPaint = new Paint();
dotPaint.setAntiAlias(true);
dotPaint.setColor(Color.RED);
dotPaint.setStyle(Paint.Style.FILL);
numPaint = new Paint();
numPaint.setColor(Color.RED);
numPaint.setAntiAlias(true);
//文本對齊方式
numPaint.setTextAlign(Paint.Align.CENTER);
hourPaint = new Paint();
hourPaint.setColor(hourColor);
hourPaint.setStyle(Paint.Style.FILL);
hourPaint.setStrokeWidth(hourWidth);
minutePaint = new Paint();
minutePaint.setColor(minuteColor);
minutePaint.setStyle(Paint.Style.FILL);
minutePaint.setStrokeWidth(minuteWidth);
secondPaint = new Paint();
secondPaint.setColor(secondColor);
secondPaint.setStyle(Paint.Style.FILL);
secondPaint.setStrokeWidth(secondWidth);
}
//繪制View
@Override
protected void onDraw(Canvas canvas) {
calendar = Calendar.getInstance();
//1.圓心X軸坐標,2.圓心Y軸坐標,3.半徑,4.畫筆
int radius = width / 2 - 10;
//畫表盤
canvas.drawCircle(width / 2, height / 2, radius, circlePaint);
canvas.drawCircle(width / 2, height / 2, 15, dotPaint);
for (int i = 1; i < 13; i++) {
//在旋轉之前保存畫布狀態
canvas.save();
canvas.rotate(i * 30, width / 2, height / 2);
//1.2表示起點坐標,3.4表示終點坐標,5.畫筆
canvas.drawLine(width / 2, height / 2 - radius, width / 2, height / 2 - radius + 10, circlePaint);
//畫表盤數字1.要繪制的文本,2.文本x軸坐標,3.文本基線,4.文本畫筆
canvas.drawText(i + "", width / 2, height / 2 - radius + 22, numPaint);
//恢復畫布狀態
canvas.restore();
}
//獲得當前小時
int hour = calendar.get(Calendar.HOUR);
canvas.save();
//旋轉屏幕
canvas.rotate(hour * 30, width / 2, height / 2);
//畫時針
canvas.drawLine(width / 2, height / 2 + 20, width / 2, height / 2 - 90, hourPaint);
canvas.restore();
int minute = calendar.get(Calendar.MINUTE);
canvas.save();
canvas.rotate(minute * 6, width / 2, height / 2);
canvas.drawLine(width / 2, height / 2 + 30, width / 2, height / 2 - 110, minutePaint);
canvas.restore();
int second = calendar.get(Calendar.SECOND);
canvas.save();
canvas.rotate(second * 6, width / 2, height / 2);
canvas.drawLine(width / 2, height / 2 + 40, width / 2, height / 2 - 130, secondPaint);
canvas.restore();
//每隔1秒重繪View,重繪會調用onDraw()方法
postInvalidateDelayed(1000);
}
}
Android編程獲取GPS數據的方法詳解
本文實例講述了Android編程獲取GPS數據的方法。分享給大家供大家參考,具體如下:GPS是Android系統中重要的組成部分,通過它可以衍生出眾多的與位置相關的應用。
Android Gradle Build Error:Some file crunching failed, see logs for details解決辦法
Android Gradle Build Error:Some file crunching failed, see logs for details解決辦法錯誤日志:E
RecyclerView 上拉加載更多以及下拉刷新
RecyclerView 已經出來很久了,但是在項目中之前都使用的是ListView,最近新的項目上了都大量的使用了RecycleView.尤其是瀑布流的下拉刷新,網上吧
一個手機號能注冊多個微信嗎 手機號注冊兩個微信號方法
一個手機號可以注冊兩個微信嗎?很多人還不知道一個手機號怎麼注冊2個甚至多個微信號,下面小編就跟大家分享一下方法吧!一個手機號怎麼注冊兩個微信: 登錄你(已