Android利用SurfaceView實(shí)現(xiàn)簡(jiǎn)單計(jì)時(shí)器
自學(xué)了android有幾個(gè)月了,跟著網(wǎng)上的節(jié)奏,應(yīng)該早點(diǎn)寫(xiě)些博客來(lái)提高自己的水準(zhǔn)的。但苦于技術(shù)水準(zhǔn)始終不自信(也是不過(guò)關(guān)的結(jié)果吧),就一直只是將自己學(xué)習(xí)過(guò)程中的問(wèn)題和重要的知識(shí)點(diǎn)寫(xiě)在自己的筆記文檔中。
但,總感覺(jué)一個(gè)人寫(xiě)下來(lái)成就感還是欠缺了那么一些,而且有些問(wèn)題及解答方法拋出來(lái),是有可能得到更多好的反饋及解決方案的。于是,本著不作不會(huì)死的心態(tài),一步一步在技術(shù)成長(zhǎng)的道路前行——>這篇博客就是其中一步!
若博客中有些技術(shù)知識(shí)點(diǎn)有誤或者有更優(yōu)化的解答方案,還望各位小伙伴多多指出。
以下是正題了:
目標(biāo):利用SurfaceView實(shí)現(xiàn)一個(gè)簡(jiǎn)單的計(jì)時(shí)器
圖示:

