Reputation: 55
I'm new to IOS
development and I'm just trying to get my feet wet. For the past couple of days I've been trying to wrap my head around how to embed horizontal and vertical scrolling inside swift for views.
One thing that people seemed to mentioned and use when it came to this was Collection Views. I've been trying to learn how to properly use them and build the picture you can see below in Swift.
Under the label Browse Categories there is a container that allows horizontal scrolling,the categories container. Below the label discover there is another container that should allow for vertical scrolling, the feed container(Similar to instagram, Airbnb , Pinterest etc)
2. What I've tried
From countless hours of googling and stackoverflowing I found out that Collection Views might be suitable for this task so I digged in. The apple documentation lacked some examples so I searched for tutorials to help me out. At the end of the day I was able to achieve the horizontal scrolling for the categories. This looked like this.
So far so good! The trouble actually starts as soon as I try adding the next collection scroll view(the vertical for the feed). After adding the feed collection the screen looks like this.
So what exactly is my problem?
Well my problem is that although I set the constraints within the storyboard for the UIIMage
view to fill the entire Content View I am presented with something else.
I want to know how I can perfectly control the size and shape of the UIImageView
and any other element.
For simplicity I omitted things such as the star, username etc.
But when I tried implementing this the project included everything.
I can't wrap my head around how to control the size and position of the contents of the CollectionViewCell
.
I was assuming that positioning and size was taken care of by the constraints I set inside the storyboard for each element but that does not seem to be the case and now I'm lost.
I saw some post where people mentioned UICollectionViewLayoutAttributes but I just don't know how ti incorporate this in to my project.
I'm open to suggestions and I also have some more closing questions.
Thx in advance
Github: https://github.com/Taharcca/LayoutChallenge.git
Code Snippets
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var categoriesCollectionView: UICollectionView!
@IBOutlet weak var feedCollectionView: UICollectionView!
let categories = Category.load() // Load data
let feeds = Feed.load()
override func viewDidLoad() {
super.viewDidLoad()
categoriesCollectionView.dataSource = self
categoriesCollectionView.delegate = self
feedCollectionView.dataSource = self
feedCollectionView.delegate = self
// Do any additional setup after loading the view.
}
}
extension ViewController: UICollectionViewDelegate {
// Not sure when to use this
}
// Diese Erweiterung legt die Datenquelle einer Collection View fest
extension ViewController: UICollectionViewDataSource {
// Wie viele Reihen?
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
// Wie viele Objekete soll es geben?
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == categoriesCollectionView {
return categories.count
}
else {
return feeds.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == categoriesCollectionView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CategoryCollectionViewCell", for: indexPath) as! CategoryCollectionViewCell
let category = categories[indexPath.item]
cell.category = category
return cell
}
else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FeedCollectionViewCell", for: indexPath) as! FeedCollectionViewCell
let feed = feeds[indexPath.item]
cell.feed = feed
return cell
}
}
}
// Größe der Zellen...Sehr intuitiv..... Danke Apple
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout:
UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView == categoriesCollectionView {
return CGSize(width: 150, height: 75) // Collection View size right?
}
else {
return CGSize(width: 374, height: 494)
}
}
}
import UIKit
class FeedCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var backgroundImage:UIImageView!
var feed:Feed! {
didSet {
self.update()
}
}
func update() {
if let feed = feed {
backgroundImage.image = feed.image
}
}
}
Upvotes: 2
Views: 11924
Reputation: 55
Well after some more Stackoverflowing and watching other Tutorials I finally found the real solution to my problem.
The answer is fairly easy: constraints.
When you create everything from the storyboard you have to make sure that you set the right constraints. This included constraints for trailing, top, etc. And more importantly also width and height.
Lastly when working with images you also have to pay close attetntion to the content mode.
Depending on the content mode you have chosen you might get funny results.
In the end Apple's Collection View works as expected when using the storyboard. The items layout is set using the storyboard.
If you want you can change the layout of the cell item either by extending the following protocol: UICollectionViewDelegateFlowLayout. You could also just set a property that has a reference to UICollectionFlowLayout
and then probably take it from there.
In the end using Collection View for my use case with the feed for one item is probably overkill and you might want to use TableView as suggested by others in this post.
Upvotes: 0
Reputation: 71854
You can achieve it easily with UITableView
by adding UICollectionView
in tableHeaderView
.
I have written it like below:
import UIKit
class DemoWithTableViewController: UIViewController {
//MARK:- @IBOutlet
@IBOutlet weak var categoriesCollectionView: UICollectionView!
@IBOutlet weak var tblFeed: UITableView!
//MARK:- Properties
let categories = Category.load()
let feeds = Feed.load()
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
}
}
//MARK:- Setup UI
extension DemoWithTableViewController {
func setupUI() {
categoriesCollectionView.dataSource = self
tblFeed.dataSource = self
tblFeed.delegate = self
}
}
//MARK:- UICollectionViewDataSource
extension DemoWithTableViewController: UICollectionViewDataSource {
// Wie viele Objekete soll es geben?
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return categories.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CategoryCollectionViewCell", for: indexPath) as! CategoryCollectionViewCell
let category = categories[indexPath.item]
cell.category = category
return cell
}
}
//MARK:- UITableViewDataSource
extension DemoWithTableViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return feeds.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tblFeed.dequeueReusableCell(withIdentifier: "FeedTableViewCell") as! FeedTableViewCell
let feed = feeds[indexPath.item]
cell.feed = feed
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 360
}
}
And your view controller in storyboard will look like:
And your result will be with above code:
And for more info you can check demo project here.
Upvotes: 1