问题描述
我有一个 UICollectionView
,并且想要水平显示单元格,例如
I have a UICollectionView
and want to display cells horizontally, e.g.
英语,它应显示: |cellA |cellB |cellC |
阿拉伯语,它应显示: [cellC |cellB |cellA |
对于RTL,如果每个单元格的大小相同,则默认情况下 UICollectionViewFlowLayout
可以正常工作.但是,如果我实现 collectionView:layout:sizeForItemAtIndexPath:
并为每个单元格设置不同的宽度,则 CollectionView 变为:
For RTL, the UICollectionViewFlowLayout
works fine by default for me if every cell has the same size. However, if I implement collectionView:layout:sizeForItemAtIndexPath:
and set different widths for each cell, the CollectionView becomes:
|cellA |cellB |cellC |
| cellA | cellB | cellC |
有什么办法可以解决这个问题?
Is there any way to fix this?
推荐答案
您需要创建自己的 UICollectionViewLayout
,正如我在评论中所说,我们将向后开始,首先需要添加此内容 ViewController
viewDidLoad
方法上的行
You need to create your own UICollectionViewLayout
, as I said in my comment, we will start backwards, first you need to add this lines on your ViewController
viewDidLoad
method
let semanticLayout = SemanticLayout()
semanticLayout.delegate = self
self.collectionView.collectionViewLayout = semanticLayout
这是您需要实现的委托
extension ViewController: SemanticLayoutDelegate{
func semanticDisposition() -> SemanticDisposition {
return SemanticDisposition.rigthToLeft
}
}
使用您的ViewController名称而不是c的ViewController
using your ViewController name instead of ViewController ofc
这里有 SemanticLayout
类,检查是否可以完全自定义,您可以定义您的 UICollectionView
是带有委托的RTL还是LTR方法 semanticDisposition
And here you have the SemanticLayout
class, check that is fully customizable you can define if your UICollectionView
will be RTL or LTR with delegate method semanticDisposition
import UIKit
protocol SemanticLayoutDelegate: UICollectionViewDelegateFlowLayout {
func semanticDisposition() -> SemanticDisposition
}
enum SemanticDisposition {
case leftToRigth
case rigthToLeft
}
class SemanticLayout: UICollectionViewLayout {
weak var delegate: SemanticLayoutDelegate!
fileprivate var cellPadding: CGFloat = 10
fileprivate var cache = [UICollectionViewLayoutAttributes]()
fileprivate var contentHeight: CGFloat = 0
private var rowsWidth : [CGFloat] = [0]
private var avaiableSpaces : [(Int,CGFloat)] = []
private var currentRow : Int = 0
private var rowHeigths : CGFloat = -1.0
fileprivate var contentWidth: CGFloat {
guard let collectionView = collectionView else {
return 0
}
let insets = collectionView.contentInset
return collectionView.bounds.width - (insets.left + insets.right)
}
private func availableWidthForRow(index:Int) -> CGFloat {
let ocuppedWidth = self.rowsWidth[index]
return self.contentWidth - ocuppedWidth
}
private func canAddCellAtRow(rowIndex:Int,size:CGSize) ->Bool
{
if(availableWidthForRow(index: rowIndex) >= size.width) {
return true
}
return false
}
override var collectionViewContentSize: CGSize {
return CGSize(width: contentWidth, height: contentHeight)
}
override func prepare() {
// Check if cache is empty
guard cache.isEmpty == true, let collectionView = collectionView else {
return
}
for item in 0 ..< collectionView.numberOfItems(inSection: 0) {
let indexPath = IndexPath(item: item, section: 0)
let viewSize: CGSize = delegate.collectionView!(collectionView, layout: self, sizeForItemAt: indexPath)
if(self.rowHeigths < 0) {
self.rowHeigths = viewSize.height
}
let width = viewSize.width
let height = viewSize.height
var xOffset = self.rowsWidth[self.currentRow]
if(self.canAddCellAtRow(rowIndex: self.currentRow, size: viewSize)) {
if(self.delegate.semanticDisposition() == .rigthToLeft) {
xOffset = (contentWidth - self.rowsWidth[self.currentRow]) - width
}
} else {
self.currentRow += 1
self.rowsWidth.append(0.0)
xOffset = self.rowsWidth[self.currentRow]
if(self.delegate.semanticDisposition() == .rigthToLeft) {
xOffset = (contentWidth - self.rowsWidth[self.currentRow]) - width
}
}
let yOffset = CGFloat(self.currentRow) * self.rowHeigths
let frame = CGRect(x: xOffset, y: yOffset, width: width, height: height)
let insetFrame = frame.insetBy(dx: cellPadding, dy: cellPadding)
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attributes.frame = insetFrame
cache.append(attributes)
contentHeight = max(contentHeight, frame.maxY)
self.rowsWidth[self.currentRow] += width
}
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var visibleLayoutAttributes = [UICollectionViewLayoutAttributes]()
// Loop through the cache and look for items in the rect
for attributes in cache {
if attributes.frame.intersects(rect) {
visibleLayoutAttributes.append(attributes)
}
}
return visibleLayoutAttributes
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return cache[indexPath.item]
}
}
结果 RTL
LTR
这篇关于UICollectionView不会在RTL中从右到左填充数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!