在 UICollectionView:打造時(shí)間軸布局里雨女,實(shí)現(xiàn)橫向滾動(dòng)的時(shí)間軸布局時(shí),當(dāng)滑動(dòng)到末尾時(shí)阳准,遇到了下面的問(wèn)題:
NSInternalInconsistencyException: layout attributes for xxx changed from xxx to xxx without invalidating the layout.
搜索一番后沒(méi)有發(fā)現(xiàn)有效的措施氛堕,也沒(méi)有找到具體的原因。其實(shí)上面已經(jīng)告訴了問(wèn)題所在野蝇,但初期毫無(wú)頭緒讼稚,如果你在此時(shí)插入invalidateLayout()
更新布局則會(huì)發(fā)生無(wú)限調(diào)用自身的情況。在使用 Header 來(lái)?yè)?dān)當(dāng)軸線的時(shí)候在看上去非橙粕颍苛刻的條件下會(huì)遇到這種情況锐想,但要湊齊其實(shí)也不是很難,不過(guò)最終我改動(dòng)了其他部分的代碼乍狐,這個(gè)又無(wú)法復(fù)現(xiàn)了赠摇。
不過(guò),我剛開始使用 DecorationView 來(lái)實(shí)現(xiàn)這根軸線的時(shí)候這個(gè)問(wèn)題一直存在浅蚪,后來(lái)無(wú)意中解決了藕帜,終于發(fā)現(xiàn)了問(wèn)題所在。剛開始我設(shè)定 DecorationView 在 X 軸方向上的起始和終點(diǎn)位置與當(dāng)前可視區(qū)域有關(guān):
if let decorationViewLayoutAttr = self.layoutAttributesForDecorationViewOfKind(decorationLineViewKind, atIndexPath: NSIndexPath(forItem: 0, inSection: 0)){
let timelineStartX = rect.origin.x//如果有 header 存在惜傲,則起點(diǎn)設(shè)置為 header 的終點(diǎn)
let timelineEndX = rect.origin.x + rect.width//如果有 footer 存在洽故,則終點(diǎn)設(shè)置為 footer 的起點(diǎn)
decorationViewLayoutAttr.frame = CGRect(x: timelineStartX, y: timelineY, width: timelineEndX - timelineStartX, height: lineThickness)
layoutAttrs?.append(decorationViewLayoutAttr)
}
當(dāng)滑動(dòng)到末尾時(shí),我們往往會(huì)繼續(xù)滑動(dòng)盗誊,這時(shí)布局系統(tǒng)會(huì)要求超過(guò)了 contentSize 區(qū)域的布局信息收津,在這個(gè)過(guò)程中 DecorationView 的布局信息發(fā)生了變化,導(dǎo)致了異常浊伙;盡管在之前的滑動(dòng)過(guò)程中撞秋,DecorationView 的布局信息也一直在變化,但在末尾時(shí)的邊界情況還是導(dǎo)致了異常嚣鄙,只能猜測(cè)這是內(nèi)部實(shí)現(xiàn)的問(wèn)題车猬。更改 DecorationView 的布局為從第一段中點(diǎn)到最后一段中點(diǎn)尝江,這時(shí)候 DecorationView 的布局在全程都是相同的阵难,問(wèn)題消失鞋喇,這下異常提示的信息能夠明白了吧。不過(guò)卧蜓,這里有多個(gè)值都在變化帐要,應(yīng)該用單值變化參照一下:只將 DecorationView 的起始位置設(shè)定為可視區(qū)域的起點(diǎn),其他值不變弥奸,同樣觸發(fā)這個(gè)異常榨惠,證明了猜測(cè)是對(duì)的。
總結(jié)下:如果有元素的布局是動(dòng)態(tài)變化的,那么確保在 top 或 bottom 位置不要再變化了赠橙,不然就會(huì)觸發(fā)這個(gè)異常耽装。