UICollectionView не заполняет данные справа налево в RTL - PullRequest
0 голосов
/ 07 января 2019

У меня есть UICollectionView и я хочу отображать ячейки по горизонтали, например,

На английском языке должно отображаться: | CellA | cellB | cellC |

На арабском должно отображаться: [cellC | cellB | cellA |

Для RTL UICollectionViewFlowLayout отлично работает по умолчанию для меня, если каждая ячейка имеет одинаковый размер. Однако, если я реализую collectionView:layout:sizeForItemAtIndexPath: и установлю разные ширины для каждой ячейки, CollectionView становится:

| CellA | cellB | cellC |

Есть ли способ это исправить?

Ответы [ 3 ]

0 голосов
/ 08 января 2019

Вам нужно создать свой собственный 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]
    }
}

Результат РТЛ

rtl LTR ltr

0 голосов
/ 17 марта 2019
class RTLSupportedCollectionViewFlowLayout: UICollectionViewFlowLayout {

    override var flipsHorizontallyInOppositeLayoutDirection: Bool {
        return true
    }
}

Вы можете использовать эту схему потока. он необходим только в том случае, если возвращаемый размер элемента не одинаков для всех ячеек.

0 голосов
/ 07 января 2019

Этот класс работает для меня, чтобы отображать коллекцию слева направо с разными размерами ячеек.

#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

Надеюсь, это поможет. дайте мне знать, если понадобится дополнительная помощь.

...