UICollectionView scrolling/swipe to next item swift - ios

I have a UICollectionView in a view controller. When the user clicks one of the images, it goes to a separate page to open the image. I would like instead of going back to the gallery each time to change pictures, to swipe left or right to get the next or previous picture.
I have seen answers to do "pagingEnabled = true" but where do you put this exactly?
I am new to swift.
Below is my code. Thanks for the help in advance.
ViewController.swift
import UIKit
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate
{
#IBOutlet weak var collectionView: UICollectionView!
let appleProducts = ["iPhone", "Apple Watch", "Mac", "iPad"]
let imageArray = [UIImage(named: "pug"), UIImage(named: "pug2"), UIImage(named: "pug3"), UIImage(named: "pug4")]
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return self.appleProducts.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! CollectionViewCell
cell.imageView?.image = self.imageArray[indexPath.row]
cell.titleLabel?.text = self.appleProducts[indexPath.row]
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
{
self.performSegueWithIdentifier("showImage", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if segue.identifier == "showImage"
{
let indexPaths = self.collectionView!.indexPathsForSelectedItems()!
let indexPath = indexPaths[0] as NSIndexPath
let vc = segue.destinationViewController as! NewViewController
vc.image = self.imageArray[indexPath.row]!
vc.title = self.appleProducts[indexPath.row]
}
}
}
CollectionViewCell.swift
import UIKit
class CollectionViewCell: UICollectionViewCell
{
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var titleLabel: UILabel!
}
NewViewController.swift
import UIKit
class NewViewController: UIViewController
{
#IBOutlet weak var imageView: UIImageView!
var image = UIImage()
override func viewDidLoad()
{
super.viewDidLoad()
self.imageView.image = self.image
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}

In the view controller that is presented after a tap, you should make a horizontally scrolling UICollectionView. On this collection view, set its pagingEnabled property to true.
The next thing to do is reformat your prepareForSegue method in your parent view controller to pass the entire array of images to the presented view controller as well as the selected index path.
Then, in your presented view controller, you should have the collection view's data source be configured to show all the images but make sure to start at the initial, selected index path that was passed by the parent view controller.

Related

Cannot see my second collectionView on viewController

So I have my program where I have two collection views on the same ViewController. However when I run the app I can only see one. I have set the constraints on the image the same way on both.
the arrays productsImages and StoresImages are names of images I have in my assets folder. Firthermore pillImage and compStoreImage I have as outlet on my ColectionViewCell files.
HomeViewController.swift
import UIKit
class HomeViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource{
#IBOutlet weak var productCollectionView: UICollectionView!
#IBOutlet weak var storesCollectionView: UICollectionView!
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if(collectionView == storesCollectionView) {
return storesImages.count
}
return productsImages.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = productCollectionView.dequeueReusableCell(withReuseIdentifier: "productsCell", for: indexPath) as! productCollectionViewCell
cell.pillImage.image = UIImage(named: productsImages[indexPath.row])
if(collectionView == storesCollectionView) {
let cell2 = storesCollectionView.dequeueReusableCell(withReuseIdentifier: "storesCell", for: indexPath) as! StoreCollectionViewCell
cell2.compstoreImage.image = UIImage(named: storesImages[indexPath.row])
return cell2
}
return cell
}
var productsImages:[String] = ["pillImage", "pillyImage", "pillsImage"]
var storesImages:[String] = ["compstoreImage", "compeImage", "compeStore"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
StoreCollectionViewCell.swift
import UIKit
class StoreCollectionViewCell: UICollectionViewCell {
#IBOutlet var compstoreImage: UIImageView!
}
productCollectionViewCell.swift
import UIKit
class productCollectionViewCell: UICollectionViewCell {
#IBOutlet var pillImage: UIImageView!
}
Screenshot

How to push SDWebImage images to a detail view

I'm trying to figure out a way to push images that are loaded via SDWebImage on a TableView, to a view (DetailView) where the image can be viewed in fullscreen.
I have the images loaded from URLs displaying on a table view correctly. But when I tap on one, it segues to another view (DetailView) that is blank when I have a UIImage there. For some reason, the image is not loading.
Thanks!
Here is the TableView code:
import UIKit
class TableViewController: UITableViewController {
var imageURLs = [String]()
override func viewDidLoad() {
super.viewDidLoad()
imageURLs = ["https://i.imgur.com/lssFB4s.jpg","https://i.imgur.com/bSfVe7l.jpg","https://i.imgur.com/vRhhNFj.jpg"]
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "DetailView") {
let VC = segue.destinationViewController as! DetailViewController
if let indexpath = self.tableView.indexPathForSelectedRow {
let Imageview = imageURLs[indexpath.row] as String
VC.SentData1 = Imageview
}
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
let cell2: TableViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! TableViewCell
let imagename = UIImage(named: imageURLs[indexPath.row])
cell2.cellImage.image = imagename
let imageView = cell?.viewWithTag(1) as! UIImageView
imageView.sd_setImage(with: URL(string: imageURLs[indexPath.row]))
return cell!
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return imageURLs.count
}
Here is the DetailView code:
import UIKit
class DetailViewController: UIViewController {
#IBOutlet weak var Detailimageview: UIImageView!
var SentData1:String!
override func viewDidLoad() {
super.viewDidLoad()
Detailimageview.image = UIImage(named: SentData1)
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
You are using UIImage(named:) in your destination VC. This will try and load the image from your bundle, not from the network. You should use sd_setImage to fetch it from the network (or via cache if it has already been fetched):
Detailimageview.sd_setImage(with: URL(string:self.SentData1))
Note that properties and variables should start with a lower case letter by convention
When you load your detail view, you are passing the web URL for the image you want to load but then trying to load it from the bundle with UIImage(named: SentData1).
Instead you should just be loading it the same way you are doing it in your tableview cells by doing something like Detailimageview.sd_setImage(with: URL(string: SentData1))

How to set title in title bar based on which cell is viewed from collectionview cells in xcode ios

I'm making a medals page for an app I have in mind. I have the app set up in such a way that when a medal is clicked, it will open up a page containing a picture of that medal.
If possible, I also wish to add in a description for every medal in their view controllers. How do I achieve that?
Here's a sample of the code I have:
Medal.swift
import UIKit
class Medals: UICollectionViewController
{
// Defining the array
let imageArray = [UIImage(named: "1"), UIImage(named: "2")]
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//Allows you to populate the cells you've created
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
// cell was from the identifier we named earlier
// we let collectionviewcell handle the connection to UIcollectionviewcell
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! CollectionViewCell
cell.imageView?.image = self.imageArray[indexPath.row]
return cell
}
// How many cells do we want to have inside the collection view? Just count the number of images assigned
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count
}
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("showImage", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showImage"
{
let indexPaths = self.collectionView!.indexPathsForSelectedItems()!
let indexPath = indexPaths[0] as NSIndexPath
let vc = segue.destinationViewController as! MedalDetail
vc.image = self.imageArray[indexPath.row]!
}
}
}
CollectionViewCell.swift
import UIKit
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imageView: UIImageView!
}
medaldetails.swift
import UIKit
class MedalDetail: UIViewController {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var setTitle: UINavigationItem!
var image = UIImage()
var medalTitle = UINavigationItem()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.imageView.image = self.image
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Thanks for you help
edit:
This is how I want the medal page to look like when clicked:
First create array of medalDescriptions in Medals ViewController then in didSelectItemAtIndexPath call performSegue to MedalDetail viewController
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let index = indexPath.row
self.performSegueWithIdentifier("SegueMedalDetail", sender: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "SegueChallenge" {
let medalDetailViewController = segue.destinationViewController as! MedalDetail
medalDetailViewController.medalDescription = medalDescriptions[index]
}
}
In MedalDetail create medalDescription and in the same viewController change navbar title
override func viewDidAppear(animated: Bool) {
self.navigationController?.navigationBarHidden = false
self.navigationItem.title = medalDescription
self.navigationController!.navigationBar.tintColor = UIColor.whiteColor()
let attributes = [
NSForegroundColorAttributeName: UIColor.whiteColor(),
NSFontAttributeName: UIFont(name: "Helvetica", size: 50)!
]
self.navigationController?.navigationBar.titleTextAttributes = attributes
}
For future do not name your controllers or other class with just their names add also ViewController or View at the end. For example, MedalDetailViewController. That would be better to understand and read
Nevermind, I found another way to do it. I instantiated separate view controller for each medal and thus I can have diffwrent properties per view controller.

Swift passing array between swift files for tableview

I have a button action in one viewcontroller connect to another tableviewcontroller. I need to pass a few textfields value to show in another tableview via click the button. In the first view, I have a global array:
var estRent = [AnyObject]()
Append value within the buttonAction:
#IBAction func calculateButtonAction(sender: UIButton) {
...
estRent.append(weekRent)
estRent.append(monthRent)
estRent.append(yearRent)
estRent.append(interestRate)
estRent.append(loanAmount)
estRent.append(monthInterest)
}
Overwrite prepareForSegue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "Load View") {
let svc = segue.destinationViewController as! NextTableViewController
svc.rentArray = self.estRent
}
}
In the NextTableViewController, there is a global array:
var rentArray = [AnyObject]()
The next table view could not see the values in the array. Appreciate any help.
First View Controller:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var ageTextField: UITextField!
#IBOutlet weak var classTextField: UITextField!
var estRent = [AnyObject]()
#IBAction func goButtonAction(sender: UIButton) {
estRent.append(nameTextField.text!)
estRent.append(ageTextField.text!)
estRent.append(classTextField.text!)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
[estRent .removeAll()]
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
print(estRent)
if (segue.identifier == "LoadView") {
let svc = segue.destinationViewController as! RentTableViewController
svc.rentArray = self.estRent
}
}
}
RentTableViewController:
import UIKit
class RentTableViewController: UITableViewController {
var rentArray = [AnyObject]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return rentArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "studentCell")
let tableCell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("studentCell", forIndexPath: indexPath)
let rentLabel: UILabel = UILabel.init(frame: CGRectMake(10, 10, 100, 25))
rentLabel.text = rentArray[indexPath.row] as? String
tableCell.addSubview(rentLabel)
return tableCell
}
}
Click here for Main.storyboard image
You must give a segue identifier as "LoadView" in storyboard
Click here to view screen short for "How to give segue identifier"

