To Set Particular Cell Left Margin of Collection View - objective-c

May I know is there any delegate method of collection view can be use to set the left, right margin of particular cell in collection view?
What I've found is as follows,
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{ // my code here }
This is to control the left right, top, bottom margin of all the cells within the collection view. May I know is there any delegate function of collection view can be done like
UITableView heightForRowAtIndexPath?

There isn't. But since you're going to supply the cells (ie UIView) yourself, why not adjust the cell's internal layout yourself?

Related

How to hide NSTableView gridlines / seperators for empty items

I have a large NSTableView with only a few items, which are separated by gridlines / separators. All is great apart from the fact that, below the items, are a bunch of gridlines, for empty items. How is it possible to show gridlines for items that exist, but to just have plain background for non existent items?
Note: UITableView has a way to set a footerView - this same method is not possible with NSTableView, otherwise it would just be a case of setting a big empty view as the footer...
I have figured out one way:
In interface builder, set the 'row height' of the tableview to a very large number i.e. 10000, and make it 'Fixed'. In the delegate implement the tableView:heightOfRow:
e.g. in swift:
func tableView(tableView: NSTableView!, heightOfRow row: Int) -> CGFloat {
return 50
}
This means that cells that don't have content are so big that you can't see the gridlines, as the above method seems to only get called for existing cells.
The other way as per Elwisz' comment, is to implement drawBackgroundInRect: of NSTableRowView.
Set NSTableView.rowHeight to a very large number in Interface Builder or programatically.
Then implement
#pragma mark - NSTableViewDelegate
- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row{
return 60;
}

UICollectionView orientation (Top to bottom v. Left To Right)

I'd like to get this collection view layout:
The collection view class is also its delegate/data source and the layout delegate. The scrolling direction is horizontal. There are two horizontal sections. The first one with header view (orange). The cells with simple border lines contain labels.
The issue here is the collection orientation is wrong 2 (top to bottom instead of left to right). Is there any explicit property that can control this orientation/cell composition?
Another question is related to the cell borders. Is there any elegant way how the border color/width can be set up using auto layout (subclassing)?
Thank you.
UPDATE:
The key value to play with might be ((UICollectionViewFlowLayout *)self.collectionViewLayout).minimumLineSpacing and assigning a big number to it. But it results in one long row of cells so that the sections are together in one row. It is weird component design when a navigation mode (the scrolling direction) dictates the collection layout.
If you subclass UICollectionViewFlowLayout you will be able to layout the cells any way you like. I use a custom flow layout to display a horizontal scrolling set of cells based on an event start time and duration:
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
dataSource = self.collectionView.dataSource;
event = [dataSource eventAtIndexPath:indexPath];
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attributes.frame = [Calculate a frame for the event from its data];
return attributes;
}
Similarly use layoutAttributesForSupplementaryViewOfKind to define your header position.
I found this reference useful Custom Collection View Layouts.

Resize UICollectionView cells after their data has been set

