? ? ? ? ? ?ListView-------列表裹驰,他作為一個(gè)非常重要的顯示方式,不管是在Web中還是在移動(dòng)平臺(tái)中盖高,都是一個(gè)非常好的、不可或缺的展示信息的工具眼虱。在Android中喻奥,ListView控件接管了這一重任,在大量的場合下捏悬,我們都需要使用這個(gè)控件撞蚕。雖然在Android5.0時(shí)代,RecycleView在很多地方都在逐漸取代ListView过牙,但ListView的使用范圍依然非常廣泛甥厦,它這萬年大哥的地位也不是輕易就能撼動(dòng)的纺铭。本章將向大家展示如何高效的使用ListView。
? ? ? ? ? ?學(xué)習(xí)本章刀疙,你將了解到以下內(nèi)容:
? ? ? ? ? ListView常用技巧
? ? ? ? ? ListView常用拓展
4.1 ListView常用優(yōu)勢技巧
? ? ? ? ? ListView的基本用法相信大多數(shù)的讀者都已經(jīng)能夠非常熟練的使用了舶赔,下面我們著重學(xué)習(xí)一下使用ListView的技巧。
4.1.1 使用ViewHolder模式提高效率
? ? ? ? ?ViewHolder模式是提高ListView效率的一個(gè)很重要的方法谦秧。ViewHolder模式充分了ListView的視圖緩存機(jī)制竟纳,避免了每次在調(diào)用getView()的時(shí)候都去通過findViewBtId()實(shí)例化控件。據(jù)測試疚鲤,使用ViewHolder將提高50%以上的效率锥累。使用ViewHolder模式來優(yōu)化ListView非常簡單,只需要在自定義Adapter中定義一個(gè)內(nèi)部類ViewHolder集歇,并將布局中的控件作為成員變量桶略,代碼如下。
? ? ? ? ? ? 效果很簡單诲宇,這就是一個(gè)簡單的ListView际歼。
4.1.2 設(shè)置項(xiàng)目間分割線
? ? ? ? ? ? ?ListView的各個(gè)項(xiàng)目之間,可以通過設(shè)置分割線來進(jìn)行區(qū)分姑蓝,系統(tǒng)提供了divider和dividerHeight這樣兩個(gè)屬性來幫助我們實(shí)現(xiàn)這一功能鹅心。通過這兩個(gè)屬性,也可以控制listView之間的分割線和它的高度它掂,當(dāng)然巴帮,分割線不僅僅可以設(shè)置為一個(gè)顏色,同樣也可以設(shè)置為一個(gè)圖片資源虐秋,分割線的使用代碼如下所示榕茧。
? ? ? ? ? ?特殊情況下,當(dāng)設(shè)置分割線為如下代碼時(shí)客给,就可以把分割線設(shè)置為透明的了秩霍。
4.1.3 隱藏ListView的滾動(dòng)條
? ? ? ? ? ?默認(rèn)的ListView在滾動(dòng)時(shí)握巢,在右邊顯示滾動(dòng)條豆巨,指示當(dāng)前滑動(dòng)的位置压怠,我們可以設(shè)置scrollbars屬性控制ListView的滾動(dòng)條狀態(tài)。特別地桩引,當(dāng)設(shè)置scrollbars屬性為none的時(shí)候listview滾動(dòng)或者不滾動(dòng)們就都不會(huì)出現(xiàn)滾動(dòng)條了缎讼,代碼如下所示。
4.1.4 ?取消listview的item點(diǎn)擊效果
? ? ? ? ?當(dāng)點(diǎn)擊listview中的一項(xiàng)時(shí)坑匠,系統(tǒng)默認(rèn)會(huì)出現(xiàn)一個(gè)點(diǎn)擊效果血崭,在Android5.X上是一個(gè)波紋效果,而在Android5.X之下的版本則是一個(gè)改變北京顏色的效果,但可以通過修改listSelector屬性來取消點(diǎn)擊后的回饋效果夹纫,代碼如下所示咽瓷。
? ? ? ? 當(dāng)然,也可以直接使用Android自帶的透明效果來實(shí)現(xiàn)這個(gè)效果舰讹,代碼如下所示茅姜。
4.1.5 ? 設(shè)置ListView需要顯示在第幾項(xiàng)
? ? ? ? ? ListView以item為單位進(jìn)行顯示,默認(rèn)顯示在第一個(gè)item月匣,當(dāng)需要指定具體顯示的Item時(shí)钻洒,可以通過如下代碼來實(shí)現(xiàn)。
? ? ? ? ?其中N就是需要顯示的第N個(gè)Item桶错。
? ? ? ? ?當(dāng)然航唆,這個(gè)方法類似scrollTo胀蛮,是瞬間完成的移動(dòng)院刁。除此之外,還可以使用如下代碼來實(shí)現(xiàn)平滑移動(dòng)
4.1.6 動(dòng)態(tài)修改ListView
? ? ? ? ? ? ListView中的數(shù)據(jù)在某些情況下是需要變化的粪狼,當(dāng)然可以通過重新設(shè)置ListView的Adapter來更新ListView的顯示退腥,但這也就需要重新獲取一下數(shù)據(jù),相當(dāng)與重新創(chuàng)建ListView再榄,這樣顯然不是非常有好的狡刘,而且效率也不會(huì)太高。因此困鸥,可以使用一個(gè)更簡單的方法來實(shí)現(xiàn)ListView的動(dòng)態(tài)修改嗅蔬,代碼如下所示。
? ? ? ? ? ? ? 當(dāng)修改了傳遞給Adapter的映射的List之后疾就,只需要通過調(diào)用Adapter的notifyDataSetChanged()方法澜术,通知ListView更改數(shù)據(jù)源即可完成對ListView的動(dòng)態(tài)修改。不過猬腰,使用這個(gè)方法有一點(diǎn)需要注意的是鸟废,在使用Adapter.notifyDataSetChanged()方法時(shí),必須保證傳進(jìn)去Adapte的數(shù)據(jù)List是同一個(gè)List而不是其他對象姑荷,否則將無法實(shí)現(xiàn)該效果盒延。下面這個(gè)實(shí)例就演示了如何動(dòng)態(tài)地修改ListView。通過點(diǎn)擊按鈕鼠冕,不斷地給原有的List增加一個(gè)新的Item添寺,并調(diào)用notifyDataSetChanged()方法來實(shí)現(xiàn)ListView的動(dòng)態(tài)更新,完整代碼懈费。
4.1.7 遍歷ListView中的所有Item
? ? ? ? ? ? ?ListView作為一個(gè)ViewGroup计露,為我們提供了操縱子View的各種方法,最常用的就是通過getChldAt()來獲取第i個(gè)子View,代碼如下:
4.1.8 處理控ListView
? ? ? ? ? ? ?ListView用于展示列表數(shù)據(jù)薄坏,但當(dāng)列表中無數(shù)據(jù)時(shí)趋厉,ListView不會(huì)顯示任何數(shù)據(jù)或顯示,按照完善用戶體驗(yàn)的需求胶坠,這里應(yīng)該給以數(shù)據(jù)的提示君账。幸好,listView提供了一個(gè)方法-------setEmptyView()沈善,通過這個(gè)方法我們可以給ListView設(shè)置一個(gè)空數(shù)據(jù)下顯示的默認(rèn)提示乡数。包含listView的布局設(shè)置如下。
? ? ? ? ? ? 在代碼中闻牡,我們通過以下方式給ListView設(shè)置空數(shù)據(jù)是要顯示的布局净赴,代碼如下:
? ? ? ? ? ? 通過以上代碼,就給listView在空數(shù)據(jù)時(shí)顯示了一張默認(rèn)的圖片罩润,用來提示用戶玖翅;而在有數(shù)據(jù)時(shí),則不顯示
4.1.9 ListView滑動(dòng)監(jiān)聽
? ? ? ? ? ? listView的滑動(dòng)監(jiān)聽割以,是ListView中最重要的技巧金度,很多重寫的ListView,基本上都是在滑動(dòng)事件的處理上下功夫严沥,通過判斷滑動(dòng)見識(shí)進(jìn)行不同的邏輯處理猜极。而為了更加精確地監(jiān)聽滑動(dòng)事件,開發(fā)者通常還需要使用GestrueDetetor手勢識(shí)別消玄,VelocityTracker滑動(dòng)速度檢測等輔助類來完成更好的監(jiān)聽跟伏。這里介紹兩種監(jiān)聽ListView滑動(dòng)事件的方法,一個(gè)是通過onTouchListener來實(shí)現(xiàn)監(jiān)聽翩瓜,另外一個(gè)是使用OnscrollListener來實(shí)現(xiàn)監(jiān)聽受扳。
4.1.9.1 onTouchListener
? ? ? ? ? ? onTouchListener是View中的監(jiān)聽事件,通過監(jiān)聽ACTION_DOWN//觸摸時(shí)操作奥溺、ACTION_MOVE//移動(dòng)時(shí)操作辞色、ACTION_UP//離開時(shí)操作,這個(gè)三個(gè)事件發(fā)生時(shí)的坐標(biāo)浮定,就可以根據(jù)坐標(biāo)判斷用戶滑動(dòng)的方向相满,并在不同的事件中進(jìn)行相應(yīng)的邏輯處理,這種方式的使用代碼如下:
4.1.9.2 OnSorllListener
OnScrollListener是A bsListView中的監(jiān)聽事件桦卒,他封裝了很多與ListView相關(guān)的信息立美,使用起來也更加靈活。首先看一下OnScrollListener的一般用法方灾,代碼如下所示建蹄。
onScrollListener中有兩個(gè)會(huì)調(diào)方法---------onScrollStateChanged()和onScroll()碌更。
先來看一第一個(gè)方法onScrollStateChanged(),這個(gè)方法根據(jù)他的參數(shù)scrollState來決定器回調(diào)的此時(shí)洞慎,scrollState有以下三種模式有以下三種模式:
OnScrollListener.SCROLL_STATE_IDLE:正在滾動(dòng)痛单。
OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:正在滾動(dòng)時(shí)。
OnScrollListener.scroll_STATE_FLING:手指拋動(dòng)時(shí)劲腿,即手指用力滑動(dòng)旭绒,在離開后ListView由于慣性繼續(xù)滑動(dòng)的狀態(tài)。
當(dāng)用戶沒有左手指拋動(dòng)的狀態(tài)時(shí)焦人,這個(gè)方法只會(huì)回調(diào)2次挥吵,否則會(huì)回調(diào)3次,差別就是手指拋動(dòng)的這個(gè)狀態(tài)花椭。通常情況下忽匈,我們會(huì)在這個(gè)方法中通過不同的狀態(tài)來設(shè)置一些標(biāo)志Flag,來區(qū)分不同的滑動(dòng)狀態(tài)矿辽,供其他方法處理丹允。
下面再來看看onScroll()這個(gè)會(huì)調(diào)方法,他在ListView滾動(dòng)時(shí)會(huì)一直回調(diào)嗦锐,而這個(gè)方法中的后面三個(gè)int類型的參數(shù)嫌松,則非常精確地顯示了當(dāng)前ListView滾動(dòng)狀態(tài)沪曙,這三個(gè)參數(shù)如下所示奕污。
firstVisibleItem:但前能看見的第一個(gè)Item的ID(從0開始)。
visibleItemCount:當(dāng)前能看見的Item總數(shù)液走。
totaIItemCount:整個(gè)ListView的Item總數(shù)碳默。
這里需要注意的是,當(dāng)前能看見的Item數(shù)缘眶,包括沒有顯示完整的Item嘱根,即顯示一小半的Item也包括在內(nèi)了。通過這幾個(gè)參數(shù)巷懈,可以很方便地進(jìn)行一些判斷该抒,比如判斷是否滾動(dòng)到最后一行,就可以使用如下代碼進(jìn)行判斷顶燕,當(dāng)前可視的另一個(gè)Item的ID加上當(dāng)前可視Item的和等于Item總數(shù)的時(shí)候凑保,及滾動(dòng)到了最后一行。
再比如涌攻,可以通過如下代碼來判斷滾動(dòng)的方向欧引,代碼如下所示。
通過一個(gè)成員變量LastVisiblePosition來記錄上一次第一個(gè)可視的Item的ID并與當(dāng)前的可視Item的ID進(jìn)行比較恳谎,即可知道當(dāng)前滾動(dòng)的方向芝此。
要理解整個(gè)OnScrollListener憋肖,最好的方法還是在代碼中添加Log,并打印出狀態(tài)信息來進(jìn)行分析學(xué)習(xí)婚苹。在以上代碼中岸更,已經(jīng)添加了相應(yīng)的Log,對照Log進(jìn)行分析膊升,會(huì)很快撞我OnScrollListener的用法坐慰。
當(dāng)然,ListView也給我們提供了一些封裝的方法來獲取當(dāng)前可視的Item的位置等信息:
//獲取當(dāng)前可視區(qū)域內(nèi)最后一個(gè)Item的id
//獲取可視區(qū)域內(nèi)第一個(gè)Item的id
4.2 ? ListView常用拓展
ListView雖然使用廣泛用僧,但系統(tǒng)原生的ListView顯然是不能瞞住用戶在審美结胀、功能上不斷提高需求的。不過也不要緊责循,Android完全可以定制化糟港,讓我們非常方便對原生ListView進(jìn)行拓展、修改院仿。于是秸抚,在開發(fā)者的創(chuàng)新下,ListView越來越豐富多彩歹垫,各種各樣的基于原生ListView的拓展讓人目不暇接剥汤。下面來看幾個(gè)常用的ListView拓展。
4.2.1 具有彈性的ListView
Android默認(rèn)的ListView在滾動(dòng)到頂端或者底端的時(shí)候排惨,并沒有很好地提示吭敢。在Android5.X中,Google為這樣的行為只添加了一個(gè)半月的陰影效果暮芭,如圖4.4所示鹿驼。
而在IOS系統(tǒng)中,列表都是具有彈性的辕宏,及滾動(dòng)到低端或者頂端后會(huì)繼續(xù)往下或者往上滑動(dòng)一段距離畜晰。不得不說,這樣的設(shè)計(jì)的確更加友好瑞筐,雖然不知道Goolge為什么不模仿這樣的設(shè)計(jì)凄鼻,但我們可以自己修改ListView,讓ListView也可以“彈性十足”聚假。
块蚌。。魔策。匈子。。闯袒。虎敦。游岳。。
4.2.3 ?聊天ListView
通常我們使用的LIstView的每一項(xiàng)都具有相同的布局其徙,所以展示出來的時(shí)候胚迫,除了數(shù)據(jù)不同,只要你不隱藏布局唾那,其他的布局應(yīng)該是類似的访锻。為我們熟知的qq、微信等聊天App闹获,在聊天界面期犬,會(huì)展示至少兩種布局,即收到消息和自己發(fā)送的消息避诽,其實(shí)這樣的效果也是通過ListView來實(shí)現(xiàn)的龟虎,下面我們就來模仿一個(gè)聊天軟件列表界面,其效果如圖4.10所示:(就是聊天界面)
這樣一個(gè)Listview與我們平時(shí)所使用的ListView最大的不同沙庐,就是他擁有兩個(gè)不同的布局-----收到的布局鲤妥,和發(fā)送的布局。要實(shí)現(xiàn)這樣的效果拱雏,就需要拿ListView的Adapter“開刀”棉安。
在定義BaseAdapter的時(shí)候,需要去重寫它的getView()方法铸抑,這個(gè)方法就是用來獲取布局的贡耽,那么只需要在獲取布局的時(shí)候,判斷一下該獲取哪一個(gè)布局就可以了羡滑。而且ListView在設(shè)計(jì)的時(shí)候就已經(jīng)考慮到這種情況菇爪,所以它提供了連個(gè)方法,代碼如下柒昏。