Подтвердить что ты не робот

Выравнивание справа налево на UICollectionView

Это довольно простой вопрос, но я не смог найти окончательного ответа на него на SO (если бы я пропустил его, пожалуйста, исправьте меня).

В основном, мой вопрос: Можно ли выровнять содержимое строки UICollectionView справа налево, а не слева направо?

В моих исследованиях я видел ответы, предлагающие подклассификацию UICollectionViewFlowLayout, но мне не удалось найти пример, где он был создан для выравнивания по правому краю.

Моя цель состоит в том, чтобы создать 2 вида коллекции таким образом:

Example

Любая помощь очень ценится!

4b9b3361

Ответ 1

Вы можете получить аналогичный результат, выполнив преобразование в виде коллекции и перевернув флип в его содержимом:

Сначала при создании UICollectionView я выполнил горизонтальный щелчок на нем:

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

Затем подкласс UICollectionViewCell и здесь сделаем один и тот же горизонтальный флип на его contentView:

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

Ответ 2

Не делая Xtransform для коллекции, просто принудительно RTL:

YourCollectionView.semanticContentAttribute = UISemanticContentAttribute.forceRightToLeft

Ответ 3

В дополнение к ответу Tawfik:

Вы также можете установить свойство UICollectionView Semantic через Interface Builder:

Раскадровка

Подробнее об этом свойстве: в этом вопросе

Ответ 4

Начиная с iOS 9, Collection Views поддерживает RTL в соответствии с этим видео WWDC. Поэтому больше не требуется создавать макет потока RTL (если вы уже не используете собственный макет).

Выберите: Изменить схему... > Параметры > Выполнить > Язык приложения > Справа налево Псевдоязык

enter image description here

Когда вы создадите Simulator, текст будет выровнен по правому краю, и ваш Collection View будет упорядочен справа налево.

enter image description here

Однако есть проблема. Когда contentOffset.x == 0, позиция прокрутки Collection View находится на Left краю (неверно) вместо Right края (правильно). Подробнее см. В статье этого стека.

Одним из способов является просто прокрутить 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, поэтому у меня не было доступа к 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 на этом git-репо. И для контекста см. Этот пост в блоге и его комментарии.

enter image description here

Ответ 5

Для любого, кто пытается получить расположение "Право налево" UICollectionView в Swift

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

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

Ответ 6

Для тех, у кого такой же вопрос:

В итоге я использовал библиотеку UICollectionViewRightAlignedLayout, которую рекомендовал @chinttu-roxen-ramani. Вы можете установить его с помощью кода:

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

или через конструктор интерфейса:

Through interface builder

В итоге я сделал пару изменений в библиотеке, но в целом она прекрасно работает.

Ответ 7

Вы можете использовать это начиная с iOS 11:

extension UICollectionViewFlowLayout {

    open override var flipsHorizontallyInOppositeLayoutDirection: Bool {
        return true
    }

}

Ответ 8

Изменяя оба параметра flipsHorizontallyInOppositeLayoutDirection и developmentLayoutDirection, я смог добиться полноэкранного RTL-прокрутки, где первый элемент находился полностью вправо, а чтобы добраться до последней ячейки, пользователь должен будет прокрутить влево.

Вот так:

class RTLCollectionViewFlowLayout: UICollectionViewFlowLayout {

    override var flipsHorizontallyInOppositeLayoutDirection: Bool {
        return true
    }

    override var developmentLayoutDirection: UIUserInterfaceLayoutDirection {
        return UIUserInterfaceLayoutDirection.rightToLeft
    }
}

Ответ 9

Для iOS 9+

  1. Обратный ваш collectionView в viewDidLoad() с этим:

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

  2. Обратно-Назад вашей ячейки (потому что все вещи отражаются) в cellForItemAt с этим:

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

Теперь содержимое находится справа, а прокрутка начинается справа.

Ответ 10

Ни один из приведенных выше ответов не помог мне. Основной причиной было то, что большинство из них не являются полными. Тем не менее, я нашел это решение от этой ссылки от AlexSerdobintsev.

В 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);
    }
}

Ответ 11

Из того, что я могу сказать, все эти ответы хотят заполнить представление коллекции справа налево. Например, если вы пометили ячейки 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
    }

}