Change scroll direction in UICollectionView
Asked Answered
C

4

11

I have a UICollectionView which I have setup, everything works fine (selection, headers, etc), however, I want to change the scroll direction in some situations.

In short if I go into the story board and change the scrollDirection it works fine but I want to do it programatically!

I have tried to change the scroll direction of the collection view directly with something like

    [myCollectionView setScrollDirection:....and so on.......

But this does not work, I can not find scrollDirection or similar in there.

I have also tried to setup a flow layout but I am sure i am doing this wrong (i.e. trying to set a ViewLayout to a FlowLayout).

    UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc]init];
    [flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];
    [myCollectionView setCollectionViewLayout:flowLayout];

This crashes with a lot of Constraint problems and I suspect I need to do a lot more work with the flowLayout (from what I have found it is a bit above me right now).

It should also be noted that I am using a custom cell, headers and footers.

In short is there an easy way to do this or not? OR does anyone know a good Flow Layout tutorial?

EDIT

I setup the collection view as such;

[myCollectionView setDataSource:self];
[myCollectionView setDelegate:self];

I implement these delegate methods and all work fine

viewForSupplementaryElementOfKind
numberOfSectionsInCollectionView
numberOfItemsInSection
cellForItemAtIndexPath
didSelectItemAtIndexPath

I have added the DataSource and Delegate to the .h and also the FlowLayout delegate BUT I am not sure what I should also have for the latter.

Most of the visual layout is done in Story Board, there are a few things such as Font, size and colour which I do programatically.

ANOTHER EDIT

This is the error when I try to change the FlowLayout, I also get this when I try and invalidate the layout.

Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)

"<NSAutoresizingMaskLayoutConstraint:0x89967f0 h=--& v=--& V:[menuCell:0x8991700(50)]>",
"<NSLayoutConstraint:0x8991200 menuCell:0x8991700.bottom == UILabel:0x8992be0.bottom + 100>",
"<NSLayoutConstraint:0x898fd50 UILabel:0x8992be0.top == menuCell:0x8991700.top + 3>"

Will attempt to recover by breaking constraint

Break on objc_exception_throw to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in may also be helpful.

Centrist answered 13/1, 2014 at 16:4 Comment(2)
Does the view where the collection view is drawn conform to the UICollectionViewFlowLayoutDelegate Protocol? Are you sure the amount of content you are trying to draw is large enough to warrant the collection view to actually scroll? Can we see more of the setup of the collection view? You are headed in the right direction by trying to set the scroll direction on the Flow Layout, so good start!Relate
@MatthewHallatt I have added a little more info. This is a big table, there could be 50-60 items in 4 or five sections. The collection view is a long bar at the bottom which scrolls horizontally, button can be clicked which make the collection expand to nearly most of the screen (which is working) but I want the scrolling to move to vertical scrolling.Centrist
R
0

Ok, try calling invalidateLayout on your collection view like so:

[myCollectionView.collectionViewLayout invalidateLayout];

This forces the collection view to update its layout at that point (See apple documentation here). I'm not certain, but I don't imagine this is called when you change the scroll direction.

See if that gets you anywhere near!

Relate answered 13/1, 2014 at 17:29 Comment(11)
I tried this but get the same result, I have for clarity put the entire error in my question too. I am fast getting to the point where I will simple add two collection views and show/hidden them when needed but it seems a waste of resources.Centrist
Are you setting up your own constraints in your cell? If so, programatically or in interface builder? The problem seems to be that you're maybe trying to keep the label height the same, but keep it a certain distance from both the top and the bottom of the cell. If you are setting your own constraints, try removing the one holding the label to the bottom of the cell, or maybe the one constraining the height of the label. Or maybe I've been barking up the wrong tree with this whole comment!Relate
It does look like it is all done in interface builder. The are no constraints set in there so I assume they are done automatically. I tried to add some but the same.Centrist
Are you doing anything in the 'prepareForReuse' method on your cells? If not, try setting the text of the label to nil (@"") and any images to nil as well whilst you're at it, just in case!Relate
I have tried return nil for the view in viewForSupplementaryElementOfKind which draws the headers and footers but that did the same. I amy make a copy and remove the whole header footer thing because (as you say) it is looking like something there.Centrist
and no not using prepareForReuse.Centrist
Are you using a custom subclass of UICollectionViewCell, or just the default? You say the cell is set up in interface builder: you should be able to turn off Autolayout in the first tab of the Utilities pane on the right hand side (See goodbyehelicopter.com/2012/02/… for example). See if that helps. The errors caused are definitely down to Autolayout, so turning it off should fix those errors, but your cells may look wrong.Relate
I will try without Autolayout. I am fast coming to the conclusion that Autolayout is useless your app changes orientation and contains lots of complicated components.Centrist
@MatthewHallett I have removed Autolayout which has stopped the crash, however, the collectionView does not change scroll direction. I am changing the flowLayout as before and invalidating the layout, is there anything else?Centrist
Got it to work (small error), this has also fixed with the Autolayout.Centrist
let us continue this discussion in chatRelate
K
20

