Different line spacing for each item at UICollectionView - swift 3 - ios

I have a collection view written programmatically with swift 3. It has 1 section and 6 vertical items in it. The default minimum line spacing for each item is 10 I assume, but I want to set different line spacing for each item. For example, the space between item 0 and 1 become 50 but space between item 1 and 2 become 0. How can I do that? I searched a lot but couldn't find solution. Thanks in advance.

It is directly not possible by setting some property of your collection view but you can do one trick I think,
set your minimum line spacing and minimum interitem spacing to 0 like,
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
so your collection view cell will not have any space at any side!
now keep your cell's background color as clear color!
and add UIView (your content) in your cell with size(less than cell size) that shows spacing between two cell. So, you can add different size of view in every cell and it will display like different space between every cell!
Or
If you don't want to resize your inner view of cell then you can return different size for your cell from delegate method sizeForItemAtIndexPath for different items!
For example,
I am writing objective c code for example,
your sizeforitem,
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.item == 1 || indexPath.item == 6 || indexPath.item == 7 || indexPath.item == 9 || indexPath.item == 15) {
return CGSizeMake(screenWidth/3 -20, screenWidth/2);
}
return CGSizeMake(screenWidth/3, screenWidth/3);
}
and result is

An idea could be to consider the lines spacing as "other kind of cell", like blank cell, you see? And in the method heightForRowAtIndexPath, when the indexPath correspond to those blank cell, you return their custom height, otherwise you return the row height of your "real" cells.
(This imply to return those blank cell in the cellForRow, and add their number to your current numberOfRowInSection count too)

Related

How to center align CollectionView Cell?

Hi have a collectionview.
Each cell's width is screenwidth/3. Means 3 cells in a row.
Now. If have 10 or 11 cells then there will be 4 rows. and there are 1 or 2 cells in last row.
The problem is ,I want to align these cell to center without changing its size . now cells are left align.
Note: I want to achieve this with in a section(Because collection-view already have multiple sections).
Image attached what i want to achieve .
You can solve this using multiple sections. Number of section should be
numberOfSection = totalItemCount/3 > Int(totalItemCount/3) ? Int(totalItemCount/3) + 1 : Int(totalItemCount/3)
dont use ceiling. Then number of items in section should be
numberOfItemInSection = totalItemCount-section*3 < 3 ? totalItemCount-section*3 : 3
Then implement the UICollectionViewDelegateFlowLayout delegate. Where in collectionView(_ collectionView:, layout:, insetForSectionAt:) set,
let minimumInterItemSpacing: CGFloat = 8.0
// minimumInterItemSpacing should be same in the delegate function
let itemCountInSection = collectionView.numberOfItems(inSection: section)
let edgeSpace = (collectionView.bounds.width - ((itemCountInSection*self.itemWidth) + (minimumInterItemSpacing*(itemCountInSection-1)))) / 2
return UIEdgeInsets(top: self.topSpace, left: edgeSpace, bottom: self.bottomSpace, right: edgeSpace)
set other delegate methods as it suits you.

How to maintain constraints even after deleting label in UITableViewCell - Swift 3

So currently, I have a tableviewcell that looks like this
What I want to happen, is that if an expense of the date already exists, the top label should disappear, the tableviewcell height should be reduced from 95 to 64 and everything should be centrally aligned. Sort of like this
I tried doing this many ways.
Use 2 different cells and switch, but that didn't work as only one expense was returned at a time and my tableviewcontroller didn't populate correctly.
Try using a stack view, but in that, I can't get the constraints to match as they are currently.
I have all the correct row height being returned in the heightForRowAtIndexPath method, but it centrally reduces the height and some of the data is cut.
How is it possible to achieve what I want to do (have the label not visible, the row height reduced and everything vertically center)?
Here is the code for switching of the cells.
func tableView(_ tableView: UITableView,
heightForRowAt indexPath: IndexPath) -> CGFloat
{
if newMode==true {
return 95
}
else if newMode==false {
return 64
}
else {
return 0
}
}
This works, however it reduces the height from the top and the bottom and I only want the height from the top to be reduced.
You should not use the delegate method heightForRowAt instead you should use:
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 80
then give the (date of expense) label a hight constraint and connect an outlet to it.
in cellForRowAtIndex delegate method should have :
if expense != nil
{
lblExpenseConstraintHeight.constant = 0
}
else
{
lblExpenseConstraintHeight.constant = 34
}
cell.layoutIfNeeded()
Edit:
More info about about dynamic tableViewHeight:
Using Auto Layout in UITableView for dynamic cell layouts & variable row heights
Another possible solution is remove the height constraint of the (date of expense) label and set it's text to empty string.

How to I build a continuous parallax scroll/Collection view?

