我有一个UICollectionView
,想水平显示单元格,例如
英语,它应显示: | cellA | cellB | cellC |
阿拉伯语,它应显示: [cellC | cellB | cellA |
对于RTL,如果每个单元格的大小相同,默认情况下UICollectionViewFlowLayout
可以正常工作。但是,如果我实现collectionView:layout:sizeForItemAtIndexPath:
并为每个单元格设置不同的宽度,则 CollectionView 变为:
| cellA | cellB | cellC |
有什么办法可以解决这个问题?
答案 0 :(得分:1)
您需要创建自己的UICollectionViewLayout
,正如我在评论中所说,我们将倒退,首先需要在ViewController
viewDidLoad
方法上添加以下行
let semanticLayout = SemanticLayout()
semanticLayout.delegate = self
self.collectionView.collectionViewLayout = semanticLayout
这是您需要实现的委托
extension ViewController: SemanticLayoutDelegate{
func semanticDisposition() -> SemanticDisposition {
return SemanticDisposition.rigthToLeft
}
}
使用您的ViewController名称而不是c的ViewController
这里有SemanticLayout
类,请检查可完全自定义,您可以使用委托方法UICollectionView
定义semanticDisposition
是RTL还是LTR
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
答案 1 :(得分:1)
class RTLSupportedCollectionViewFlowLayout: UICollectionViewFlowLayout {
override var flipsHorizontallyInOppositeLayoutDirection: Bool {
return true
}
}
您可以使用此流布局。仅当返回的项目大小对于所有单元格都不相同时才需要。
答案 2 :(得分:0)
该课程对我来说非常有用,可以从左到右显示不同大小的单元格的集合视图。
#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
希望此帮助。让我知道是否需要进一步的帮助。
答案 3 :(得分:0)
首先,当创建UICollectionView时,我对其进行了水平翻转:
collectionView.transform = CGAffineTransform(scaleX: -1, y: 1)
然后子类UICollectionViewCell并在此处对其contentView进行相同的水平翻转:
contentView.transform = CGAffineTransform(scaleX: -1, y: 1)
注意:如果您的单元格中有任何子视图,则也要对其进行转换。例如cell.lblTitle.transform = CGAffineTransform(scaleX:-1,y:1)