描述:1.利用SurfaceView來(lái)實(shí)現(xiàn)計(jì)時(shí)功能,同時(shí)不斷將圓弧畫(huà)滿;2.點(diǎn)擊按鈕可以停止計(jì)時(shí);
重點(diǎn):
1.自定義SurfaceView中針對(duì)SurfaceHolder.CallBack的三個(gè)方法進(jìn)行覆寫(xiě);
2.通過(guò)surfaceHolder.lockCanvas()在新開(kāi)的線程中得到canvas對(duì)象,從而進(jìn)行圖形和時(shí)間文字的繪制;
3.通過(guò)設(shè)置flag值,從而控制在線程run()方法中邏輯代碼的執(zhí)行;
重要部分代碼:
public TestView(Context context) {
super(context);
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
countThread = new CountThread(surfaceHolder);
}
public TestView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
countThread = new CountThread(surfaceHolder);
}
以上為自定義的SurfaceView(TestView)的構(gòu)造函數(shù),做相應(yīng)的初始化工作。(第二個(gè)構(gòu)造方法在實(shí)現(xiàn)過(guò)程中沒(méi)有覆寫(xiě),導(dǎo)致如果是通過(guò)布局文件引入進(jìn)Activity中時(shí),則顯示不出View——>也就是一般自定義View一定要覆寫(xiě)的構(gòu)造方法)。
在構(gòu)造方法中初始化了自定義的內(nèi)部線程類CountThread,用來(lái)執(zhí)行繪制工作。
以下為CountThread類的run()方法執(zhí)行邏輯:
@Override
public void run() {
Canvas canvas = null;
int pivotX = getResources().getDisplayMetrics().widthPixels / 2;
RectF rectF = new RectF(pivotX - 300, pivotX - 300, pivotX + 300, pivotX + 300);
while (!isStop) {
try {
canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.WHITE);//設(shè)置畫(huà)布背景為白色
// canvas.drawRoundRect(300, 300, 600, 600, 150, 150, paint);//直接使用該行代碼來(lái)畫(huà)圓是行不通的,因?yàn)檫@個(gè)方法要求版本21,我的手機(jī)運(yùn)行android版本是19
canvas.drawArc(rectF, -90, endAngle++, false, paint);//-90在這里不等于270,所以要想從最上方開(kāi)始畫(huà)弧,就得用-90
canvas.drawText(countTime(endAngle), pivotX, pivotX, paintText);//顯示計(jì)算的時(shí)間
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (canvas != null) {//需要對(duì)canvas進(jìn)行非空判斷
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
主要就是通過(guò)Thread.sleep(1000)來(lái)停頓一秒,從而通過(guò)endAngle來(lái)計(jì)數(shù)。
至此,基本的程序邏輯已經(jīng)實(shí)現(xiàn)。再講該自定義View引入進(jìn)Activity指定的layout布局文件中即可進(jìn)行顯示。
但,這其中也會(huì)涉及到相應(yīng)的問(wèn)題。譬如:
1.圖示中的按鈕無(wú)法顯示出來(lái),只能看到自定義的SurfaceView的視圖;
我的做法是:將布局設(shè)定為FrameLayout即可。因?yàn)镾urfaceView是浮在窗口的一層,那么就可以把它看做一個(gè)圖層。
2.java.lang.IllegalThreadStateException:Thread already started
該錯(cuò)誤表明,線程已經(jīng)存在了。這種錯(cuò)誤的操作重現(xiàn)是:按下home鍵或者menu鍵會(huì)導(dǎo)致該自定的SurfaceView銷毀,但線程并沒(méi)有被銷毀,再次啟動(dòng)該自定義SurfaceView的時(shí)候又去重新啟動(dòng)該線程。解決的方法是:
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (!countThread.isAlive()) {//如果線程不存在,則啟動(dòng)線程——>當(dāng)應(yīng)用掛起的時(shí)候Thread是存在的,如果不做這個(gè)判斷,會(huì)報(bào)“Thread already started ”錯(cuò)誤
countThread.start();//SurfaceView創(chuàng)建時(shí)開(kāi)啟線程
}
}
在surfaceCreated()方法中對(duì)該線程是否是在存活中進(jìn)行判斷。
當(dāng)然,這里面還有最重要的一個(gè)問(wèn)題:
當(dāng)按下home鍵或者menu鍵時(shí),程序是沒(méi)有在計(jì)時(shí)的。那么這種情況下,我的一個(gè)解決方案是,通過(guò)開(kāi)啟一個(gè)service來(lái)接收程序停止( onStop() )時(shí)已經(jīng)計(jì)時(shí)的數(shù)值,然后傳遞給service記下并計(jì)時(shí),當(dāng)應(yīng)用程序界面重新回歸屏幕時(shí)( onRestart() )則將數(shù)據(jù)取出并回傳到自定義的SurfaceView的邏輯run()方法中繼續(xù)計(jì)時(shí)。
整個(gè)小程序的代碼可以通過(guò)以下鏈接下載:
點(diǎn)擊進(jìn)入下載頁(yè)面:http://xiazai.jb51.net/201701/yuanma/AndroidSurfaceView(jb51.net).rar
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android中SharedPreference使用實(shí)例講解
這篇文章主要介紹了Android中SharedPreference使用方法,實(shí)現(xiàn)登陸界面記住密碼功能,感興趣的小伙伴們可以參考一下2016-01-01
詳解Android中Handler的實(shí)現(xiàn)原理
這篇文章主要為大家詳細(xì)介紹了Android中Handler的實(shí)現(xiàn)原理,本文深入分析 Android 的消息處理機(jī)制,了解 Handler 的工作原理,感興趣的小伙伴們可以參考一下2016-04-04
Android自定義View實(shí)現(xiàn)拖拽效果
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)拖拽效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11
Android App界面的ListView布局實(shí)戰(zhàn)演練
這篇文章主要介紹了Android App界面的ListView布局方法,文中分了三種情況通過(guò)實(shí)例來(lái)講解,ListView適用于功能最簡(jiǎn)單的應(yīng)用程序UI布局,需要的朋友可以參考下2016-04-04
Flutter實(shí)現(xiàn)自定義搜索框AppBar的示例代碼
開(kāi)發(fā)中,頁(yè)面頭部為搜索樣式的設(shè)計(jì)非常常見(jiàn),為了可以像系統(tǒng)AppBar那樣使用,本文將利用Flutter自定義一個(gè)搜索框,感興趣的可以了解一下2022-04-04
Android點(diǎn)擊EditText文本框之外任何地方隱藏鍵盤(pán)的解決辦法
這篇文章主要介紹了Android點(diǎn)擊EditText文本框之外任何地方隱藏鍵盤(pán)的解決辦法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-01-01
Android開(kāi)發(fā)使用Drawable繪制圓角與圓形圖案功能示例
這篇文章主要介紹了Android開(kāi)發(fā)使用Drawable繪制圓角與圓形圖案功能,結(jié)合具體實(shí)例形式分析了Drawable繪制圓角矩形的實(shí)現(xiàn)步驟與使用方法,需要的朋友可以參考下2017-10-10
Android利用Canvas標(biāo)點(diǎn)畫(huà)線并加入位移動(dòng)畫(huà)(2)
這篇文章主要為大家詳細(xì)介紹了Android利用Canvas標(biāo)點(diǎn)畫(huà)線并加入位移動(dòng)畫(huà)的第二篇,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-09-09