do this:

- (IBAction)changeDirection:(UIButton *)sender
{
     UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)[self.collectionView collectionViewLayout];
     if(layout.scrollDirection == UICollectionViewScrollDirectionHorizontal)
     {
        layout.scrollDirection = UICollectionViewScrollDirectionVertical;
     }
     else
     {
         layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
     }
}

It works for me.

Kirkkirkcaldy answered 28/3, 2014 at 16:23 Comment(2)
Still doesn't works for me. Even if I call [layout invalidateLayout] after that changesLimpet
Glad to be of help :)Kirkkirkcaldy
D
5

In swift you can do this:

//From the collection view subclass
    if let layout: UICollectionViewFlowLayout = self.collectionViewLayout as? UICollectionViewFlowLayout {
        layout.scrollDirection = .Vertical
    }
Dogcatcher answered 6/11, 2015 at 22:48 Comment(0)
R
0

Ok, try calling invalidateLayout on your collection view like so:

[myCollectionView.collectionViewLayout invalidateLayout];

This forces the collection view to update its layout at that point (See apple documentation here). I'm not certain, but I don't imagine this is called when you change the scroll direction.

See if that gets you anywhere near!

Relate answered 13/1, 2014 at 17:29 Comment(11)
I tried this but get the same result, I have for clarity put the entire error in my question too. I am fast getting to the point where I will simple add two collection views and show/hidden them when needed but it seems a waste of resources.Centrist
Are you setting up your own constraints in your cell? If so, programatically or in interface builder? The problem seems to be that you're maybe trying to keep the label height the same, but keep it a certain distance from both the top and the bottom of the cell. If you are setting your own constraints, try removing the one holding the label to the bottom of the cell, or maybe the one constraining the height of the label. Or maybe I've been barking up the wrong tree with this whole comment!Relate
It does look like it is all done in interface builder. The are no constraints set in there so I assume they are done automatically. I tried to add some but the same.Centrist
Are you doing anything in the 'prepareForReuse' method on your cells? If not, try setting the text of the label to nil (@"") and any images to nil as well whilst you're at it, just in case!Relate
I have tried return nil for the view in viewForSupplementaryElementOfKind which draws the headers and footers but that did the same. I amy make a copy and remove the whole header footer thing because (as you say) it is looking like something there.Centrist
and no not using prepareForReuse.Centrist
Are you using a custom subclass of UICollectionViewCell, or just the default? You say the cell is set up in interface builder: you should be able to turn off Autolayout in the first tab of the Utilities pane on the right hand side (See goodbyehelicopter.com/2012/02/… for example). See if that helps. The errors caused are definitely down to Autolayout, so turning it off should fix those errors, but your cells may look wrong.Relate
I will try without Autolayout. I am fast coming to the conclusion that Autolayout is useless your app changes orientation and contains lots of complicated components.Centrist
@MatthewHallett I have removed Autolayout which has stopped the crash, however, the collectionView does not change scroll direction. I am changing the flowLayout as before and invalidating the layout, is there anything else?Centrist
Got it to work (small error), this has also fixed with the Autolayout.Centrist
let us continue this discussion in chatRelate
S
0

You can do it with property observer didSet{} with your collection view outlet.

Assuming that the outlet for the collectionView is myCollectionView, in the code add a didSet property observer to the outlet and change the layout's direction. Something like-

@IBOutlet weak var myCollectionView:UICollectionView!{
      didSet{
            let layout = contentCollectionView.collectionViewLayout as!
UICollectionViewFlowLayout
            layout.scrollDirection = .Vertical
        }
}

Normally a collectionView is dropped in storyboard from object library, it automatically comes with FlowLayout. You can change this layout's flow direction by telling your code that when I get my collection view, I want its layout's scroll direction to be horizontal or vertical.

Significs answered 3/6, 2019 at 1:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.