在UICollectionView上从右向左对齐

时间:2014-09-01 02:41:41

标签: ios objective-c uicollectionview right-to-left uicollectionviewlayout

这是一个非常简单的问题,但我无法在SO上找到明确的答案(如果我错过了,请纠正我)。

基本上,我的问题是: 是否可以从右到左而不是从左到右对齐UICollectionView行内容?

在我的研究中,我看到了建议继承UICollectionViewFlowLayout的答案,但我找不到一个为右对齐创建一个例子的例子。

我的目标是设置2个集合视图:

Example

非常感谢任何帮助!

15 个答案:

答案 0 :(得分:81)

您可以通过对集合视图执行转换并反转其内容的翻转来获得类似的结果:

首先在创建UICollectionView时,我对它执行了水平翻转:

[collectionView_ setTransform:CGAffineTransformMakeScale(-1, 1)];

然后子类UICollectionViewCell并在此处对其contentView执行相同的水平翻转:

[self.contentView setTransform:CGAffineTransformMakeScale(-1, 1)];

答案 1 :(得分:77)

不对集合视图执行任何Xtransform,只需强制RTL:

YourCollectionView.semanticContentAttribute = UISemanticContentAttribute.forceRightToLeft

答案 2 :(得分:19)

除了Tawfik的回答:

您还可以通过Interface Builder设置UICollectionView的Semantic属性:

Storyboard

有关此媒体资源的更多信息:in this question

答案 3 :(得分:12)

从iOS 9开始,集合视图根据此WWDC video支持RTL。因此,不再需要创建RTL流布局(除非您已经使用自定义布局)。

选择:编辑方案... > 选项> 运行> 应用程序语言> 从左到右的伪语言

enter image description here

当您构建到模拟器时,文本将右对齐,并且您的集合视图将从右到左排序。

enter image description here

但是有一个问题。 contentOffset.x == 0时,“收藏视图”滚动位置位于Left边缘(错误),而不是Right边缘(正确)。有关详细信息,请参阅此stack article

一种解决方法是只需将First项滚动到.Left(有一个问题 - .Left实际上是正确,或领先边缘):

override func viewDidAppear(animated: Bool) {
    if collectionView?.numberOfItemsInSection(0) > 0  {
        let indexPath = NSIndexPath(forItem: 0, inSection: 0)
        collectionView?.scrollToItemAtIndexPath(indexPath, atScrollPosition: .Left, animated: false)
    }
}

在我的测试项目中,我的Collection View嵌套在Table View Cell中,因此我无法访问viewDidAppear()。所以相反,我最终挂钩drawRect()

class CategoryRow : UITableViewCell {
    @IBOutlet weak var collectionView: UICollectionView!

    override func drawRect(rect: CGRect) {
        super.drawRect(rect)
        scrollToBeginning()
    }

    override func prepareForReuse() {
        scrollToBeginning()
    }

    func scrollToBeginning() {
        guard collectionView.numberOfItems(inSection: 0) > 0 else { return }
        let indexPath = IndexPath(item: 0, section: 0)
        collectionView.scrollToItem(at: indexPath, at: .left, animated: false)
    }
}

要查看此操作,请查看RTL branch on this git repo。有关上下文,请参阅此blog post and its comments

enter image description here

答案 4 :(得分:11)

对于任何试图在Swift中实现UICollectionView的从右到左布局的人

//in viewDidLoad
    YourCollectionView.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)

//in cellForItemAtIndexPath
    cell.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)

答案 5 :(得分:6)

对于有同样问题的人:

我最终使用@ chinttu-roxen-ramani推荐的UICollectionViewRightAlignedLayout library。您可以使用代码设置它:

self.collectionView.collectionViewLayout = [[UICollectionViewRightAlignedLayout alloc] init];

或通过界面构建​​器:

Through interface builder

我最终对图书馆进行了一些修改,但总的来说它很有效。

答案 6 :(得分:5)

extension UICollectionViewFlowLayout {

    open override var flipsHorizontallyInOppositeLayoutDirection: Bool {
        return true
    }

}

答案 7 :(得分:3)

您可以从iOS 11开始使用它:

extension UICollectionViewFlowLayout {

    open override var flipsHorizontallyInOppositeLayoutDirection: Bool {
        return true
    }

}

答案 8 :(得分:2)

通过同时更改 SELECT assets.*, templates.* , json_agg(to_json(fields)) as field FROM public.assets LEFT JOIN public.templates ON templates.id = assets.id_template LEFT JOIN public.fields ON fields.id_template = templates.id WHERE assets.id = $1 GROUP BY (all variables till json_agg); flipsHorizontallyInOppositeLayoutDirection,我可以实现全屏RTL滚动,其中第一项一直向右滚动并到达最后一个单元格,用户需要向左滚动。

像这样:

developmentLayoutDirection

答案 9 :(得分:1)

据我所知,所有这些答案都希望从右到左填充集合视图。例如,如果标记了单元格1、2、3,则它们将以3、2、1的顺序出现在集合视图中。在我的情况下,我希望单元格以1、2、3的顺序显示(例如,当行未满时,文本右对齐)。为此,我创建了一个简单的UICollectionViewFlow布局。