I am looking to build a continuous parallax scroll like this.
http://www.screencast.com/t/7Z48zkkW
But my Requirement is view and then CollectionView like this
When collection view scroll then changes upper view height.
and yes upper view and collection view is separate.
I Have also navigation bar it also goes up when user scroll
You can use collectionView with section header for this effect. However, the effect collectionView bounced below the search can't be achieved by this way instead the whole view will bounce.
Simplest solution for iOS 9 +
1) Make a cell for items above the search
2) Make reusableView for search bar (section header)
3) Make cells for those pictures
i.e. you will have two cell's prototypes and one reusableView
In viewDidLoad of viewController with collectionView use following code so that header of section gets pinned always in top:
let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout // casting is required because UICollectionViewLayout doesn't offer header pin. Its feature of UICollectionViewFlowLayout
layout?.sectionHeadersPinToVisibleBounds = true
Number of section: Keep it 2
Number of row for section == 0 will be 1 which will be items above search
Number of row for section == 2 will be number of images you have
Now, in collection view datasource you have a method viewForSupplementaryElementOfKind which you need to implement to get sectionHeaderView.
implement referenceSizeForHeaderInSection function for hiding sectionHeader for first section (section == 0) by returning CGSize(width: 0, height: 0) and for second section (section == 1) return size of searchBar as you want.
in cellForItemAtIndexPath return cells according to section.
EDIT
I think you don't need sticky header at top like that search bar. So its better you use collectionView with section header. (section header contains the red View you marked)

Expanding tableviewcell based on UIlabel line count

I have a custom UITableViewCell with a UILabel that has multiple lines. I'm trying to implement a tap expand/contract feature so that when the label is only one line, no expansion happens when you tap the cell, but if the label is multiple lines, the cell is capable on expanding/contracting when tapped. I got the expansion and contracting working, but I can't figure out how to make it work based on the number of lines in the UILabel.
This is currently what I'm doing for the cell expansion, but its not based on the UILabel at all.
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if (indexPath.row == self.selectedRow?.row && self.expand == true)
{
self.previousRow = self.selectedRow?.row
return 200
}
else if(self.previousRow == self.selectedRow?.row && self.expand == false){
return 65
}
return 65
}
You can use table view dynamic cell sizing with autolayout in conjunction with the numberOfLines property of UILabel to expand and compress cell.
The heart of the solution is this:
tableView.beginUpdates()
label.numberOfLines = label.numberOfLines == 0 ? 1 : 0
tableView.endUpdates()
This is essentially triggering an animation on the table and toggling the number of lines from 0 (any number of lines) to 1 line. Autolayout is doing the rest.
I think this is better than updating height metrics manually. The full example project can be found on my github: https://github.com/rayfix/MultilineDemo
You probably need to measure the text yourself because the label won't have more lines until you expand.
Something like this (the 100000 just needs to be a big number)
CGSize textSize = [self.label.text sizeWithFont:self.label.font constrainedToSize:CGSizeMake(self.label.bounds.width, 100000) lineBreakMode: UILineBreakModeWordWrap];

Label not adjusting text correctly with Auto Layout enabled in Xcode 6

I'm using Storyboard to layout the UI for an app and I'd like to use Auto Layout. I'm usually able to resolve my own issues with Auto Layout, but I've hit a wall here with one label that does not want to re-size properly or show any text at all.
Here's a screenshot of the simulator:
In the attributes inspector I have Lines set to 0 and Line Breaks set to Word Wrap:
I've tried "Resetting to Suggested Constraints" for the entire UITableViewController:
I've also tried selecting the labels themselves and Pinning the width and the height, as well as adding any missing constraints:
However, it only shows the first four characters of the address:
The table cell for the Address label is correctly adjusting to 88 points because of this method I implemented, but still something still obviously off:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0 && indexPath.row == 0) {
return 88;
}
else if (indexPath.section == 2 && indexPath.row == 2) {
return 88;
}
else {
return 44;
}
}
I've solved it, however, I don't know if it's the best solution.
I tried just about everything to try and get the two labels in the table cell to play well together.
Ultimately, I'd like the detail label frame to expand as needed for the address to populate.
I ended up selecting both the Address label and the Detail label on the Storyboard and choosing the default "Reset to Suggested Constraints" in the current view.
Then I set an explicit width in the size inspector for the detail view:
That along with this method seems to work OK:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0 && indexPath.row == 0) {
return 88;
}
else if (indexPath.section == 2 && indexPath.row == 2) {
return 88;
}
else {
return 44;
}
}
The latter part is on the right track but you have set a "greater than or equal to" constraint and autolayout is choosing to go with the "equal to" rather than making it any wider.
You need to figure out why. I'd start by setting a fixed width constraint on the label "Address" and then setting a constraint fire the left side of your address field to equal the right side of the address label, while pinning them to the right and left of the respective container to keep them attached to the sides. That may fix it.
For the earlier part where you see nothing, it's quite likely the field is being displayed entirely outside its parent container, which is clipping to bounds. Orange dotted lines often indicate this location in the interface builder preview and it is a sign there are insufficient constraints set.

Resources