Ios UICollectionView没有';t在RTL中从右向左填充数据

Ios UICollectionView没有';t在RTL中从右向左填充数据,ios,right-to-left,collectionview,Ios,Right To Left,Collectionview,我有一个UICollectionView,希望水平显示单元格,例如 在英语中,应显示: | cellA | cellB | cellC | 阿拉伯语,应显示: [cellC | cellB | cellA | 对于RTL,默认情况下,如果每个单元格的大小相同,UICollectionViewFlowLayout对我来说效果很好。但是,如果我实现collectionView:layout:sizeForItemAtIndexPath:并为每个单元格设置不同的宽度,则collectionView将变

我有一个
UICollectionView
,希望水平显示单元格,例如

在英语中,应显示: | cellA | cellB | cellC |

阿拉伯语,应显示: [cellC | cellB | cellA |

对于RTL,默认情况下,如果每个单元格的大小相同,
UICollectionViewFlowLayout
对我来说效果很好。但是,如果我实现
collectionView:layout:sizeForItemAtIndexPath:
并为每个单元格设置不同的宽度,则collectionView将变为:

|细胞|细胞B |细胞C|


有什么方法可以解决这个问题吗?

这个类为我提供了从左到右显示集合视图的功能,其中包含不同大小的单元格

#import <UIKit/UIKit.h>
#import <objc/runtime.h>

static const char kBundleKey = 0;

@interface BundleEx : NSBundle

@end

@implementation BundleEx

- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName
{
    NSBundle *bundle = objc_getAssociatedObject(self, &kBundleKey);
    if (bundle) {
        return [bundle localizedStringForKey:key value:value table:tableName];
    }
    else {
        return [super localizedStringForKey:key value:value table:tableName];
    }
}

@end

@implementation NSBundle (Language)

+ (void)setLanguage:(NSString *)language
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        object_setClass([NSBundle mainBundle], [BundleEx class]);
    });
    if (isCurrentLanguageRTL) {
        if ([[[UIView alloc] init] respondsToSelector:@selector(setSemanticContentAttribute:)]) {
            [[UIView appearance] setSemanticContentAttribute:UISemanticContentAttributeForceRightToLeft];
            [[UITableView appearance] setSemanticContentAttribute:UISemanticContentAttributeForceRightToLeft];
        }
    }else {
        //FOR LTR
        if ([[[UIView alloc] init] respondsToSelector:@selector(setSemanticContentAttribute:)]) {
            [[UIView appearance] setSemanticContentAttribute:UISemanticContentAttributeForceLeftToRight];
            [[UITableView appearance] setSemanticContentAttribute:UISemanticContentAttributeForceLeftToRight];
        }
    }
    [[NSUserDefaults standardUserDefaults] synchronize];

    id value = language ? [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]] : nil;
    objc_setAssociatedObject([NSBundle mainBundle], &kBundleKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end
#导入
#进口
静态常量char kBundleKey=0;
@接口BundleEx:NSBundle
@结束
@实现BundleEx
-(NSString*)localizedStringForKey:(NSString*)键值:(NSString*)值表:(NSString*)表名
{
NSBundle*bundle=objc_getAssociatedObject(self,&kBundleKey);
如果(捆绑){
return[bundle localizedStringForKey:key-value:value-table:tableName];
}
否则{
return[super-localizedStringForKey:key-value:value-table:tableName];
}
}
@结束
@实现包(语言)
+(void)setLanguage:(NSString*)语言
{
静态调度一次;
一次发送(一次发送)^{
对象_setClass([NSBundle mainBundle],[BundleEx class]);
});
if(isCurrentLanguageRTL){
if([[[UIView alloc]init]respondsToSelector:@selector(setSemanticContentAttribute:)])){
[[UIView外观]setSemanticContentAttribute:UISemanticContentAttributeForceRightToLeft];
[[UITableView外观]setSemanticContentAttribute:UISemanticContentAttributeForceRightToLeft];
}
}否则{
//对于LTR
if([[[UIView alloc]init]respondsToSelector:@selector(setSemanticContentAttribute:)])){
[[UIView外观]setSemanticContentAttribute:UISemanticContentAttributeForceLeftToRight];
[[UITableView外观]setSemanticContentAttribute:UISemanticContentAttributeForceLeftToRight];
}
}
[[NSUserDefaults standardUserDefaults]同步];
id值=语言?[NSBundle bundleWithPath:[[NSBundle mainBundle]pathForResource:类型为@“lproj”的语言]]:nil;
objc_setAssociatedObject([NSBundle mainBundle],&kBundleKey,value,objc_ASSOCIATION_RETAIN_NONATOMIC);
}
@结束

希望有此帮助。如果需要进一步帮助,请告诉我。

您需要创建自己的
UICollectionViewLayout
,正如我在评论中所说,我们将从后面开始,首先您需要在
ViewController
viewDidLoad方法中添加这行代码

let semanticLayout = SemanticLayout()
semanticLayout.delegate = self
self.collectionView.collectionViewLayout = semanticLayout
这是您需要实现的委托

extension ViewController: SemanticLayoutDelegate{
    func semanticDisposition() -> SemanticDisposition {
        return SemanticDisposition.rigthToLeft
    }   
}
使用ViewController名称而不是ViewController ofc

这里有
SemanticLayout
类,检查它是否是完全可定制的您可以定义您的
UICollectionView
是RTL还是LTR,并使用委托方法
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]
    }
}
导入UIKit
协议SemanticalyOutDelegate:UICollectionViewDelegateFlowLayout{
func semanticDisposition()->semanticDisposition
}
枚举语义位置{
案例左图
案例右侧至左侧
}
类SemanticLayout:UICollectionViewLayout{
弱变量委托:SemanticalyOutDelegate!
fileprivate变量cellPadding:CGFloat=10
fileprivate变量缓存=[UICollectionViewLayoutAttribute]()
fileprivate var contentHeight:CGFloat=0
私有变量rowsWidth:[CGFloat]=[0]
私有变量可用空间:[(Int,CGFloat)]=[]
私有变量currentRow:Int=0
私有变量rowHeights:CGFloat=-1.0
fileprivate var contentWidth:CGFloat{
guard let collectionView=collectionView else{
返回0
}
let insets=collectionView.contentInset
return collectionView.bounds.width-(insets.left+insets.right)
}
私有函数可用WidthForrow(索引:Int)->CGFloat{
设ocuppedWidth=self.rowsWidth[index]
返回self.contentWidth-ocuppedWidth
}
私有函数canAddCellAtRow(行索引:Int,大小:CGSize)->Bool
{
if(availableWidthForRow(索引:rowIndex)>=size.width){
返回真值
}
返回错误
}
覆盖变量collectionViewContentSize:CGSize{
返回CGSize(宽度:contentWidth,高度:contentHeight)
}
重写func prepare(){
//检查缓存是否为空
guard cache.isEmpty==true,让collectionView=collectionView else{
返回
}
对于0..class RTLSupportedCollectionViewFlowLayout: UICollectionViewFlowLayout {

    override var flipsHorizontallyInOppositeLayoutDirection: Bool {
        return true
    }
}