Using UITableView in detail, how to display string in TextView (Master-Detail project, Swift, iOS)

I want to use a TableView for the detail side of a Master Detail app. I have started with the standard Master Detail project in Xcode, deleted the standard app that comes with it, deleted the standard UIView detail controller, added a TableView controller, added a TextView to the prototype cell for testing, and created a new segue to the new TableView. I subclassed UITableViewCell and created an outlet (detailTextView) from the TextView to the subclass (TableViewCell). Changed the class in DetailViewController.swift from UIViewController to UITableViewController. I am successfully passing a string stringForTextView = "String for TextView" from master to the detail. But I can't figure out how to display that string in the TextView. I tried to reference the TextView text in the detail view through the outlet (detailTextView.text) but got "Use of unresolved identifier detailTextView"
Any help will be greatly appreciated.
Relevant code is shown below.
You can also download the whole project here if that would be helpful:
http://greendept.com/MasterDetailTwoTableViews/
TableViewCell.swift (subclass for prototype cell in detail)
import UIKit
class TableViewCell: UITableViewCell {
#IBOutlet weak var detailTextView: UITextView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
DetailViewController.swift
import UIKit
class DetailViewController: UITableViewController {
var stringForTextView : String?
var detailItem: AnyObject? {
didSet {
// Update the view.
self.configureView()
}
}
func configureView() {
// THE NEXT TWO LINES WORK: PASSED IN STRING PRINTS TO CONSOLE
let printThis = stringForTextView! as String
print("\(printThis)")
// BUT THE REFERENCE TO THE OUTLET BELOW DOES NOT WORK, GIVES
// "Use of unresolved identifier detailTextView"
detailTextView.text = printThis
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.configureView()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
MasterViewController.swift
import UIKit
class MasterViewController: UITableViewController {
var detailViewController: DetailViewController? = nil
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
if let split = self.splitViewController {
let controllers = split.viewControllers
self.detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
}
}
override func viewWillAppear(animated: Bool) {
self.clearsSelectionOnViewWillAppear = self.splitViewController!.collapsed
super.viewWillAppear(animated)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Segues
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetail" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
controller.stringForTextView = "String for TextView"
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
}
// MARK: - Table View
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
return cell
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
}
DetailViewController is a UITableViewController, and you can't access the detailTextView in the tableView controller. You defined the outlet in the cell, and that is where you can access and configure the detailTextView.
It doesn't make any sense to have the DetailViewController as a UITableViewController, if what you really want is to configure the text view there. Then you should set it back to a UIViewController, and add the text view as a single UITextView to the view controllers view.
This link below shows how you can change text in a cell label even though the outlet to the textview is in the cell subclass. It shows this with a single TableView.
creating custom tableview cells in swift
In adapting the above approach for my test project, I didn't have to change the Master at all. In the Detail view, the configureView() doesn't do the main job of updating the TextView. That happens in cellForRowAtIndexPath -- second to the last function in detail view. Another difference is I could not, and did not need to, implement #IBOutlet var tableView: UITableView! -- because tableView was already available as a stored property. I also had to add overrride in a couple of places. Finally, in the TableViewCell class, I added an outlet linked to the content view of the TextView. The result is that the TextView text is getting updated.
TableViewCell.swift:
import UIKit
class TableViewCell: UITableViewCell {
#IBOutlet weak var detailTextView: UITextView!
#IBOutlet weak var detailContentView: UIView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
print ("awakeFromNib")
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
print("test")
}
}
DetailViewController.swift:
import UIKit
class DetailViewController: UITableViewController {
// #IBOutlet var tableView: UITableView! -- cannot override a stored property
var stringForTextView : String?
// Don't forget to enter this in IB also
let cellReuseIdentifier = "reuseIdentifier"
var detailItem: AnyObject? {
didSet {
// Update the view.
self.configureView()
}
}
func configureView() {
// Update the user interface for the detail item.
// stringForTextView
let printThis = stringForTextView! as String
print("\(printThis)")
// detailTextView.text = printThis
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
self.configureView()
}
// needed "override" here
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
// create a cell for each table view row
// needed "override" here
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:TableViewCell = self.tableView.dequeueReusableCellWithIdentifier(cellReuseIdentifier) as! TableViewCell
cell.detailTextView.text = stringForTextView
print("cell.detailTextView.text: \(cell.detailTextView.text)")
print("row : \(indexPath.row)")
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Resources