[關鍵字] Android / scroller / textview / duration / speed / computeScroll / view / viewgroup

 

上一篇裡頭我有提到如何將一個 TextView 改變成跑馬燈的模式。

如果你有實作過的話,會發現預設的捲動速度,實在有點慢。

原本這項功能,是設計來顯示過長的標題,再怎麼長都不會超過太多,

所以他把速度設定的很緩慢。

 

相信有些人是需要設計一個不斷往前跑的長字串,像是

新聞台的跑馬燈一樣,一直不斷的跑。如果是這種需求,

那預設跑動的速度明顯是偏慢。

 

但是找來找去,在 TextView 裡頭並沒有用來控制速度的 method,

所以,如果你想要讓跑馬燈跑快一點,就需要參考接下來這兩篇的內容。

 

讓我們閱讀一下 TextView(.java) 這支程式,

會發現他有一個方法叫做 setScroller(Scroller s),這就是用來控制捲動功能的工具。

 

首先,就讓我們一起來研究一下 Scroller 吧。

 

Scroller 是用來捲動該 View 底下的 child。

每個 View 都有這個 method: computeScroll()。

而 Scroller 必須配合 computeScroll() 去叫用。

先讓我們看看 android.view.View 原始碼的說明:

Screen Shot 2013-01-19 at 5.58.56 PM    

 

而我們在 android.widget.Scroller(.java) 的原始碼裡發現了這個 method:

Screen Shot 2013-01-19 at 6.09.33 PM  

身為一個程式阿宅的你,看到這裡想必很興奮了吧?(其實在說我自己xd)。

 

看看這些參數 -- 起始x,起始y,目標x,目標y,間隔時間duration --

這不正是我們需要的東西了嗎?

正當準備大顯身手的時候,等等,請冷靜一下,

仔細讀了裡面的 code,發現其實它並沒有做任何繪圖的動作,

只是重新設定了一些變數值,這到底可以如何讓 View 移動呢?

 

因此接下來我們要知道怎麼使用這個 Scroller。

如果你有空去細看 android.view.ViewGroup(.java) 這個文件:

http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.0_r1/android/view/ViewGroup.java

你可以在 drawChild() 這個 method 裡頭看到 

child.computeScroll();

 

這段程式碼。

 

也就是在每次要畫 ViewGroup 中的 Child 時,才會去呼叫它。

這個 computeScroll() 其實是被動的,它並不是主動的去移動 View,

而是等到別人發出重繪圖的命令,才會去做出相對應的動作。

通常是 View 底下的這兩個指令:

invalidate(); //當從主 Thread 去發起重繪圖

postInvalidate(); //當從非主 Thread 去發起重繪圖

 

p.s 所謂 invalidate() 的意思是,這個 View 暫時無法使用,

通常在發起重繪圖的時候,只有發起人知道,所以這個 method 

就是告知其他會使用到此 View 的人 --

我要更新它,暫時不能使用這個 View,然後指令下了之後

會回到 View.onDraw(Canvas canvas) 裡頭,去重新繪圖。

 

一旦重繪了 View 就會再次叫用到 computeScroll()。

所以如果我們埋個 Log 在裡頭,我們就會看到在每次繪圖過程中,

它都會被叫用一次。

 

所以我們如果要試著去移動某個子 View,也就是要從此下手。

 

首先我們實驗一下,創建一個 class 繼承 FrameLayout,

然後在它底下加上一個小方塊,用 Scroller 來觀察一下它的行為。

 Screen Shot 2013-02-14 at 11.56.41 PM  

我們預期它底下的子 View 會照著我們的希望走,

也就是在2000毫秒間,從0走向-300(向右移動300pixel)。

 

於是在我們的 Activity 裡頭我們這麼做:

Screen Shot 2013-02-15 at 12.25.51 AM  

我們在 onCreate 裡頭把我們創建的 TestView 加入到基底的 LinearLayout,

並且加入一個小方塊 View 到它底下。預期它可以照我們想的移動,可是....

Screen Shot 2013-02-15 at 4.42.50 PM  

所以我們可以知道,光是叫用 Scroller 裡的 startScroll

是不夠的!

 

其實,Scroller.startScroll() 這個 method 並沒有真正的去移動子 View,

它只是在做一些確認的動作,諸如:

你想要移動的x/y距離,移動的時間。

 

然後會經由這一個 method 去確認移動是否已經結束:

(android.widget.Scroller)

Screen Shot 2013-02-15 at 5.00.51 PM  

然後我們必須要在 ViewGroup(FrameLayout) 裡的 computeScroll()

叫用 Scroller.computeScrollOffset(),它可以幫助我們判斷移動是否已經結束,

如果還沒結束,就繼續移動,如果已經結束了就停止。

 

仔細研讀裡面的程式碼會發現,其判斷停止與否的依據,也是根據

startScroll(startx, startY, dX,dY,Duration); 這個方法裡設定的各項參數計算而出,

例如:時間還沒到就繼續移動,時間到了就回傳已經結束。

還有時間區段(duration)應該移動多少距離(dX)等等移動的行為。

 

而真正讓 View 移動的是以下兩個 methods:

 

scrollTo(int x, int y);

scrollBy(int dx, int dy);

 

簡單的說,整個 scroller 的操作流程約略是:

Screen Shot 2013-08-31 at 7.15.13 PM  

而我想讓我的小方塊移動的話,還必須多加一個動作在 computeScroll 裡面:

Screen Shot 2013-08-31 at 7.23.52 PM  

於是剛剛的小方塊終於可以順利移動了:

Screen Shot 2013-08-31 at 7.31.30 PM  

 

這樣可以簡單解釋了 Scroller 的運作原理, 

接下來可以搜尋在 TextView(.java) 裡頭有關 Scroller 相關的字眼,

便可以理解是怎麼讓字串動起來,然後我們再做些小手腳,

就可以去改變跑馬燈的速度了。 

 

有興趣的話請參閱下一篇文章~ 

arrow
arrow
    全站熱搜

    keep walking 發表在 痞客邦 留言(0) 人氣()