在做iOS 開發(fā)的最常用到的就是tableview,因此最常見的也就是tableview 的重用問題缩幸,這次我來介紹一種tableview 的重用的場景 和如何解決這個重用的問題俗壹。首先來看一個圖片
這是一個播放的音樂的界面私痹,這里可能會涉及到兩個明顯的問題捎迫,(1)一個播放進(jìn)度條的進(jìn)度渲染,需要用到定時器去不斷的渲染紅點(diǎn)的位置澳叉,那么需要用到多少個定時器隙咸,應(yīng)該怎么優(yōu)化呢,(2)第二個就是在滾動tableview 由于cell 重用的影響會導(dǎo)致沒有被點(diǎn)擊的播放的cell成洗,紅點(diǎn)的位置五督,播放時間 ,還有播放按鈕的狀態(tài)錯誤瓶殃。
(1)第一個問題和我之前寫的一篇文章的思路很類似http://www.reibang.com/p/9784a996d187
大概的思路一個定時器去刷新可見cell 的ui 充包,由于這個場景是只用對一個cell 操作,那么可以記錄下這個正在播放的cell 的索引遥椿,通過判斷這個cell 是否為空基矮,來判斷他是否可見,可以看這個代碼段
if let cell : ReAudioListTableViewCell = tableView1.cellForRowAtIndexPath(curIndex) as? ReAudioListTableViewCell
{
}
那么只需在if里面刷新 cell的ui 即可
(2)第二個問題冠场,由于我們只是處理可見cell 的話家浇,那么在滾動的時候還是會導(dǎo)致其中的一個cell 的由于重用的問題,導(dǎo)致他的進(jìn)度條的狀態(tài)和音樂播放時間的狀態(tài)的錯亂慈鸠,
1 導(dǎo)致錯誤的原因也很簡單,先看下灌具,下面的圖片
由于cell 的重用數(shù)組是用從不可見cell獲取的青团,那么可見cell剛好獲取正在播放的cell,那么狀態(tài)就變了。
2要怎么防止重用狀態(tài)錯亂
每次滾動tableview都會調(diào)用cellforindexpath,只要我們把每個cell的狀態(tài)通過這個代理方法告訴tableiview 即可咖楣。
3 那么用什么來標(biāo)記cell的狀態(tài)督笆,
我現(xiàn)在使用 了curIndex,來記錄當(dāng)前選中的cell 的索引,isplay記錄當(dāng)前選中的cell是否在播放诱贿,
大致的思路介紹完了來看下代碼
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! ReAudioListTableViewCell
//記錄下來判斷是否為可見cell
cell.tag = indexPath.row
//加載本地音樂
let path:String = NSBundle.mainBundle().pathForResource("lj", ofType:"mp3")!
let dict = ["path" : path , "time":"64.0" , "size":"1.8" ,"second":"64.0"]
cell.getAudioDict(dict)
cell.title.text = "錄音" + String(indexPath.row+1) + ".aac"
if isfirst
{
//第一次加載默認(rèn)不播放狀態(tài)
cell.noPlay()
}
else
{
//當(dāng)前點(diǎn)擊的索引
if indexPath.row == curIndex.row
{
//如果播放設(shè)置為播放的狀態(tài)
if isPlay == true
{
//記錄播放的狀態(tài)和進(jìn)度
cell.playBtn.selected = true
cell.playBar.playProgress(CGFloat(playProgress))
}
//如果沒有播放顯示未播放狀態(tài)
else
{
cell.noPlay()
}
}
//不是當(dāng)前點(diǎn)擊說明沒有播放
else{
cell.noPlay()
}
}
return cell
}
最后再說說一種場景就是娃肿,(1)選擇當(dāng)前的播放的cell,在點(diǎn)一次就需要關(guān)閉,(2)或者選擇另外一個cell,要暫停前一個珠十,播放當(dāng)前的這個料扰,思路又是怎樣的呢(還是利用的報(bào)存當(dāng)前的索引curIndex)
1 判斷curIndex 和 didselect 的index 是否相同,相同的播放 在通過isplay 判斷是否正在播放焙蹭,播放則暫停晒杈,暫停則繼續(xù)播放
2 如果curIndex 和 didselect 的index 不相同,說明是場景2 孔厉,則需要修改判斷前一個cell是否在播放拯钻,播放則需修改上次狀態(tài)為暫停帖努,這里需要注意兩個點(diǎn),來看下代碼段
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! ReAudioListTableViewCell
//如果首次播放 curIndex 沒有賦值 粪般,需要特殊處理一下
if isfirst
{
//記錄當(dāng)前選中索引
//已非第一次選中
isfirst = false
//運(yùn)行定時器
timeTick = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "playingAction", userInfo: nil, repeats: true)
// NSRunLoop.currentRunLoop().addTimer(timeTick, forMode: NSRunLoopCommonModes)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
cell.startPlay()
//////////////////////////////////注意
////////////curIndex = indexPath 需要寫在timeTick.fire() 之前拼余,因?yàn)閒ire() 會讓定時器先跑完一次方法,才會執(zhí)行下面的代碼亩歹,由于這個curIndex 賦值在定時器方法用到匙监,所以需要先賦值,如果想改變可以將定時器放入隊(duì)列中
curIndex = indexPath
timeTick.fire()
}
else
{
//如果上次選中和當(dāng)前選中索引相同捆憎,說明用戶再次點(diǎn)擊正在播放的cell舅柜,希望音樂暫停
if(curIndex.row == indexPath.row)
{
//如果正在播放
if isPlay == true
{
isPlay = false
cell.stopPlay()
timeTick.invalidate()
}
else
{
cell.startPlay()
isPlay = true
timeTick = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "playingAction", userInfo: nil, repeats: true)
NSRunLoop.currentRunLoop().addTimer(timeTick, forMode: NSRunLoopCommonModes)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
cell.playBtn.selected = true
timeTick.fire()
curIndex = indexPath
}
}
//點(diǎn)擊一個新的cell播放
else
{
//////////////////////////////////注意
////////////需要判斷l(xiāng)astcell 是否為空,如果lastcell 不可見可能會為空
if let lastcell : ReAudioListTableViewCell = tableView1.cellForRowAtIndexPath(curIndex) as? ReAudioListTableViewCell {
lastcell.stopPlay()
}
if RecorderTool.getTool().player.playing {
RecorderTool.getTool().player.stop()
}
//當(dāng)前cell 開始播放
cell.startPlay()
isPlay = true
//設(shè)置定時器
timeTick = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "playingAction", userInfo: nil, repeats: true)
NSRunLoop.currentRunLoop().addTimer(timeTick, forMode: NSRunLoopCommonModes)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
curIndex = indexPath
timeTick.fire()
}
}
}
demo 的鏈接如下 躲惰,如果有說的不對地方致份,各位大神多多指教
https://github.com/heysunnyboy/audioList.git