走馬燈效果總結
android:ellipsize實現跑馬燈效果總結
首先我們要實現走馬燈這樣一個效果,通常來說都是在TextView這個控制元件中來實現的,而且其中的文字一定是單行顯示,如果多行顯示,那走馬燈效果也就失去了存在的意義。另外,在EditText中使用走馬燈沒有必要,也不合理,實際上對於EditText來說android:ellipsize這個屬性只有對於設定在android:hint中的文字的時候是有用的,而且android:ellipsize=”marquee”這個用法不能用在EditText控制元件上。對於在EditText使用者輸入的文字,android:ellipsize這個屬性沒有用處。關於EditText
設定android:ellipsize的相關用法以後再講,在這裡也算留個標記,以防自己忘了。
在TextView中實現我們的走馬燈效果,需要兩個屬性android:singleLine=”true”,以及android:ellipsize=”marquee”,我們來看下面的程式碼:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="100dip" android:layout_height="wrap_content" android:layout_gravity="center" android:text="走馬燈效果的演示" android:singleLine="true" android:ellipsize="marquee"/> </LinearLayout>
執行這段程式碼之後,我們會發現走馬燈效果並沒有顯示出來,顯示出的文字是不動的,實際效果如下:
這其中的原因在於跑馬燈效果需要TextVIew獲得當前的焦點(focus)。然而對於TextView這個控制元件來說,他的預設的Clickable,LongClickable,Focusable,
FocusableInTouchMode這四個屬性的值都是false,所以跑馬燈效果也就不會出來了,即使你用手觸控TextView或者按下手機上的導航按鍵也是無法顯示跑馬燈的效果的。
解決這個問題我們就需要讓我們的TextView得到焦點,這裡主要涉及android:focusable和android:focusableInTouchMode這兩個屬性,簡單來說把這兩個屬性都設定成true,那麼在執行程式以後跑馬燈效果就顯示出來了,這裡就不再貼這兩行程式碼了。
但是細細品味這兩個屬性之後發現其中其實還是有一些玄機的:
1.。如果這兩個屬性設定成android:focusable=”true”以及android:focusableInTouchMode=”false”,那麼會發現程式執行之後,走馬燈效果沒有出現,
這個時候需要使用者按下手機或者模擬器上的上下導航鍵,才能讓走馬燈的效果出現,這說明android:focusable是針對於手機按鍵有效的,然而根據api的解釋,
android:focusableInTouchMode是根據螢幕觸控決定的。
2。如果這兩個屬性設定成android:focusable=”false”與android:focusableInTouchMode=”true”,那麼無論如何走馬燈都出現不了了,就算加上android:clickable=”true”
也不行,這說明 android:focusable=”true”是android:focusableInTouchMode=”true”能有效的先決條件,我推測可能是在原始碼實現中,android:focusableInTouchMode
的邏輯是巢狀在android:focusable中的,這個有待於以後進一步的研究,路漫漫其修遠兮。。。
3。在把這兩個屬性都設定成true以後,會發現程式執行之後,走馬燈效果自動就顯現了出來,這說明應用在執行後,會自動地按照某種順序(在這裡應該是自上而下),
尋找第一個android:focusableInTouchMode=”true”這個屬性有效的第一個控制元件,當然要使這個屬性有效按照前面的討論android:focusable=”true”也必須具備。根據測試,
LinearLayout的Clickable,LongClickable,Focusable,FocusableInTouchMode這四個屬性預設也都是false,因此,在上面的例子中TextView就率先獲得了焦點,
走馬燈也就走了起來了。
這裡我們做一下驗證,首先將程式碼修改為:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:focusable="true">
<TextView
android:layout_width="100dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="走馬燈效果的演示"
android:singleLine="true"
android:ellipsize="marquee"
android:focusable="true"
android:focusableInTouchMode="true"
></TextView>
</LinearLayout>
也就是為LinearLayout加上了android:focusable=”true”然後執行應用,會發現TextView的走馬燈照走不誤:
然後我們為LinearLayout加上android:focusableInTouchMode=”true”然後再執行,會發現走馬燈失效了。
這裡也就驗證了我們總結的第三條結論。
但是稍等,我們在這裡又發現問題了!現在無論我們怎麼點選導航按鈕,又或是點選螢幕上的TextView走馬燈死活都走不出來了。這是怎麼回事呢?
讓我們理順一下思路,按照我們前面的總結,走馬燈要想有效,TextView必須要得到焦點,現在走馬燈出不來,說明TextView沒有得到焦點。
這裡有兩個情況,一是導航按鈕無法讓TextView或得焦點,二是螢幕點選無法讓TextView獲得焦點。
先看第一種情況,第一種情況的原因在於使用導航按鈕切換焦點預設的的方式會跳過內部控制元件,說白了,上面例子裡面的TextView在LinearLayout裡面,現在
LinearLayout有焦點,如果你按導航按鈕上下按鍵,焦點只會在LinearLayout同層次的控制元件之間切換,不會進入到Linearlayout內部,為了驗證這個結論,我們使用
下面的程式碼:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="100dip"
android:focusable="true"
android:focusableInTouchMode="true"/>
<TextView
android:layout_width="100dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="走馬燈效果的演示"
android:singleLine="true"
android:ellipsize="marquee"
android:focusable="true"
android:focusableInTouchMode="true"
></TextView>
</LinearLayout>
然後我們執行程式,會發現開始的時候走馬燈沒有自動執行,因為這時候焦點在程式碼裡面的第二個LinearLayout那裡,然後我們按下導航下按鍵,會發現走馬燈效果出來了,
這裡我就不貼圖了。
但是稍等,再重新執行應用,不要按導航按鍵,然後我們這個時候用手指或者說模擬器裡的滑鼠繼續點選TextView,會發現走馬燈還是沒有出現。
這個時候我們來到了第二種情況了。
這裡的問題可以總結為,除了應用第一次開啟的時候,應用自動尋找到android:focusableInTouchMode=”true”屬性有效的控制元件冰賦予焦點,我們要如何
自行通過點選螢幕的方式使一個控制元件獲得焦點,在這種情況之下控制元件想要獲得焦點的流程是什麼。
這方面的資料我沒有查到,所以只能自己做一些試驗,然後總結。有盲人摸象的嫌疑,但是我認為在某種程度上是管用的,繼續。
首先我們將程式碼修改為如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="100dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
<TextView
android:layout_width="100dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="走馬燈效果的演示"
android:singleLine="true"
android:ellipsize="marquee"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
></TextView>
</LinearLayout>
也就是給TextView加上了一個android:clickable=”true”屬性,然後執行之後發現,現在通過觸控的方式點選TextView可以讓走馬燈初顯也就是可以讓TextView獲得焦點了。
看起來問題解決了,但是仔細想想其中還是有一些值得思考的地方:
android:clickable與android:focusableInTouchMode之間是一種什麼關係?是說一個空間如果要想能獲得焦點就必須可點選嗎?又或者說一個空間只要可以點選就一定可以獲得焦點?這二者之間是充要條件還是充分條件還是必要條件?
我們來做一下驗證:
首先執行如下程式碼:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="100dip"
android:clickable="true"
/>
<TextView
android:layout_width="100dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="走馬燈效果的演示"
android:singleLine="true"
android:ellipsize="marquee"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
></TextView>
</LinearLayout>
執行後會發現,應用開始以後跑馬燈馬上出現,滑鼠點選TextView上方的位置也就是第二個LinearLayout的區域,跑馬燈不停止,這說明:
android:clickable=”true”不一定就能獲得焦點,也就是一個空間能點選不一定就能獲得焦點。
我們來看下一段程式碼:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="100dip"
android:clickable="false"
android:focusable="true"
android:focusableInTouchMode="true"
/>
<TextView
android:layout_width="100dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="走馬燈效果的演示"
android:singleLine="true"
android:ellipsize="marquee"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
></TextView>
</LinearLayout>
這段程式碼執行之後,首先程式碼中的第二個LinearLayout自動獲得焦點,然後我們點選TextView。跑馬燈出現,TextView獲得焦點,然後我們點選TextView上方區域,
跑馬燈不停止。這說明如果一個空間能獲得觸控模式焦點但卻不能點選,那麼在觸控模式下無論怎麼觸控也還是不能獲得焦點的。
好的我們來看最後一段程式碼:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="100dip"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
/>
<TextView
android:layout_width="100dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="走馬燈效果的演示"
android:singleLine="true"
android:ellipsize="marquee"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
></TextView>
</LinearLayout>
這段程式碼執行之後,首先走馬燈不出現,程式碼中的第二個LinearLayout獲得焦點,然後我們點選第二個TextView,走馬燈出現,然後我們點選TextView上方的區域,
走馬燈效果消失,說明焦點轉移到程式碼中的第二個LinearLayout。
好的,總結一下也就是說,在觸控模式下android:clickable=”true”是(android:focusable=”true”,android:focusableInTouchMode=”true”)能獲得焦點的必要條件,
就是說一個控制元件想要在觸控模式下獲得焦點就一定要可點選,上面三個屬性都要有。