I am using pod 'CardsLayout' to my project.
cardlayout library
The image is
this library doesn't have functionality of swipe left and swipe right programmatically. so, i checked that, it is using UICollectionView. So, i thought that i can use selectItem by following code.
func onNextButtonClicked(collectionViewCell:QuestionrieViewCell) {
let currentIndex = collectionViewCell.getIndexPath().row
if currentIndex < getIndexPaths().count-1{
collectionView.deselectItem(at: collectionViewCell.getIndexPath(), animated: true)
collectionView.selectItem(at: getIndexPaths()[collectionViewCell.getIndexPath().row + 1], animated: true, scrollPosition: .left)
self.collectionView(collectionView, didSelectItemAt:getIndexPaths()[collectionViewCell.getIndexPath().row + 1] )
}
}
func onPrevButtonClicked(collectionViewCell:QuestionrieViewCell) {
let currentIndex = collectionViewCell.getIndexPath().row
if currentIndex > 0{
collectionView.deselectItem(at: collectionViewCell.getIndexPath(), animated: true)
collectionView.selectItem(at: getIndexPaths()[collectionViewCell.getIndexPath().row - 1], animated: true, scrollPosition: .right)
self.collectionView(collectionView, didSelectItemAt:getIndexPaths()[collectionViewCell.getIndexPath().row - 1] )
}
}
I want that, swipe left and swipe right should be happen when the user click the buttons. here,
onPreviousButtonClicked working fine. whereas, swipe right button click not responding like i expected.
onNextBUttonClick gives weird response. response as below
it's stopped going to left and if i click the same right arrow button, on that stopped card, then it still slide little bit of the screen then stopped going to left.i don't know what should i do. Anyone can help me?
Edit
Additional images below.
ViewController Class is here
class ControllerQuestionarie: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate,QuestionrieViewCellDelegate{
var currentIndexPath:IndexPath?
var indexPaths:[IndexPath] = [IndexPath]()
var swipeToLeft:UISwipeGestureRecognizer?,swipeToRight:UISwipeGestureRecognizer?
var previousPage : Int = 0
#IBOutlet weak var linearProgressBar: LinearProgressBar!
#IBOutlet weak var lblQuestionNumber: UILabel!
func setIndexPaths(indexPath:IndexPath){
self.indexPaths.append(indexPath)
}
func getIndexPaths()->[IndexPath]{
return self.indexPaths
}
func onNextButtonClicked(collectionViewCell:QuestionrieViewCell) {
let currentIndex = collectionViewCell.getIndexPath().row
if currentIndex < getIndexPaths().count-1{
self.collectionView.selectItem(at: IndexPath(item: collectionViewCell.getIndexPath().row + 1, section: 0), animated: true, scrollPosition: .left)
self.collectionView(self.collectionView, didSelectItemAt: IndexPath(item: collectionViewCell.getIndexPath().row + 1, section: 0))
self.collectionView.layoutIfNeeded()
self.currentIndexPath = collectionViewCell.getIndexPath()
if self.currentIndexPath!.row == 4{
let controllerQuestionarieCompletionViewController = ControllerQuestionarieCompletionViewController.init(nibName: "ControllerQuestionarieCompletionViewController", bundle: nil)
self.navigationController!.pushViewController(controllerQuestionarieCompletionViewController, animated: true)
}
}
}
func onPrevButtonClicked(collectionViewCell:QuestionrieViewCell) {
let currentIndex = collectionViewCell.getIndexPath().row
if currentIndex > 0{
self.collectionView.selectItem(at: IndexPath(item: collectionViewCell.getIndexPath().row - 1, section: 0), animated: true, scrollPosition: .right)
self.collectionView(self.collectionView, didSelectItemAt: IndexPath(item: collectionViewCell.getIndexPath().row - 1, section: 0))
self.collectionView.layoutIfNeeded()
self.currentIndexPath = collectionViewCell.getIndexPath()
}
}
override func viewDidLoad() {
super.viewDidLoad()
collectionView.register(UINib.init(nibName: "QuestionrieViewCell", bundle: nil), forCellWithReuseIdentifier: "QuestionrieViewCell")
collectionView.collectionViewLayout = CardsCollectionViewLayout()
collectionView.dataSource = self
collectionView.delegate = self
collectionView.isPagingEnabled = true
collectionView.showsHorizontalScrollIndicator = false
let progressValue = 100/CGFloat(colors.count)
let progress = CGFloat(progressValue) * CGFloat(previousPage + 1)
lblQuestionNumber.text = "\(previousPage + 1) / \(colors.count)"
linearProgressBar.progressValue = progress
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.currentIndexPath = indexPath
// ... Other settings
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageWidth = scrollView.frame.size.width
let page = Int(floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1)
print (page)
if previousPage != page{
let progressValue = 100/CGFloat(colors.count)
let progress = CGFloat(progressValue) * CGFloat(page + 1)
lblQuestionNumber.text = "\(page + 1) / \(colors.count)"
linearProgressBar.progressValue = progress
}
previousPage = page
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "QuestionrieViewCell", for: indexPath) as! QuestionrieViewCell
cell.questionrieViewCellDelegate = self
cell.layer.cornerRadius = 50.0
cell.setIndexPath(indexPath: indexPath)
setIndexPaths(indexPath: indexPath)
cell.bindData()
cell.view.backgroundColor = colors[indexPath.row]
return cell
}
#IBOutlet var collectionView: UICollectionView!
var colors: [UIColor] = [
UIColor(red: 255, green: 255, blue: 255),
UIColor(red: 249, green: 220, blue: 92),
UIColor(red: 194, green: 234, blue: 189),
UIColor(red: 1, green: 25, blue: 54),
UIColor(red: 255, green: 184, blue: 209)
]
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return colors.count
}
}
extension UIColor {
convenience init(red: Int, green: Int, blue: Int) {
self.init(red: CGFloat(red)/255 ,
green: CGFloat(green)/255,
blue: CGFloat(blue)/255,
alpha: 1.0)
}
}
Yes. I did it. Finally i have tasted the answer for this question.
public func moveToPage(position:Int){
let totalPage = collectionView.contentOffset.x/collectionView.frame.width// getting totalNumberOfPage
if position < Int(totalPage){
scrollToPage(page: position, animated: true)
}
}
public func moveToNextPage()->Int{
let pageIndex = round(collectionView.contentOffset.x/collectionView.frame.width)
let pageNo = Int(pageIndex+1)
scrollToPage(page: pageNo, animated: true)
return pageNo
}
public func moveToPreviousPage()->Int{
let pageIndex = round(collectionView.contentOffset.x/collectionView.frame.width)
let pageNo = Int(pageIndex-1)
scrollToPage(page: pageNo, animated: true)
return pageNo
}
func scrollToPage(page: Int, animated: Bool) {
var frame: CGRect = self.collectionView.frame
frame.origin.x = frame.size.width * CGFloat(page)
frame.origin.y = 0
self.collectionView.scrollRectToVisible(frame, animated: animated)
}
It works like charm. Thank you
Related
My Viewcontroller shows "Cannot find 'selectedIndexPaths' in scope" and other errors
My viewcontroller with errors:- import UIKit
class ProductViewController: UIViewController, UITableViewDataSource,
UITableViewDelegate {
let notificationButton = SSBadgeButton()
let rightbarbuttonimage = UIImage(named:"ic_cart")
fileprivate var cart = Cart()
let scrollView = UIScrollView()
let sections = ["Section A", "Section B","Section C", "Section D","Section E","Section F","Section G","Section H", "Section I","Section J","Section K","Section L"]
let rowspersection = [2,3,1,2,2,3,3,1,4,2,1,2]
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
self.tableView.backgroundColor = UIColor.gray
//Add and setup scroll view
self.tableView.addSubview(self.scrollView)
self.scrollView.translatesAutoresizingMaskIntoConstraints = false;
//Constrain scroll view
self.scrollView.leadingAnchor.constraint(equalTo: self.tableView.leadingAnchor, constant: 20).isActive = true;
self.scrollView.topAnchor.constraint(equalTo: self.tableView.topAnchor, constant: 20).isActive = true;
self.scrollView.trailingAnchor.constraint(equalTo: self.tableView.trailingAnchor, constant: -20).isActive = true;
self.scrollView.bottomAnchor.constraint(equalTo: self.tableView.bottomAnchor, constant: -20).isActive = true;
// customising rightBarButtonItems as notificationbutton
notificationButton.frame = CGRect(x: 0, y: 0, width: 44, height: 44)
notificationButton.setImage(UIImage(named: "ic_cart")?.withRenderingMode(.alwaysTemplate), for: .normal)
notificationButton.badgeEdgeInsets = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 15)
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: notificationButton)
//following register is needed because I have rightbarbuttonitem customised as uibutton i.e. notificationbutton
notificationButton.addTarget(self, action: #selector(self.registerTapped(_:)), for: .touchUpInside)
}
#objc func registerTapped(_ sender: UIButton) {
self.performSegue(withIdentifier: "showCart", sender: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//Workaround to avoid the fadout the right bar button item
self.navigationItem.rightBarButtonItem?.isEnabled = false
self.navigationItem.rightBarButtonItem?.isEnabled = true
//Update cart if some items quantity is equal to 0 and reload the product table and right button bar item
cart.updateCart()
//self.navigationItem.rightBarButtonItem?.title = "Checkout (\(cart.items.count))"
notificationButton.badge = String(cart.items.count)// making badge equal to no.ofitems in cart
tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// this segue to transfer data
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showCart" {
if let cartViewController = segue.destination as? CartViewController {
cartViewController.cart = self.cart
}
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return productMap.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return productMap[section]?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let product = productMap[indexPath.section]![indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "ProductTableViewCell") as! ProductTableViewCell
cell.imageView?.image = product.imagename
cell.delegate = self as CartDelegate
cell.setButton(state: self.cart.contains(product: product))
return cell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 44
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch(section) {
case 0: return "Section A"
case 1: return "Section B"
case 2: return "Section C"
case 3: return "Section D"
case 4: return "Section E"
case 5: return "Section F"
case 6: return "Section G"
case 7: return "Section H"
case 8: return "Section I"
case 9: return "Section J"
case 10: return "Section K"
case 11: return "Section L"
default: return ""
}
}
}
extension ProductViewController: CartDelegate {
// MARK: - CartDelegate
func updateCart(cell: ProductTableViewCell) {
guard let indexPath = tableView.indexPath(for: cell) else { return }
let product = productMap[indexPath.section]![indexPath.row]
/// `var selectedIndexPaths = [IndexPath]()` defined inside `ProductViewController`, to keep track of the selected products// **error -Cannot find 'selectedIndexPaths' in scope**
if selectedIndexPaths.contains(indexPath) {**//error -Cannot find 'selectedIndexPaths' in scope**
if let index = selectedIndexPaths.firstIndex(of: indexPath) {
selectedIndexPaths.remove(at: index)**//error -Cannot find 'selectedIndexPaths' in scope**
removeProductFromCart(indexPath: indexPath)
}
} else {
selectedIndexPaths.append(indexPath)
addProductToCart(indexPath: indexPath)
}
// addProductToCart(indexPath: indexPath)
/// **I commented this out because I don't have the code for `Cart`**
//Update Cart with product
// cart.updateCart(with: product)
// self.navigationItem.rightBarButtonItem?.title = "Checkout (\(cart.items.count))"
// notificationButton.badge = String(cart.items.count) // making badge equal to noofitems in cart
}
}
func addProductToCart(indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? ProductTableViewCell {
if let imageView = cell.imagename {
let initialImageViewFrame = imageView.convert(imageView.frame, to: self.view)
let targetImageViewFrame = self.notificationButton.frame
let imgViewTemp = UIImageView(frame: initialImageViewFrame)
imgViewTemp.clipsToBounds = true
imgViewTemp.contentMode = .scaleAspectFill
imgViewTemp.image = imageView.image
self.view.addSubview(imgViewTemp)
UIView.animate(withDuration: 1.0, animations: {
imgViewTemp.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
}) { _ in
UIView.animate(withDuration: 0.5, animations: {
imgViewTemp.transform = CGAffineTransform(scaleX: 0.2, y: 0.2).rotated(by: CGFloat(Double.pi))
imgViewTemp.frame = targetImageViewFrame
}) { _ in
imgViewTemp.removeFromSuperview()
UIView.animate(withDuration: 1.0, animations: {
self.notificationButton.transform = CGAffineTransform(scaleX: 1.4, y: 1.4)
}, completion: {_ in
self.notificationButton.transform = CGAffineTransform.identity
})
}
}
}
}
}
func removeProductFromCart(indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? ProductTableViewCell {
if let imageView = cell.imagename {
let initialImageViewFrame = self.notificationButton.frame
let targetImageViewFrame = imageView.convert(imageView.frame, to: self.view)
let imgViewTemp = UIImageView(frame: initialImageViewFrame)
imgViewTemp.clipsToBounds = true
imgViewTemp.contentMode = .scaleAspectFill
imgViewTemp.image = imageView.image
self.view.addSubview(imgViewTemp)
var initialTransform = CGAffineTransform.identity
initialTransform = initialTransform.scaledBy(x: 0.2, y: 0.2)
initialTransform = initialTransform.rotated(by: CGFloat(Double.pi))
UIView.animate(withDuration: 0.5, animations: {
self.notificationButton.animationZoom(scaleX: 1.4, y: 1.4)
imgViewTemp.transform = initialTransform
}) { _ in
UIView.animate(withDuration: 1, animations: {
self.notificationButton.animationZoom(scaleX: 1, y: 1)
imgViewTemp.transform = CGAffineTransform.identity
imgViewTemp.frame = targetImageViewFrame
}) { _ in
imgViewTemp.removeFromSuperview()
}
}
}
}
}
screenshot of the error-
I have tableview in my productviewcotroller as shown below. so, thats not an issusem still errors:-
There are other errors also which it is showing.
How to sort it out ?
var selectedIndexPaths = IndexPath
Please define selectedIndexPaths inside the main class not in the extension then check it again .
first, I hope I don't break any rules or make it long but I'm really stuck and spent the whole day about that so I would love to get help with that :).
Okay so I'm having a popped up view controller using Panmodel 3rd party and I've got a UIButton inside of a UITableView custom cell, now I want to present my custom calendar when the user press the button, now I followed Ray tutorial(Link) on how to do a custom calendar and it still doesn't work for me, for some reason when I press the button it just shows a clear view + freezes my screen :|, I'm going to post the code of my tableView setup + the cell of the UIButton, not going to post the code of the calendar because it's long and I don't want to spam, if needed I will post that :) once again thanks for the help really spent the whole day about it and found myself with no solution, so here's my code:
Code: TableViewVC:
import UIKit
import PanModal
class FilterTableViewController: UITableViewController, PanModalPresentable {
var panScrollable: UIScrollView? {
return tableView
}
var albumsPickerIndexPath: IndexPath? // indexPath of the currently shown albums picker in tableview.
var datesCell = DatesCell()
override func viewDidLoad() {
super.viewDidLoad()
setupTableView()
// registerTableViewCells()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// tableView.frame = view.bounds
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
// MARK: - View Configurations
func setupTableView() {
tableView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
tableView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
tableView.separatorStyle = .singleLine
tableView.isScrollEnabled = false
tableView.allowsSelection = true
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 600
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
}
func indexPathToInsertDatePicker(indexPath: IndexPath) -> IndexPath {
if let albumsPickerIndexPath = albumsPickerIndexPath, albumsPickerIndexPath.row < indexPath.row {
return indexPath
} else {
return IndexPath(row: indexPath.row + 1, section: indexPath.section)
}
}
// MARK: - UITableViewDataSource
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// If datePicker is already present, we add one extra cell for that
if albumsPickerIndexPath != nil {
return 5 + 1
} else {
return 5
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.row {
case 0:
let byActivityCell = UINib(nibName: "byActivityCell",bundle: nil)
self.tableView.register(byActivityCell,forCellReuseIdentifier: "byActivityCell")
let activityCell = tableView.dequeueReusableCell(withIdentifier: "byActivityCell", for: indexPath) as! byActivityCell
activityCell.selectionStyle = .none
return activityCell
case 1:
let byTypeCell = UINib(nibName: "ByType",bundle: nil)
self.tableView.register(byTypeCell,forCellReuseIdentifier: "byTypeCell")
let typeCell = tableView.dequeueReusableCell(withIdentifier: "byTypeCell", for: indexPath) as! ByType
typeCell.selectionStyle = .none
return typeCell
case 2:
let byHashtagsCell = UINib(nibName: "ByHashtags",bundle: nil)
self.tableView.register(byHashtagsCell,forCellReuseIdentifier: "byHashtagsCell")
let hashtagsCell = tableView.dequeueReusableCell(withIdentifier: "byHashtagsCell", for: indexPath) as! ByHashtags
hashtagsCell.selectionStyle = .none
return hashtagsCell
case 3:
let byDatesCell = UINib(nibName: "DatesCell",bundle: nil)
self.tableView.register(byDatesCell,forCellReuseIdentifier: "byDatesCell")
let datesCell = tableView.dequeueReusableCell(withIdentifier: "byDatesCell", for: indexPath) as! DatesCell
datesCell.selectionStyle = .none
datesCell.datesTableViewCellDelegate = self
return datesCell
case 4:
let byAlbumCell = UINib(nibName: "AlbumCell",bundle: nil)
self.tableView.register(byAlbumCell,forCellReuseIdentifier: "byAlbumCell")
let albumCell = tableView.dequeueReusableCell(withIdentifier: "byAlbumCell", for: indexPath) as! AlbumCell
albumCell.configureCell(choosenAlbum: "Any")
albumCell.selectionStyle = .none
return albumCell
case 5:
let albumPickerCell = UINib(nibName: "AlbumsPickerTableViewCell", bundle: nil)
self.tableView.register(albumPickerCell, forCellReuseIdentifier: "albumPickerCell")
let albumsPicker = tableView.dequeueReusableCell(withIdentifier: "albumPickerCell", for: indexPath) as! AlbumsPickerTableViewCell
return albumsPicker
default:
return UITableViewCell()
}
}
// MARK: - footer Methods:
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
return getfooterView()
}
func getfooterView() -> UIView
{
let footerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 400))
let applyFiltersBtn = UIButton(frame: CGRect(x: 0, y: 0, width: 380, height: 35))
applyFiltersBtn.center = footerView.center
applyFiltersBtn.layer.cornerRadius = 12
applyFiltersBtn.layer.masksToBounds = true
applyFiltersBtn.setTitle("Apply Filters", for: .normal)
applyFiltersBtn.backgroundColor = #colorLiteral(red: 0.1957295239, green: 0.6059523225, blue: 0.960457623, alpha: 1)
// doneButton.addTarget(self, action: #selector(hello(sender:)), for: .touchUpInside)
footerView.addSubview(applyFiltersBtn)
return footerView
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 10
}
// MARK: TableViewDelegate Methods:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
tableView.beginUpdates()
// 1 - We Delete the UIPicker when the user "Deselect" the row.
if let datePickerIndexPath = albumsPickerIndexPath, datePickerIndexPath.row - 1 == indexPath.row {
tableView.deleteRows(at: [datePickerIndexPath], with: .fade)
self.albumsPickerIndexPath = nil
} else {
// 2
// if let datePickerIndexPath = albumsPickerIndexPath {
// tableView.deleteRows(at: [datePickerIndexPath], with: .fade)
// }
albumsPickerIndexPath = indexPathToInsertDatePicker(indexPath: indexPath)
tableView.insertRows(at: [albumsPickerIndexPath!], with: .fade)
tableView.deselectRow(at: indexPath, animated: true)
}
tableView.endUpdates()
if indexPath.row == 4 {
let pickerController = CalendarPickerViewController(
baseDate: Date(),
selectedDateChanged: { [weak self] date in
guard let self = self else { return }
// self.item.date = date
self.tableView.reloadRows(at: [IndexPath(row: 3, section: 0)], with: .fade)
})
present(pickerController, animated: true, completion: nil)
}
}
override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
if indexPath.row == 4 {
return indexPath
} else {
return nil
}
}
}
extension FilterTableViewController: DatesTableViewCellDelegate {
func didButtonFromPressed() {
print("Button From is Pressed")
let pickerController = CalendarPickerViewController(
baseDate: Date(),
selectedDateChanged: { [weak self] date in
guard let self = self else { return }
// self.item.date = date
self.tableView.reloadRows(at: [IndexPath(row: 3, section: 0)], with: .fade)
})
present(pickerController, animated: true, completion: nil)
}
func didButtonToPressed() {
print("Button To is Pressed")
//TODO: Present our custom calendar
let vcToDisplay = CalendarPickerViewController(baseDate: Date()) { (date) in
self.tableView.reloadRows(at: [IndexPath(row: 3, section: 0)], with: .fade)
}
self.present(vcToDisplay, animated: true, completion: nil)
}
}
custom cell code:
import UIKit
// MARK: - Class Protocols:
protocol DatesTableViewCellDelegate { // a delegate to tell when the user selected the button:
func didButtonFromPressed()
func didButtonToPressed()
}
class DatesCell: UITableViewCell {
#IBOutlet var fromDate: UIButton!
#IBOutlet var toDate: UIButton!
var datesTableViewCellDelegate: DatesTableViewCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
fromDate.layer.cornerRadius = 5
toDate.layer.cornerRadius = 5
fromDate.layer.borderWidth = 1
toDate.layer.borderWidth = 1
fromDate.layer.borderColor = #colorLiteral(red: 0.2005972862, green: 0.6100016236, blue: 0.9602670074, alpha: 1)
toDate.layer.borderColor = #colorLiteral(red: 0.2005972862, green: 0.6100016236, blue: 0.9602670074, alpha: 1)
fromDate.layer.masksToBounds = true
toDate.layer.masksToBounds = true
self.preservesSuperviewLayoutMargins = false
self.separatorInset = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 15)
self.layoutMargins = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 15)
}
// MARK: - UIButton Methods:
#IBAction func fromDateButtonIsPressed(_ sender: UIButton) {
datesTableViewCellDelegate?.didButtonFromPressed()
}
#IBAction func toDateButtonIsPressed(_ sender: UIButton) {
datesTableViewCellDelegate?.didButtonToPressed()
}
}
Found the problem, the problem was with the auto-layout, I changed the auto layout to be like this:
override func viewDidLoad() {
super.viewDidLoad()
collectionView.backgroundColor = .yellow
view.addSubview(dimmedBackgroundView)
view.addSubview(collectionView)
var constraints = [
dimmedBackgroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
dimmedBackgroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
dimmedBackgroundView.topAnchor.constraint(equalTo: view.topAnchor),
dimmedBackgroundView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
]
constraints.append(contentsOf: [
//1
collectionView.leadingAnchor.constraint(
equalTo: view.readableContentGuide.leadingAnchor),
collectionView.trailingAnchor.constraint(
equalTo: view.readableContentGuide.trailingAnchor),
//2
collectionView.centerYAnchor.constraint(
equalTo: view.centerYAnchor,
constant: 10),
//3
collectionView.heightAnchor.constraint(
equalTo: view.heightAnchor,
multiplier: 0.5)
])
NSLayoutConstraint.activate(constraints)
// NSLayoutConstraint.activate([
// dimmedBackgroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
// dimmedBackgroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
// dimmedBackgroundView.topAnchor.constraint(equalTo: view.topAnchor),
// dimmedBackgroundView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
// ])
}
i am implementing collection view as my ChatMessagViewController and i am populating message in collectionview all things works perfect for me but issue is that when i scrolled collection view message was . issing or replaced on scroll let me show you my code for populating collectionview
here i am adding screen shot for what output i get before scrolling and after scrolling please have a look
func loadMessageData(){
self.message.removeAll()
guard let uid = Auth.auth().currentUser?.uid else{
return
}
let userref = Database.database().reference().child("Message").child(uid)
userref.child(self.senderID!).observe(.childAdded, with: { (snapshot) in
print(snapshot)
if let dictonary = snapshot.value as? [String:AnyObject]{
let key = snapshot.key
let mainDict = NSMutableDictionary()
mainDict.setObject(key, forKey: "userid" as NSCopying)
self.namesArray.add(mainDict)
let message = Message(dictionary: dictonary)
self.message.append(message)
self.timer?.invalidate()
self.timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(self.handleReload), userInfo: nil, repeats: false)
}
}, withCancel: nil)
}
extension ChatViewController: UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return message.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellID, for: indexPath) as! ChatMessageCell
let message1 = message[indexPath.item]
cell.tetxtView.text = message1.msg
cell.bubbleWidthAnchor?.constant = estimatedFrameForText(text: message1.msg!).width + 32
let ketID = message1.key_id
if ketID == Auth.auth().currentUser?.uid{
cell.bubbleView.backgroundColor = UIColor(red: 255, green: 255, blue: 255, alpha: 1)
cell.bubbleViewRightAnchor?.isActive = false
cell.bubbleViewLeftAnchor?.isActive = true
}else{
cell.bubbleView.backgroundColor = UIColor(red: 0/255, green: 158/255, blue: 214/255, alpha: 1)
cell.tetxtView.textColor = UIColor.white
cell.bubbleViewRightAnchor?.isActive = true
cell.bubbleViewLeftAnchor?.isActive = false
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
var height: CGFloat = 80
if let mesg = message[indexPath.item].msg{
height = estimatedFrameForText(text: mesg).height + 20
}
return CGSize(width: view.frame.width, height: height)
}
}
and here is the collectionview methods for populating
issue is that when i scroll the message was replaced or missing
please check screen shot first i am getting messages and after scrolling i came back to top message is missing
cell.tetxtView.textColor is dequeued make sure to add it inside the if also
if ketID == Auth.auth().currentUser?.uid{
cell.bubbleView.backgroundColor = UIColor(red: 255, green: 255, blue: 255, alpha: 1)
cell.tetxtView.textColor = UIColor.black /////// here
cell.bubbleViewRightAnchor?.isActive = false
cell.bubbleViewLeftAnchor?.isActive = true
}else{
cell.bubbleView.backgroundColor = UIColor(red: 0/255, green: 158/255, blue: 214/255, alpha: 1)
cell.tetxtView.textColor = UIColor.white
cell.bubbleViewRightAnchor?.isActive = true
cell.bubbleViewLeftAnchor?.isActive = false
}
The text color is white so it same as the background of it's superview , hence doesn't appear
I've created custom collection view layout(for MultiDirectional scroll), running successfully. Now, I tried to achieve pagination from all sides (top, left, right and bottom). For that, I am tracing the scroll direction and upon reaching the border elements, I wish to paginate(load more data) in that direction. But as I need to place the page default to top-left position, the top-left elements are already reached and hence resulting in conflicts. Can you help?
Following code I tried:
import UIKit
class ViewController: UIViewController{
var cellId: String = "MyCellId"
var vPivotPrev = 0
var vPivotNext = 19
var hPivotPrev = 0
var hPivotNext = 29
var targetPoint = CGPoint(x: 0, y: 0)
var scrollDirection: String = ""
var scrolledDailyToTop:String = ""
var scrolledDailyToBottom:String = ""
var scrolledDailyToLeft:String = ""
var scrolledDailyToRight:String = ""
var shouldPaginate:Bool = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
showCollectionView()
}
var customCollectionView: UICollectionView = { // CODE TO CREATE CUSTOM COLLECTION VIEW
let layout = CustomCollectionViewLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
return cv
}()
class CustomCell: UICollectionViewCell{ // CODE TO CREATE CUSTOM CELLS
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
let label: UILabel = {
let myLabel = UILabel()
return myLabel
}()
func setup(){
addSubview(label)
}
}
func showCollectionView(){
view.addSubview(customCollectionView)
customCollectionView.backgroundColor = .darkGray
customCollectionView.frame = CGRect(x: 60, y: 145, width: UIScreen.main.bounds.size.width-120, height: UIScreen.main.bounds.size.height/1.8)
customCollectionView.dataSource = self
customCollectionView.delegate = self
customCollectionView.register(CustomCell.self, forCellWithReuseIdentifier: cellId) // REGISTER CELL CLASS
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// DETECT SCROLL DIRECTION CODE
var currentPoint = scrollView.contentOffset
if(targetPoint.y > currentPoint.y){
scrollDirection = "going up"
print(scrollDirection)
}
else if(targetPoint.y < currentPoint.y){
scrollDirection = "going down"
print(scrollDirection)
}
if(targetPoint.x > currentPoint.x){
scrollDirection = "going left"
print(scrollDirection)
}
else if(targetPoint.x < currentPoint.x){
scrollDirection = "going right"
print(scrollDirection)
}
self.targetPoint = scrollView.contentOffset
}
}
extension ViewController: UICollectionViewDataSource{
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 20
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 30
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! CustomCell
cell.label.text = "\(indexPath.section.description),\(indexPath.item.description)"
cell.backgroundColor = .lightGray
cell.label.frame = CGRect(x: 0, y: 0, width: cell.contentView.bounds.width, height: 10)
cell.label.textColor = .white
cell.bringSubview(toFront: cell.label)
return cell
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
for visibleIndices in collectionView.indexPathsForVisibleItems{
if(visibleIndices.section == vPivotPrev){
scrolledDailyToTop = "top"
shouldPaginate = true
paginate()
}
else if(visibleIndices.section == vPivotNext){
scrolledDailyToBottom = "bottom"
shouldPaginate = true
paginate()
}
else if(visibleIndices.item == hPivotPrev){
scrolledDailyToLeft = "left"
shouldPaginate = true
paginate()
}
else if(visibleIndices.item == hPivotNext){
scrolledDailyToRight = "right"
shouldPaginate = true
paginate()
}
}
}
func paginate(){
print("Swipe Direction: \(scrollDirection)")
if(shouldPaginate == true){
if(self.scrollDirection == "going down" && self.scrolledDailyToTop == "top"){ // PAGINATING USING 9 BOX LOGIC
print("Fetch Vertical previous page")
//getNewPageData(gotopageURL: self.goToPageURL)
self.customCollectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .bottom, animated: false)
self.customCollectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .left, animated: false)
shouldPaginate = false
}
else if(self.scrollDirection == "going up" && self.scrolledDailyToBottom == "bottom"){
print("Fetch Vertical next page")
//getNewPageData(gotopageURL: self.goToPageURL)
self.customCollectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
self.customCollectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .left, animated: false)
shouldPaginate = false
}
else if(self.scrollDirection == "going right" && self.scrolledDailyToLeft == "left"){
print("Fetch Horizontal previous page")
//getNewPageData(gotopageURL: self.goToPageURL)
self.customCollectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
self.customCollectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .right, animated: false)
shouldPaginate = false
}
else if(self.scrollDirection == "going left" && self.scrolledDailyToRight == "right"){
print("Fetch Horizontal next page")
//getNewPageData(gotopageURL: self.goToPageURL)
self.customCollectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
self.customCollectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .left, animated: false)
shouldPaginate = false
}
scrolledDailyToTop = ""
scrolledDailyToBottom = ""
scrolledDailyToLeft = ""
scrolledDailyToRight = ""
}
}
}
extension ViewController: UICollectionViewDelegate{
func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
let cell:CustomCell = collectionView.cellForItem(at: indexPath)! as! ViewController.CustomCell
print("SELECTED CELL: \(cell.label.text!)")
return true
}
}
The code for Multi-Directional Scroll CustomCollectionViewLayout
import UIKit
class CustomCollectionViewLayout:UICollectionViewFlowLayout {
let CELL_HEIGHT = 50.0
let CELL_WIDTH = 80.0
let STATUS_BAR = UIApplication.shared.statusBarFrame.height
var cellAttrsDictionary = Dictionary<IndexPath, UICollectionViewLayoutAttributes>()
var contentSize = CGSize.zero
var dataSourceDidUpdate = true
override var collectionViewContentSize : CGSize {
return self.contentSize
}
override func prepare() {
dataSourceDidUpdate = false
cellAttrsDictionary.removeAll()
if let sectionCount = collectionView?.numberOfSections, sectionCount > 0 {
for section in 0...sectionCount-1 {
if let rowCount = collectionView?.numberOfItems(inSection: section), rowCount > 0 {
for item in 0...rowCount-1 {
let cellIndex = IndexPath(item: item, section: section)
let xPos = Double(item) * CELL_WIDTH
let yPos = Double(section) * CELL_HEIGHT
let cellAttributes = UICollectionViewLayoutAttributes(forCellWith: cellIndex)
cellAttributes.frame = CGRect(x: xPos, y: yPos, width: CELL_WIDTH, height: CELL_HEIGHT)
if section == 0 && item == 0 {
cellAttributes.zIndex = 4
} else if section == 0 {
cellAttributes.zIndex = 3
} else if item == 0 {
cellAttributes.zIndex = 2
} else {
cellAttributes.zIndex = 1
}
cellAttrsDictionary[cellIndex] = cellAttributes
}
}
}
}
let contentWidth = Double(collectionView!.numberOfItems(inSection: 0)) * CELL_WIDTH
let contentHeight = Double(collectionView!.numberOfSections) * CELL_HEIGHT
self.contentSize = CGSize(width: contentWidth, height: contentHeight)
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var attributesInRect = [UICollectionViewLayoutAttributes]()
for cellAttributes in cellAttrsDictionary.values {
if rect.intersects(cellAttributes.frame) {
attributesInRect.append(cellAttributes)
}
}
return attributesInRect
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return cellAttrsDictionary[indexPath]!
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
}
I'm trying to programmatically select all rows in my tableview using the following code:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:myTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell") as! myTableViewCell
cell.accessoryType = .None
if allJobsSelected {
let bgColorView = UIView()
bgColorView.backgroundColor = UIColor(red: 250/255, green: 182/255, blue: 17/255, alpha: 1)
cell.contentView.backgroundColor = UIColor(red: 250/255, green: 182/255, blue: 17/255, alpha: 1)
cell.selectedBackgroundView = bgColorView
cell.accessoryType = .Checkmark
cell.highlighted = false
cell.selected = true
// cell.accessoryType = .Checkmark
self.tableView.selectRowAtIndexPath(indexPath, animated: true, scrollPosition: UITableViewScrollPosition.None)
self.tableView(self.tableView, didSelectRowAtIndexPath: indexPath)
}
var job: Jobs!
job = jobs[UInt(indexPath.row)] as! Jobs
cell.reports2JobTitle.text = job.jobTitle
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.tableView.allowsMultipleSelection = true
if let cell:myTableViewCell = tableView.cellForRowAtIndexPath(indexPath) as? myTableViewCell {
let bgColorView = UIView()
bgColorView.backgroundColor = UIColor(red: 250/255, green: 182/255, blue: 17/255, alpha: 1)
cell.contentView.backgroundColor = UIColor(red: 250/255, green: 182/255, blue: 17/255, alpha: 1)
cell.selectedBackgroundView = bgColorView
cell.accessoryType = .Checkmark
cell.highlighted = false
self.tableView.selectRowAtIndexPath(indexPath, animated: true, scrollPosition: UITableViewScrollPosition.Bottom)
}
}
My issue is that only the rows that have been dequeued are added to my table's data model when I segue to the next viewcontroller. In order to add all the rows to my table's data model I have to manually scroll through the whole table. How can I change this so all the selected rows are added to my table's data model without having to scroll through the whole table?
What I cannot understand is that after all my rows are selected I then loop through my indexPaths as follows but not all of the indexPaths are added unless I first scroll through the entire table.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "reportsDisplay") {
let controller = segue.destinationViewController as! ReportsDisplayViewController
var selectedJob : Jobs!
if let indexPaths = tableView.indexPathsForSelectedRows {
for i in 0 ..< indexPaths.count {
let thisPath = indexPaths[i]
selectedJob = jobs[UInt(thisPath.row)] as! Jobs
let jobTitle = selectedJob.jobTitle
let id = selectedJob.identifier
jobsToReport.append(jobTitle)
jobsID.append(id)
}
}
controller.reportedJobs = jobsToReport
controller.idOfJobs = jobsID
}
}
For Swift 3 and answering your question literally, regardless of your code.
func selectAllRows() {
for section in 0..<tableView.numberOfSections {
for row in 0..<tableView.numberOfRows(inSection: section) {
tableView.selectRow(at: IndexPath(row: row, section: section), animated: false, scrollPosition: .none)
}
}
}
If you want to inform the tableview delegate, use this method:
func selectAllRows() {
for section in 0..<tableView.numberOfSections {
for row in 0..<tableView.numberOfRows(inSection: section) {
let indexPath = IndexPath(row: row, section: section)
_ = tableView.delegate?.tableView?(tableView, willSelectRowAt: indexPath)
tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
tableView.delegate?.tableView?(tableView, didSelectRowAt: indexPath)
}
}
}
At the time allJobsSelected becomes true, you need to call the UITableView method selectRowAtIndexPath(_:animated:scrollPosition:) for each row of your table. In my case, I attached this functionality to the right bar button item which I named Select All. Calling this from cellForRowAtIndexPath is surely not the right place.
#IBAction func doSelectAll(sender: UIBarButtonItem) {
let totalRows = tableView.numberOfRowsInSection(0)
for row in 0..<totalRows {
tableView.selectRowAtIndexPath(NSIndexPath(forRow: row, inSection: 0), animated: false, scrollPosition: UITableViewScrollPosition.None)
}
}
Functional solution (Swift 5.1)
extension UITableViewDataSource where Self: UITableView {
/**
* Returns all IndexPath's in a table
* ## Examples:
* table.indexPaths.forEach {
* selectRow(at: $0, animated: true, scrollPosition: .none) // selects all cells
* }
*/
public var indexPaths: [IndexPath] {
return (0..<self.numberOfSections).indices.map { (sectionIndex: Int) -> [IndexPath] in
(0..<self.numberOfRows(inSection: sectionIndex)).indices.compactMap { (rowIndex: Int) -> IndexPath? in
IndexPath(row: rowIndex, section: sectionIndex)
}
}.flatMap { $0 }
}
}
Solution for Swift 5.5
This method can be logically made an extension of UITableView and must be called from the main thread:
extension UITableView {
// Must be called from the main thread
func selectAllRows() {
let totalRows = self.numberOfRows(inSection: 0)
for row in 0..<totalRows {
self.selectRow(at: IndexPath(row: row, section: 0), animated: true, scrollPosition: .none)
}
}
}
Note: this code is only for the only section