My UICollectionView cells contain UILabels with multiline text. I don't know the height of the cells until the text has been set on the label.
-(CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
This was the initial method I looked at to size the cells. However, this is called BEFORE the cells are created out of the storyboard.
Is there a way to layout the collection and size the cells AFTER they have been rendered, and I know the actual size of the cell?
I think your are looking for the invalidateLayout method you can call on the .collectionViewLayout property of your UICollectionView. This method regenerates your layout, which in your case means also calling -collectionView: layout: sizeForItemAtIndexPath:, which is the right place to reflect your desired item size. Jirune points the right direction on how to calculate them.
An example for the usage of invalidateLayout can be found here. Also consult the UICollectionViewLayout documentation on that method:
Invalidates the current layout and triggers a layout update.
Discussion:
You can call this method at any time to update the layout information. This method invalidates the layout of the collection view itself and returns right away. Thus, you can call this method multiple times from the same block of code without triggering multiple layout updates. The actual layout update occurs during the next view layout update cycle.
Edit:
For storyboard collection view which contains auto layout constraints, you need to override viewDidLayoutSubviews method of UIViewController and call invalidateLayout collection view layout in this method.
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[yourCollectionView.collectionViewLayout invalidateLayout];
}
subclass UICollectionViewCell and override layoutSubviews like this
hereby you will anchor cell leading and trailing edge to collectionView
override func layoutSubviews() {
super.layoutSubviews()
self.frame = CGRectMake(0, self.frame.origin.y, self.superview!.frame.size.width, self.frame.size.height)
}
Hey in the above delegate method itself, you can calculate the UILabel size using the below tricky way and return the UICollectionViewCell size based on that calculation.
// Calculate the expected size based on the font and
// linebreak mode of your label
CGSize maximumLabelSize = CGSizeMake(9999,9999);
CGSize expectedLabelSize =
[[self.dataSource objectAtIndex:indexPath.item]
sizeWithFont:[UIFont fontWithName:#"Arial" size:18.0f]
constrainedToSize:maximumLabelSize
lineBreakMode:NSLineBreakByWordWrapping];
- (void)viewDidLoad {
self.collectionView.prefetchingEnabled = NO;
}
In iOS 10, prefetchingEnabled is YES by default. When YES, the collection view requests cells in advance of when they will be displayed. It leads to crash in iOS 10

Preload cells of uitableview

I acknowledge that UITableview load dynamically a cell when user scrolls. I wonder if there is a way to preload all cells in order not to load each one while scrolling. I need to preload 10 cells. Is this possible?
You can initialize table view cells, put them into an array precomputedCells and in the data source delegate method tableView:cellForRowAtIndexPath: return the precomputed cells from the array instead of calling dequeueReusableCellWithIdentifier:. (Similar to what you would do in a static table view.)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [self.precomputedCells objectAtIndex:indexPath.row];
}
It might also be useful to have a look at the
WWDC 2012 Session 211 "Building Concurrent User Interfaces on iOS"
where it is shown how to fill the contents of table view cells in background threads while keeping the user interface responsive.
I was looking for a solution to the original question and I thought I'd share my solution.
In my case, I only needed to preload the next cell (I won't go into the reason why, but there was a good reason).
It seems the UITableView renders as many cells as will fit into the UITableView frame assigned to it.
Therefore, I oversized the UITableView frame by the height of 1 extra cell, pushing the oversized region offscreen (or it could be into a clipped UIView if needed). Of course, this would now mean that when I scrolled the table view, the last cell wouldn't be visible (because the UITableView frame is bigger than it's superview). Therefore I added an additional UIView to the tableFooterView of the height of a cell. This means that when the table is scrolled to the bottom, the last cells sits nicely at the bottom of it's superview, while the added tableFooterView remains offscreen.
This can of course be applied to any number of cells. It should even be possible to apply it to preload ALL cells if needed by oversizing the UITableView frame to the contentSize iOS originally calculates, then adding a tableFooterView of the same size.
Hopefully this helps someone else with the same problem.
As suggested by Mark I also changed the height of my UITableView temporarily so that the table view creates enough reusable cells. Then I reset the height of my table view so that it stops creating reusable cells while scrolling.
To accomplish that I create a helper bool which is set to false by default:
var didPreloadCells = false
It is set to true when my table view first reloaded data and therefore created the first reusable cells.
resultsHandler.doSearch { (resultDict, error) -> Void in
[...]
self.tableView.reloadData()
self.didPreloadCells = true
[...]
}
The real trick happens in my viewDidLayoutSubviews Method. Here I set the frame of my table view depending on my boolean. If the reusable cells were not created yet I increase the frame of the table view. In the other case I set the normal frame
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.tableView.frame = self.view.bounds
if !didPreloadCells
{
self.tableView.frame.size.height += ResultCellHeight
}
}
With the help of that the table view creates more initial reusable cells than normal and the scrolling is smooth and fluent because no additional cells need to be created.
Change the dequeueReusableCellWithIdentifier when you are reusing the table view otherwise it will load the old data
Solution for autoresizing cells. Change 'estimatedRowHeight' to lower value
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 32; //Actual is 64
}
Actual estimated height is 64. 32 is used to add more cells for reuse to avoid lagging when scrolling begins

UITableViewCell Align all subviews

I have a custom UITableViewCell which has some subviews. i.e. some labels, some images. I want all these subviews to be right aligned in the UITable. How do i do that?
I have tried these approaches -
1.In InterfaceBuilder when I select the UITableViewCell, I can set the "indentaion" section. It's by default 0, I made it 100 but I see no change in the device.
2.I have tried this in the code too. Override the default method...
(NSInteger)tableView:(UITableView *)tableView
indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 100;
}
The above code also does not work. How do I align all my subviews in my UITableViewCell to right?
Basically, I want to display one cell left aligned (which is default) & some cells right aligned. As shown in the picture.
There is automatic way everything will align to right. You will have to lay the view appropriately. For UITextField and UILabel objects you can set the textAlignment property to UITextAlignmentRight.
label.textAlignment = UITextAlignmentRight;
If necessary you must also adjust the autoresizingMask of the views to set it such that it has a UIViewAutoresizingFlexibleLeftMargin mask set so that they stick to the right on view resize.
use interface builder for alignment.