how to scroll collection view automatically between time intervel to display images get from backend services? - ios10.3

I am developing an application based on getting images from backend service and displaying on collection view which have to scroll automatically in horizontal direction.
-(void)scrollAutomatically:(NSIndexPath *)pathRef {
[_collectionView scrollToItemAtIndexPath:pathRef atScrollPosition:UICollectionViewScrollPositionRight animated:YES];
if (row ==adImgsArr.count-1) {
_pageControl.currentPage = row;
row = 0;
}
else
{
_pageControl.currentPage = row;
row = row + 1;
}
pathRef = [NSIndexPath indexPathForRow:row inSection:section];
[self performSelector:#selector(scrollAutomatically:) withObject:pathRef afterDelay:5.0];
}
I am using the following code, but sometimes its working properly and sometimes it getting crash.
what is modification i need to do here ?

Related

Trying to dynamically increase height of UITableView while user adds rows to UITableView in iOS

I am working on an app where the user is able to add rows to the UITableView dynamically. This part is working fine. However, on my iOS screen, the UITableView is of a static height regardless of how many rows there are. Once the number of rows increases beyond a certain point, the user must scroll to see the additional cells.
What I would like to do is dynamically increase the height of the table with each row the user adds. So for example, if I have a tableView, if the user adds one row, I would like the tableview to be 50px tall, if the user adds 2 rows, the table dynamically increases in height to 100px, until it reaches say, a maximum height of 250px. My code for adding the rows dynamically, is as follows:
- (IBAction)addRow:(id)sender {
NSString *theObjectToInsert = [NSString stringWithFormat:#"Row #: %lu", (unsigned long)[self.tableData count]];
[self.tableData addObject:theObjectToInsert];
NSIndexPath *newPath=[NSIndexPath indexPathForRow:self.tableData.count-1 inSection:0];
[self.choiceTable insertRowsAtIndexPaths:#[newPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.choiceTable scrollToRowAtIndexPath:newPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
How do I incorporate the dynamic growth of the UITableView along with the increasing number of rows?
Just to be clear, when you say the table height is statically set right now I'll assume that is not desired and you do want it to be dynamic.
What if recommend doing is every time you add a row, check the height of all of the rows already added. You can do that by calling methods already implemented in the UITableViewDataSource protocol.
CGFloat maxDynamicTableHeight = 250.0f;
NSInteger numberOfSections = [self numberOfSectionsInTableView:self.tableView];
CGFloat runningHeight = 0.0f;
for (int section = 0; section < numberOfSections && runningHeight < maxDynamicTableHeight; section++) {
NSInteger numberOfRows = [self tableView:self.tableView numberOfRowsInSection:section];
for (int row = 0; row < numberOfRows && runningHeight < maxDynamicTableHeight; row++) {
runningHeight += [self tableView:self.tableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section]];
}
}
CGRect frame = self.tableView.frame;
frame.size.height = (runningHeight > maxDynamicTableHeight) ? maxDynamicTableHeight : runningHeight;
Self.tableView.frame = frame;
Sorry if there are any glaring issues, I'm on mobile so I can't test this right now.

Insert an UItableView in UITableViewCell causes lag

I'm trying to use a UITableView to display news,and inserting another tablview in the news cell to display the comment,but I got some issue,I make the cell to be the child table's datasource,and return the height like below
-(void)setReplayArray:(NSArray *)replayArray
{
_replayArray = replayArray;
[_replyTableView reloadData];
CGFloat h = 0;
for(int i=0; i < _replayArray.count; i++)
{
h = h+ [self tableView:_replyTableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
}
_replyTableViewHeight.constant = (_replayArray&&_replayArray.count>0)?h+10:h;
}
and set like this in father's datasource
newCell.replayArray = comment.replyArray;
but it causes lag when I scroll the tableview,what's wrong with the code?

Collapsing UICollectionView

I'm having a fight with UICollectionView to adopt it to my needs.
I'm trying to build a collapsing tag cloud. All elements can dynamically change size based on text inside.
When collection is displayed, I would like to display only first row and hide rest of content.
If there is more content than just for one row I want to show a button as a last item in first row - after selecting it, I will change collection size to fit it's content.
First step:
After click:
I was able to achieve desired effect with this code:
- (void) updateFrame
{
if(self.showFull)
{
self.showMoreButton.hidden = YES;
self.bottomConstrain.constant = 0;
self.frame = CGRectMake(0, 0, self.collectionView.frame.size.width, self.collectionView.contentSize.height);
}
else
{
self.showMoreButton.hidden = NO;
self.bottomConstrain.constant = self.originalConstrainValue;
self.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
}
}
But button in my case is placed completely outside the collection:
I'm hitting my head against a brick wall how to make this button to be a part of collection view.
It's the first time I'm playing with UICollectionView and UICollectionViewFlowLayout and it's too complex for me still to understand where would be best spot to put it.
One idea I had was to play a button over UICollectionView and position it at the end of first row - but I don't know how to get first row size from collection. With this approach it will be problematic also to cover last item in a row.
I think the best will be to put this element as a UICollectionViewCell, but I have no idea how to approach that - how to predict where it will placed and how to hide it later.
Any ideas will be highly appreciated.
Current template project is here:
https://www.zipshare.com/download/eyJhcmNoaXZlSWQiOiJjNTg2MGFkNC1mYWYxLTRlMzItOTA1YS1hMWFjOGFkMjMzYjUiLCJlbWFpbCI6Imdya3J1a293c2tpQGdtYWlsLmNvbSJ9
I'd suggest putting this button as a different cell INSIDE the collection view. Then, in collectionView:didSelectItemAtIndexPath: you would check to see if the special item was selected and react accordingly. I would let this button always be the last item in the collection view so you know where it is. When the items have expanded and everything is displayed, make sure you flip your logic and compress the collection view when this special cell is pressed.
You'll need to save some state to do this:
1.The array of tags
whether or not the collection view is expanded or not
Once you have this info, you can just flip the bits and reload the collection view section.
I've managed to achieve what I wanted with this code (thanks for atreat for suggestion).
I'm estimating which element won't fit in first row, and pushing "More" tag into tags array.
There is some logic also to make sure that More button will fit after last element in this row, if not it's pushed instead of this element. Maybe some will find it usefull.
UICollectionViewFlowLayout *flowLayout = (UICollectionViewFlowLayout*)self.collectionView.collectionViewLayout;
CGFloat collectionWidth = self.frame.size.width;
CGFloat lastFittingItemRight = 0.0f;
CGFloat spacingBetweenElements = flowLayout.minimumInteritemSpacing;
CGFloat sectionInsetLeft = flowLayout.sectionInset.left;
CGFloat sectionInsetRight = flowLayout.sectionInset.right;
CGFloat rightEdge = sectionInsetLeft;
for (int i = 0; i < [self collectionView:self.collectionView numberOfItemsInSection:0]; i++)
{
CGSize elementSize = [self collectionView:self.collectionView layout:flowLayout sizeForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
CGFloat elementWidth = elementSize.width;
rightEdge += elementWidth;
if(rightEdge > collectionWidth - sectionInsetRight)
{
self.moreButtonIndexPath = [NSIndexPath indexPathForItem:i inSection:0];
break;
}
lastFittingItemRight = rightEdge;
rightEdge += spacingBetweenElements;
}
if(self.moreButtonIndexPath)
{
NSString* showMoreText = #"More";
CGSize moreButtonSize = [self sizeForTagWithText:showMoreText];
CGFloat rightEdgeMoreButton = lastFittingItemRight + spacingBetweenElements + moreButtonSize.width;
NSInteger moreButtonIndex = self.moreButtonIndexPath.row;
if(rightEdgeMoreButton > collectionWidth - sectionInsetRight)
{
moreButtonIndex = moreButtonIndex-1;
}
[self.tags insertObject:showMoreText atIndex:moreButtonIndex];
}

Collection View,with custom layouts, cells misbehave on scrolling

I am trying to create custom tiled layout using UICollectionView.
It renders perfectly as desired in simulator once I run my app.
But the moment I scroll the view and bring it back all the cell's frame changes and the cells get overlapped, leaving spaces, randomly.
I am not able to solve this issue past 2 days.
Here goes the code from my custom layout class.
-(void)prepareLayout{
[self createCellSizeArray];//cellSizeArray holds cell sizes for all the cells(calculated statically)
[self createAttributeArrayOfAll];//attributeArrayOfAll holds attributes for all the cells and also calculates their frames using cellSizeArray
}
-(CGSize)collectionViewContentSize{
return CGSizeMake(768, 1500);//The size is static to check for scrolling, is this creating problems?
}
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewLayoutAttributes * layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
return layoutAttributes;
}
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
NSMutableArray *attArray =[NSMutableArray array];
for (NSInteger i =0; i< attributeArrayOfAll.count; i++) {
UICollectionViewLayoutAttributes * attribute = (UICollectionViewLayoutAttributes*)[attributeArrayOfAll objectAtIndex:i];
if(CGRectIntersectsRect(rect, attribute.frame)){
[attArray addObject:attribute];
}
}
return attArray;
}
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
return YES;
}
Please help, Thanks in advance.
Edit:
In my [self createAttributeArrayOfAll]; I have these lines of code
CGRect frame = CGRectMake(_startNewRowPoint.x, _startNewRowPoint.y, cellSize.width, cellSize.height);
UICollectionViewLayoutAttributes * attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
attribute.alpha = 1.0;
attribute.frame = frame;
[attributeArrayOfAll addObject:attribute];
While I modified layoutAttributesForItemAtIndexPath:, to look something like this
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewLayoutAttributes * layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
layoutAttributes.frame = ((UICollectionViewLayoutAttributes*)[attributeArrayOfAll objectAtIndex:indexPath.item]).frame;
return layoutAttributes;
}
Moreover, the method layoutAttributesForItemAtIndexPath: never gets called implicitly. I even tried this:
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
NSMutableArray *attArray =[NSMutableArray arrayWithCapacity:attributeArrayOfAll.count];
for (NSInteger i =0; i< attributeArrayOfAll.count; i++) {
UICollectionViewLayoutAttributes * attribute = (UICollectionViewLayoutAttributes*)[attributeArrayOfAll objectAtIndex:i];
if(CGRectIntersectsRect(rect, attribute.frame)){
[attArray insertObject:[self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]] atIndex:i];
}
}
return attArray;
}
But still the result is the same distorted set of cells on scrolling.
I worked with 5 cells, first time it renders correctly, on scrolling away and then bringing it back in visible rect it gets distorted, if i scroll away again and bring it back in visible rect it renders correctly. However, when I do this with around 400 cells, once i scroll it never renders correctly. Even on reloading collection view, The cells gets distort. Please help.
Your layoutAttributesForItemAtIndexPath: method is not setting any properties of the layoutAttributes object before returning it. It needs to set frame (or center and size).
So finally managed a workaround!!! dequeue each cell with an unique Cell Identifier in cellForRow:
[self.summaryView registerClass:[BFSSummaryViewCell class] forCellWithReuseIdentifier:[NSString stringWithFormat:#"%#%d",CellIdentifier,indexPath.row]];
UICollectionViewCell *collectionCell = [collectionView dequeueReusableCellWithReuseIdentifier:[NSString stringWithFormat:#"%#%d",CellIdentifier,indexPath.row] forIndexPath:indexPath];
These two lines inside cellForRow worked for me, however with my collection view having around 1000 cells it increases the size of my application considerably. Lets hope apple fixes this bug asap.

UITableViewCell becomes unresponsive

I have a popover screen, with inside it :
a label, that may or may not appear (title)
a search bar, that may or may not appear
a label, that may or may not appear, and has a variable height (help label)
a scrollview, that may or may not appear, and has a variable height (some infos about the following table)
a table view
In order to present something nice, in viewDidLoad, I move the various frames to place the objects correctly and not have unused spaces cluttering my popover. Besides, I then resize the table (to take the most place needed), and the popover via contentSizeInPopover (to avoid having a near-empty huge popover). All that resizing seems to work nicely, but I have one big problem : with all that resizing done, some cells of my UITableView become unresponsive. One or two cells, usually the second one, only respond if i tap in their outer corners, but the rest of the cell completely ignore any touches.
I've tried everything : moving all to viewWillAppear, letting the autoresize do its job (doesn't seem to work either), but I still have this problem every time. I've found that if I comment the lines involved with changing the frame of the table, or the ones in contentSizeInPopover, the problem stops, but then my view is messed up, so this ins't a fix.
If anyone could give me something to get out of this mess, that would be awesome.
- (CGFloat)getHeightWithoutTable {
return LIST_TITLE_HEIGHT + (self.searchBar.hidden ? 0 : LIST_SEARCH_BAR_HEIGHT) + (self.helpLabel.hidden ? 0 : self.helpLabel.frame.size.height + LIST_STD_SPACE) + (self.errorScrollView.hidden ? 0 : self.errorScrollView.frame.size.height + LIST_STD_SPACE);
}
-(void)viewDidLoad {
[super viewDidLoad];
self.tableViewOutlet.backgroundView = nil;
self.originData = [NSMutableArray array];
self.searchedData = [NSMutableArray array];
if (self.helper != nil) {
CGFloat heightOffset = 0;
// Content
self.originData = [self.helper getData];
self.tableData = [NSMutableArray arrayWithArray:self.originData];
// Title
NSString *title = [self.helper getPopoverTitle];
if (title == nil) {
self.popoverTitle.hidden = YES;
heightOffset -= LIST_TITLE_HEIGHT;
} else {
self.popoverTitle.text = [self.helper getPopoverTitle];
}
// Search
if ([self.originData count] [self getStdHeight] / 3){
self.helpLabel.lineBreakMode = UILineBreakModeTailTruncation;
[self.helpLabel sizeThatFits:CGSizeMake(self.helpLabel.frame.size.width, [self getStdHeight] / 3)];
}
heightOffset += (self.helpLabel.frame.size.height - LIST_HELP_STD_HEIGHT);
}
// Errors
if ([self.helper respondsToSelector:#selector(getErrors)]) {
self.errors = [self.helper getErrors];
}
if (self.errors == nil || [self.errors count] == 0) {
self.errorScrollView.hidden = YES;
self.errorBg.hidden = YES;
heightOffset -= LIST_ERROR_STD_HEIGHT + LIST_STD_SPACE;
} else {
[self createErrorView];
heightOffset += (self.errorScrollView.frame.size.height - LIST_ERROR_STD_HEIGHT);
}
// Table
CGFloat previewHeight = LIST_CELL_HEIGHT * [self.tableData count] + LIST_STD_SPACE;
CGFloat remainingHeight = LIST_MAX_HEIGHT - [self getHeightWithoutTable] - LIST_STD_SPACE;
CGFloat tableHeight = MIN(previewHeight, remainingHeight);
CGRect tableFrame = self.tableViewOutlet.frame;
self.tableViewOutlet.frame = CGRectMake(tableFrame.origin.x, tableFrame.origin.y + heightOffset, LIST_WIDTH, tableHeight);
// Selected items
if ([helper getSelectedObject] != nil){
int index = [self.tableData indexOfObject:[helper getSelectedObject]];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
[self.tableViewOutlet scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
}
}
- (CGSize)contentSizeForViewInPopover {
if (self.navigationController) {
return CGSizeMake(LIST_WIDTH, LIST_MAX_HEIGHT);
} else {
CGFloat totalHeight = [self getHeightWithoutTable] + self.tableViewOutlet.frame.size.height + LIST_STD_SPACE;
return CGSizeMake(LIST_WIDTH, totalHeight);
}
}
(gist if you need some coloring to help you)
An image of the nib :
Just a shot in the dark, since you have not provided any code. If you are adding things to the UITableCellView, just remember that a lot of components have their UserInteractionEnabled set to NO, which will disable the ability to interact with it. Make sure that any items you add to the cell that potentially take up the space where you are tapping (presumably the center of the cell?) have their UserInteractionEnabled set to YES.
The reason why the edges might still work is that the UITableCellView consists of 3 main parts, so you are probably only changing the center part.
Post some code then we can have a better look.
Found the answer myself : the fact I was using a self-filled UIScrollView next to my UITableView seemed to be the problem. As soon as I replaced the UIScrollView by a proper UITableView, the problem disappeared.

Resources