最近无心间看到了涉及到跑马灯效果的代码,因而在网上查阅了不少资料,在这里对本身看的一些文章进行一下总结,顺便加上本身的一些体会。html
让咱们一步步逐渐向下。android
首先咱们要实现走马灯这样一个效果,一般来讲都是在TextView这个控件中来实现的,并且其中的文字必定是单行显示,若是多行显示,那走马灯效果api
也就失去了存在的意义。另外,在EditText中使用走马灯没有必要,也不合理,实际上对于EditText来讲android:ellipsize这个属性只有对于设置在android:hint中的文字测试
的时候是有用的,并且android:ellipsize="marquee"这个用法不能用在EditText控件上。对于在EditText用户输入的文字,android:ellipsize这个属性没有用处。关于EditTextspa
设置android:ellipsize的相关用法之后再讲,在这里也算留个标记,以防本身忘了。xml
在TextView中实现咱们的走马灯效果,须要两个属性android:singleLine="true",以及android:ellipsize="marquee",咱们来看下面的代码:htm
- <?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>
运行这段代码以后,咱们会发现走马灯效果并无显示出来,显示出的文字是不动的,实际效果以下:ip

这其中的缘由在于跑马灯效果须要TextVIew得到当前的焦点(focus)。然而对于TextView这个控件来讲,他的默认的Clickable,LongClickable,Focusable,utf-8
FocusableInTouchMode这四个属性的值都是false,因此跑马灯效果也就不会出来了,即便你用手触摸TextView或者按下手机上的导航按键(如今的手机没这get
个东东了都。。。)也是没法显示跑马灯的效果的。
解决这个问题咱们就须要让咱们的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")能得到焦点的必要条件,
就是说一个控件想要在触摸模式下得到焦点就必定要可点击,上面三个属性都要有。