本文介绍了UICollectionView不会在RTL中从右到左填充数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 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中从右到左填充数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 22:55