Выравнивание справа налево на UICollectionView
Это довольно простой вопрос, но я не смог найти окончательного ответа на него на SO (если бы я пропустил его, пожалуйста, исправьте меня).
В основном, мой вопрос: Можно ли выровнять содержимое строки UICollectionView
справа налево, а не слева направо?
В моих исследованиях я видел ответы, предлагающие подклассификацию UICollectionViewFlowLayout
, но мне не удалось найти пример, где он был создан для выравнивания по правому краю.
Моя цель состоит в том, чтобы создать 2 вида коллекции таким образом:
![Example]()
Любая помощь очень ценится!
Ответы
Ответ 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+
-
Обратный ваш collectionView в viewDidLoad() с этим:
myCollectionView.transform = CGAffineTransform (scaleX: -1, y: 1)
-
Обратно-Назад вашей ячейки (потому что все вещи отражаются) в 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
}
}