I've tried some solutions found on stackoverflow such as
self.collectionView.clipsToBounds = NO;
[self.scrollView setContentOffset:CGPointMake(0, 0)];
And nothing is working.
My collection view has a cell in it and should display one cell at a time. I'm using paging and evertyhing is working fine except that when you go to the second page it cuts a little of the cell off by the screen. And every page you go after that cuts more of the cell of till you get to the last page where half the cell is cut off. I'm doing this on iphone.
What is happening is, your cell is not centered, so as you swipe between them, and the UICollectionView dynamically figures out the spacing of each cell, it gradually becomes more and more off centre, getting the effect you explain.
Ensure that your UICollectionViewCell + UICollectionViewLayout insets equal the width of the contentView of your UICollectionView.
e.g.
On a 320.0f,100.0f UICollectionView. Your cell could be 300.0f,90.0f. And your UICollectionViewLayout (if using a flowLayout), could have the edge insets set to 5.0f,10.0f,5.0f,10.0f.
E.g.
[(UICollectionViewFlowLayout *)collectionView.collectionViewLayout setItemSize:CGSizeMake(320.0f, 100.0f)];
[(UICollectionViewFlowLayout*)collectionView.collectionViewLayout setSectionInset:UIEdgeInsetsMake(5.0f, 10.0f, 5.0f, 10.0f)];
It was min spacing for lines was on 10 so I set it to 0. I think thats a bug in xcode 5 because my collection view is scrolling horizontal not vertical so one would think it would be my min spacing for cells would be wrong
Please make each item in a section, NOT all items in one section.
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return [self.items count];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 1;
}
That's done.
I am using scrollToRowAtIndexPath: to scroll UITableView to top. Then I handle the animation in scrollViewDidEndScrollingAnimation:. After it scrolls, it should perform an action. My problem is, that when it doesn't scroll - e.g. the table view is already on top before I call the method - the action doesn't get called in scrollViewDidEndScrollingAnimation:. How do I find out whether the UITableView is already on top?
if (yourTableView.contentOffset.y > 0)
{
// yourTableView is not on top.
}
else
{
// yourTableView is already on top.
}
Use UITableView contentOffset property. If contentOffset.y is 0 then table is at top else it is not.
Hope it helps you.
You need to use the UIScrollViewDelegate function - (void)scrollViewDidEndDecelerating:(UIScrollView *)aScrollView and work out if the content offset is set to 0 on the y axis for that scrollview. If its 0 then you have reached the top.
while you're scrolling up tableView(_:cellForRowAt) gets called to display rows and when the indexPath.row == 0 that's when you're at the top of the tableview
I have a UITableView that scrolls up too far, to the point where the list of items in the UITableView scroll up and then a large amount of whitespace follows it.
How can I stop UITableView from scrolling that extra space?
Hope I described it well enough.
I think this may work for you. Run this code after calling reloadData on the table :
if (table.contentSize.height < table.frame.size.height)
{
table.scrollEnabled = NO;
}
else
{
table.scrollEnabled = YES;
}
Here ,table.frame.size.height is the actual size of the object (you can see this in Interface Builder) displayed on the screen, whereas table.contentSize.height is the height of the header, the footer, and the height of every cell added together.
I found it here : How to disable scrolling in UITableView table when the content fits on the screen
Hope you can get something from the answers given their also.
This will fix your problem
TableView.bounces=NO;
This will remove empty cells
TableView.separatorStyle = UITableViewCellSeparatorStyleNone;
I am currently testing in xcode a UICollectionView with just one horizontal row like a kinda cover flow. Basically I have my own Custom Cell class and xib file for the cell and then on each cell I am adding another UIView with a xib. In case you are wondering why, it is so I can add different UIViews to the cell. Right now I am only adding one.
Edit I have followed the WWDC 2012 video on creating a linelayout of a UICollectionViewCell with one difference. Instead of the cell in the middle getting bigger all the other cells get smaller.
Everything below is new to my question.
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *array = [super layoutAttributesForElementsInRect:rect];
CGRect visibleRect;
visibleRect.origin = self.collectionView.contentOffset;
visibleRect.size = self.collectionView.bounds.size;
for (UICollectionViewLayoutAttributes *attributes in array){
if (CGRectIntersectsRect(attributes.frame, rect)) {
CGFloat distance = CGRectGetMidX(visibleRect) - attributes.center.x;
CGFloat normalizedDistance = distance / ACTIVE_DISTANCE;
if (ABS(distance) < ACTIVE_DISTANCE) {
//THIS WOULD MAKE THE MIDDLE BIGGER
//CGFloat zoom = 1 + ZOOM_FACTOR *(1- ABS(normalizedDistance));
//attributes.transform3D = CATransform3DMakeScale(zoom, zoom, 1.0);
//attributes.zIndex = round(zoom);
} else {
//THIS MAKES ALL THE OTHERS NOT IN THE RECT SMALLER
CGFloat zoom = 1 + ZOOM_FACTOR *(1- ABS(normalizedDistance));
attributes.transform3D = CATransform3DMakeScale(zoom, zoom, 1.0);
attributes.zIndex = round(zoom);
}
}
}
return array;
}
The problem can be seen in the attached image.
Pink = Collection View Size
Brown = Cell size
Green = Cells Content size and an attached xib to the content size.
The problem I THINK I have is with the layout. When the sell is dequeued it is made smaller by the above code. Then when it is reused the CELL gets bigger again but the content view does not.
I have tired to manually set the frame of the content view but that does nothing.
UPDATE 1: This also only happens when I add a xib to the Cells content view. If there is no subview to the content view then there is no problem
UPDate 2: It appears that the subview of the cell, my xib is not resizing. I have tried to manually change its frame size but the only place this helps is in the cells drawrect method which feels like a hack to me.
reused cell not able to redraw itself so give call to
-(void)setFrame:(CGRect)frame {
[super setFrame:frame];
[self setNeedsDisplay]; // force drawRect:
}
from cellForItemAtIndexPath of the UICollectionView.
also have a look at this link
and this question
My answer is very specific and I am not sure it will help anyone.
The problem was that I had a constraint on the bottom of the grey view. After I changed this constraint to a less than or equal too then for some reason it worked.
Now I know this does not explain why it was not happening to every cell but it fixed my problem.
As such Harsh's answer might also be worth looking at if you have landed here after doing a search.
Edit: there also appears to be some bugs in the 6.0 UiCollectionView controller which seem to be fixed in 6.1
I have a UITableView that needs to introduce new content from the bottom. This is how a table view behaves when the view is full and you add new rows with animation.
I was starting it by altering the contentInset as rows are introduced but then when they change things go off, and the entry animation is all wrong... My problem with this approach is compounded by the fact that users can delete rows, and the row contents update, causing them to resize (each row has it's own height which changes).
Any recommendations on how to get a UITableView rows to always appear at the bottom of the UITableView's view space?
I've got a solution that works for me perfectly, but it causes a bunch of double thinking so it's not as simple in theory as it is in practice... kinda...
Step 1, apply a transform to the table view rotating it 180deg
tableView.transform = CGAffineTransformMakeRotation(-M_PI);
Step 2, rotate your raw cell 180deg in tableView:cellForRowAtIndexPath:
cell.transform = CGAffineTransformMakeRotation(M_PI);
Step 3, reverse your datasource. If you're using an NSMutableArray insert new objects at location 0 instead of using AddObject...
Now, the hard part is remembering that left is right and right is left only at the table level, so if you use
[tableView insertRowsAtIndexPaths:targetPath withRowAnimation:UITableViewRowAnimationLeft]
it now has to be
[tableView insertRowsAtIndexPaths:targetPath withRowAnimation:UITableViewRowAnimationRight]
and same for deletes, etc.
Depending on what your data store is you may have to handle that in reverse order as well...
Note: rotate the cells OPPOSITE the table, otherwise floating point innacuracy might cause the transform to get off perfect and you'll get crawlies on some graphics from time to time as you scroll... minor but annoying.
The accepted method introduces issues for my app - the scroll bar is on wrong side, and it mangles cell separators for UITableViewStyleGrouped
To fix this use the following
tableView.transform = CGAffineTransformMakeScale (1,-1);
and
cell.contentView.transform = CGAffineTransformMakeScale (1,-1);
// if you have an accessory view
cell.accessoryView.transform = CGAffineTransformMakeScale (1,-1);
Similar approach to ima747, but rotating 180 degrees also makes the scrolling indicator go to the opposite side. Instead I flipped the table view and its cells vertically.
self.tableView.transform = CGAffineTransformMakeScale(1, -1); //in viewDidLoad
cell.transform = CGAffineTransformMakeScale(1, -1);//in tableView:cellForRowAtIndexPath:
Create a table header that is the height of the screen (in whatever orientation you are in) LESS the height of the of rows you have that you want visible. If there are no rows, then the header is the full height of the table view. As rows are added, simultaneously reduce the height of the table header by the height of the new row. This means changing the height of the frame of the view you provide for the table header. The point is to fill the space above the table rows to give the appearance that the rows are entering from the bottom. Using a table header (or section header) pushes the table data down. You can put whatever you like in the header view, even have it blank and transparent if you like.
This should have the effect you are looking for, I think.
Look at the attribute tableHeaderView. You simply set this to the view you want displayed in the table header. Then you can manipulate it as needed as you add rows. I can't recall just how forceful you then need to be to get the view to actually update in the UI. Might be as simple as calling setNeedsDisplay, if anything.
Alternatively, look at the methods tableView:viewForHeaderInSection: and tableView:heightForHeaderInSection:. Similar to using a table header view, you would want to have an instance variable that you setup once but that you can access from these methods to return either the view itself or its height, respectively. When you need to change the view for the (first) section, you can use reloadSections:withAnimation: to force an update to the view on screen after you have changed the views height (or content).
Any of that make sense? I hope so. :-)
Swift 3.01 - Other solution can be, rotate and flip the table view. Works very well for me and not mess with the animation and is less work for the reload data on the table view.
self.tableView.transform = CGAffineTransform.init(rotationAngle: (-(CGFloat)(Double.pi)))
self.tableView.transform = CGAffineTransform.init(translationX: -view.frame.width, y: view.frame.height)
I just wanted to add something to all of these answers regarding the use of this technique with UICollectionView... Sometimes when invalidating the layout, my cells would get transformed back the wrong way, I found that in the UICollectionViewCell and UICollectionReusableView subclasses I had to do this:
- (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes {
[super applyLayoutAttributes:layoutAttributes];
[self setTransform:CGAffineTransformMakeScale(1, -1)];
}
dataSourceArray = dataSourceArray.reversed()
tableView.transform = CGAffineTransform(scaleX: 1, y: -1)
cell.transform = CGAffineTransform(scaleX: 1, y: -1)
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if let text = textField.text {
dataSourceArray.insert(text, at: 0)
self.tableView.reloadData()
textField.text = ""
}
textField.resignFirstResponder()
return true
}
An easier way is to add the following lines at the bottom of cellForRowAtIndexPath
if(indexPath.section == self.noOfSections - 1)
[self scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:([self numberOfRowsInSection:self.noOfSections -1] - 1) inSection:self.noOfSections -1] atScrollPosition:UITableViewScrollPositionBottom animated:animated];
Late to the party but, inspired by #Sameh Youssef's idea, a function to scroll to the last cell in the tableview, assuming you only have one section. If not, just return the number of sections instead of hardcoding the 0.
The microsecond delay was arbitrarily chosen.
func scrollToLast() {
DispatchQueue.main.asyncAfter(deadline: .now() + .microseconds(5)) {
let lastIndex = IndexPath(row: self.tableView.numberOfRows(inSection: 0) - 1, section: 0)
if lastIndex.row != -1 {
self.tableView.scrollToRow(at: lastIndex, at: .bottom, animated: false)
}
}
}
I would recommend to use the approach described in this blog post.
Have checked it on iOS 12 and 13. Works perfectly.
Well, if you load your tableview with an NSMutableArray i would suggest you to sort out the array in the inverse order. So the table view will be filled up like you want.