import UIKit

class RightAlignFlowLayout: UICollectionViewFlowLayout {

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]?
    {
        guard let attrsArr = super.layoutAttributesForElements(in: rect) else {
            return nil
        }
        guard let collectionView = self.collectionView else { return attrsArr }
        if self.collectionViewContentSize.width > collectionView.bounds.width {
            return attrsArr
        }

        let remainingSpace = collectionView.bounds.width - self.collectionViewContentSize.width

        for attr in attrsArr {
            attr.frame.origin.x += remainingSpace
        }

        return attrsArr
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        guard let attrs = super.layoutAttributesForItem(at: indexPath) else { return nil }
        guard let collectionView = self.collectionView else { return attrs }
        if self.collectionViewContentSize.width > collectionView.bounds.width {
            return attrs
        }

        let remainingSpace = collectionView.bounds.width - self.collectionViewContentSize.width
        attrs.frame.origin.x += remainingSpace
        return attrs
    }

}

答案 10 :(得分:0)

对于Swift 4.2 和iOS 9 +

  1. 使用以下命令在 viewDidLoad()中反转您的collectionView:

    myCollectionView.transform = CGAffineTransform(scaleX:-1,y:1)

  2. 使用以下命令在 cellForItemAt 中反向回退您的单元格(因为所有内容均已镜像):

    cell.transform = CGAffineTransform(scaleX:-1,y:1)

现在内容在右侧,并且从右侧开始滚动。

答案 11 :(得分:0)

以上所有答案均不适用于我。主要原因是大多数都不完整。但是,我从this linkAlexSerdobintsev找到了这个解决方案。

在AppDelegate.cs中。首先,您必须导入以下功能

[DllImport(ObjCRuntime.Constants.ObjectiveCLibrary, EntryPoint = "objc_msgSend")]
internal extern static IntPtr IntPtr_objc_msgSend(IntPtr receiver, IntPtr selector, UISemanticContentAttribute arg1);

然后调用FinishedLaunching内部的函数

        var selector = new ObjCRuntime.Selector("setSemanticContentAttribute:");
        IntPtr_objc_msgSend(UIView.Appearance.Handle, selector.Handle, UISemanticContentAttribute.ForceRightToLeft);

瞧!我们完了。 这是应用更改后的文件:

    [Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
    [DllImport(ObjCRuntime.Constants.ObjectiveCLibrary, EntryPoint = "objc_msgSend")]
    internal extern static IntPtr IntPtr_objc_msgSend(IntPtr receiver, IntPtr selector, UISemanticContentAttribute arg1);


    //
    // This method is invoked when the application has loaded and is ready to run. In this 
    // method you should instantiate the window, load the UI into it and then make the window
    // visible.
    //
    // You have 17 seconds to return from this method, or iOS will terminate your application.
    //
    public override bool FinishedLaunching(UIApplication app, NSDictionary options)
    {
        global::Xamarin.Forms.Forms.SetFlags("Shell_Experimental", "Visual_Experimental", "CollectionView_Experimental", "FastRenderers_Experimental");
        global::Xamarin.Forms.Forms.Init();
        LoadApplication(new App());

        ...

        var selector = new ObjCRuntime.Selector("setSemanticContentAttribute:");
        IntPtr_objc_msgSend(UIView.Appearance.Handle, selector.Handle, UISemanticContentAttribute.ForceRightToLeft);

        return base.FinishedLaunching(app, options);
    }
}

答案 12 :(得分:0)

UICollectionView如果UICollectionViewFlowLayout不是动态的,则已经支持rtl方向。

将图像的估算尺寸更改为“无”,会自动更改CollectionView的方向。

enter image description here

另一个问题是在重新加载数据后滚动到集合视图的末尾。

extension UICollectionView {
    
    func scrollToEndIfArabic() {
        if Language.shared.isArabic() {
            DispatchQueue.main.async {
                self.contentOffset
                    = CGPoint(x: self.contentSize.width
                        - self.frame.width
                        + self.contentInset.right, y: 0)
            }
        }
    }
}

答案 13 :(得分:0)

以上答案都不适合我。所以最后我解决了这个问题。我将 RTL 用于 2 种语言(阿拉伯语、法语) 这是我的解决方案

<块引用>

使用此行从左到右转移集合视图

let LangCheck = PPLocalization.sharedInstance.getLanguage(forAPI: true)
if(LangCheck == "ar"){
   CollectionView.transform = CGAffineTransform(scaleX: -1, y: 1);
}
<块引用>

使用此行使您的标签适合您的集合视图单元格

let LangCheck = PPLocalization.sharedInstance.getLanguage(forAPI: true)
  if(LangCheck == "ar"){
     cell.lbCategoryName.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
  }

答案 14 :(得分:0)

添加以下扩展对我有用

extension UICollectionViewFlowLayout {
    open override var flipsHorizontallyInOppositeLayoutDirection: Bool {
        return true  //RETURN true if collection view needs to enable RTL
    }
}