Aligning right to left on UICollectionView

前端 未结 13 627
悲哀的现实
悲哀的现实 2020-12-02 08:31

this is a pretty straightforward question, but I haven\'t been able to find a definitive answer to it on SO (if I missed it, please correct me).

Basically, my quest

相关标签:
13条回答
  • 2020-12-02 09:22

    Non of the above answers worked for me. The main reason was that most of them are not complete. However, I found this solution from this link by AlexSerdobintsev.

    In AppDelegate.cs. First, you have to import the following function

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

    Then call the function inside FinishedLaunching

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

    voila! we are done. Here is the file after applying the changes:

        [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);
        }
    }
    
    0 讨论(0)
  • 2020-12-02 09:23

    Without doing any Xtransform to the collection view, simply forced RTL:

    YourCollectionView.semanticContentAttribute = UISemanticContentAttribute.forceRightToLeft
    
    0 讨论(0)
  • 2020-12-02 09:25

    UICollectionView already support rtl direction if UICollectionViewFlowLayout is not dynamic.

    Changing Estimate size to None as the image shows automatically changed the direction of the CollectionView.

    One more issue is to scroll to the end of the collection view after reloading data.

    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)
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-02 09:26

    As of iOS 9, Collection Views support RTL according to this WWDC video. So it's no longer necessary to create an RTL flow layout (unless you're already using a custom layout).

    Select: Edit Scheme... > Options > Run > Application Language > Right to Left Pseudolanguage

    When you build to Simulator, text will be right-aligned, and your Collection View will be ordered from Right to Left.

    There's a problem though. When contentOffset.x == 0, the Collection View scroll position is at the Left edge (wrong) instead of the Right edge (correct). See this stack article for details.

    One workaround is to simply scroll the First item to the .Left (There's a gotcha -- .Left is actually on the Right, or Leading edge):

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

    In my test project, my Collection View was nested inside a Table View Cell, so I didn't have access to viewDidAppear(). So instead, I ended up hooking into 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)
        }
    }
    

    To see this in action, check out the RTL branch on this git repo. And for context, see this blog post and its comments.

    0 讨论(0)
  • 2020-12-02 09:27

    you can use this since iOS 11:

    extension UICollectionViewFlowLayout {
    
        open override var flipsHorizontallyInOppositeLayoutDirection: Bool {
            return true
        }
    
    }
    
    0 讨论(0)
  • 2020-12-02 09:29
    extension UICollectionViewFlowLayout {
    
        open override var flipsHorizontallyInOppositeLayoutDirection: Bool {
            return true
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题