Swift: UIPanGesture on tableview cell not working - swift

Heyy,
Hello I want to implement a gesture in a tableview cell but it does not work here is my code:
var panGesture: UIPanGestureRecognizer?
override func awakeFromNib() {
super.awakeFromNib()
panGesture = UIPanGestureRecognizer(target: self, action: #selector(detectPan(recognizer:)))
panGesture?.delaysTouchesBegan = false
panGesture?.delaysTouchesEnded = false
separatorView.addGestureRecognizer(panGesture!)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
#objc func detectPan(recognizer: UIPanGestureRecognizer) {
let translation = recognizer.translation(in: self.vc?.view)
switch recognizer.state {
case .began:
self.startingConstant = self.constantCenter.constant
case .changed:
self.constantCenter.constant = self.startingConstant + translation.x
case .ended:
if translation.x > 0 {
constantCenter.isActive = false
constanteGauche.isActive = false
constanteDroite.isActive = true
}else{
constantCenter.isActive = false
constanteGauche.isActive = true
constanteDroite.isActive = false
print("ok")
}
UIView.animate(withDuration: 0.2) {
self.vc?.view.layoutIfNeeded()
}
constantCenter.constant = separatorView.center.x - (self.vc?.view.center.x)!
constantCenter.isActive = true
constanteGauche.isActive = true
constanteDroite.isActive = true
default:
break
}
}
Do I have to fix something in my function tableview:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//On lien le TableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? FeedCell
cell?.selectionStyle = .none
cell?.vc = self
cell?.delegate = self
cell?.view(post: FeedPostController.posts[indexPath.row], user: FeedPostController.users[indexPath.row]); //On passe l'objet a l'index i a la fonction view du TableViewCell pour l'affichage
return cell!;
}
I tried a lot of possibilities but nothing works, the function of the gesture I need it in the uitableviewcell because I use constraints that are in the cell
UPDATE SOLUTION
override func awakeFromNib() {
super.awakeFromNib()
separatorView.isUserInteractionEnabled = true //THIS LINE ITS VERY IMPORTANT !!!!!!!!
panGesture = UIPanGestureRecognizer(target: self, action: #selector(detectPan(recognizer:)))
panGesture?.delaysTouchesBegan = false
panGesture?.delaysTouchesEnded = false
separatorView.addGestureRecognizer(panGesture!)
}

Here is the code example. 100% works. Hope, it'll help.
import UIKit
private let cellID = "cellID"
class ViewController: UIViewController {
// Setup Table View
private lazy var tableView: UITableView = {
let rect: CGRect = view.bounds
let tableView = UITableView(frame: rect, style: .grouped)
tableView.separatorStyle = .singleLine
tableView.backgroundColor = .white
tableView.dataSource = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellID)
// If you need to PAN the tableView, uncomment this line
// tableView.addGestureRecognizer(self.panGesture)
return tableView
}()
// Setup panGesture
private lazy var panGesture: UIPanGestureRecognizer = {
let pan = UIPanGestureRecognizer(target: self, action: #selector(didPan(sender:)))
// Set delegate
pan.delegate = self
return pan
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(tableView)
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath)
cell.backgroundColor = .red
// Add panGesture to first cell for example
if indexPath.section == 0, indexPath.row == 0 {
cell.addGestureRecognizer(self.panGesture)
cell.backgroundColor = .lightGray
cell.textLabel?.text = "You can drag a table for this cell"
}
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
}
extension ViewController: UIGestureRecognizerDelegate {
#objc fileprivate func didPan(sender: UIPanGestureRecognizer) {
let translation = sender.translation(in: view)
switch sender.state {
case .began:
print("Began")
case .changed:
print("Canged \(translation.y)")
// This is just example to show you how that works. Dragging tableView.
tableView.frame.origin.y = translation.y
case .ended:
print("Ended")
default:
break
}
}
}
Link for short video how it works on device: https://www.dropbox.com/s/1lorvamynbwvyv7/TJCQ1216.MP4?dl=0
If you have any questions, just ask )

Related

Getting id by clicking on tableView

By clicking on the red area I get a comment id. But I also want to get the id if I click on the blue button. How can I do that?
Right now I use this to detect a tap on a row. But tapping on button should run some other code.
extension FirstTabSecondViewComment: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
FirstTabSecondViewComment.subComment = table[indexPath.row].commentId ?? ""
print(FirstTabSecondViewComment.subComment)
self.performSegue(withIdentifier: "CommentDetail", sender: Any?.self)
}
}
After you have register your custom cell declare it in cellForRowAt and add target in button cell:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! MyCell // your custom cell
// add target in buoon cell
cell.YourButtonCell.addTarget(self, action: #selector(submit(_:)), for: .touchUpInside)
return cell
}
after that add submit func:
#objc fileprivate func submit(_ sender: UIButton) {
var superview = sender.superview
while let view = superview, !(view is UITableViewCell) {
superview = view.superview
}
guard let cell = superview as? UITableViewCell else {
print("button is not contained in a table view cell")
return
}
guard let indexPath = tableView.indexPath(for: cell) else {
print("failed to get index path for cell containing button")
return
}
// We've got the index path for the cell that contains the button, now do something with it.
print("button is in index \(indexPath.row)")
}
This is a full code example, copy and paste in a new project and run:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let tableView = UITableView()
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
tableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
tableView.delegate = self
tableView.dataSource = self
tableView.register(MyCell.self, forCellReuseIdentifier: cellId)
}
#objc fileprivate func submit(_ sender: UIButton) {
var superview = sender.superview
while let view = superview, !(view is UITableViewCell) {
superview = view.superview
}
guard let cell = superview as? UITableViewCell else {
print("button is not contained in a table view cell")
return
}
guard let indexPath = tableView.indexPath(for: cell) else {
print("failed to get index path for cell containing button")
return
}
// We've got the index path for the cell that contains the button, now do something with it.
print("button is in index \(indexPath.row)")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! MyCell
// add target in buoon cell
cell.cancelButton.addTarget(self, action: #selector(submit(_:)), for: .touchUpInside)
return cell
}
}
class MyCell: UITableViewCell {
let cancelButton: UIButton = {
let b = UIButton(type: .system)
b.backgroundColor = .white
b.setTitle("get Index", for: .normal)
b.layer.cornerRadius = 10
b.clipsToBounds = true
b.titleLabel?.font = .systemFont(ofSize: 16, weight: .semibold)
b.tintColor = .black
b.translatesAutoresizingMaskIntoConstraints = false
return b
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.backgroundColor = .darkGray
contentView.addSubview(cancelButton)
cancelButton.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
cancelButton.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
cancelButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
cancelButton.widthAnchor.constraint(equalToConstant: 300).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

How to make changes to UITableViewCell from navigationBar?

How can I make layout changes to a UITableViewCell from the navigation bar of a UITableViewController? It feels like I've tried everything, but to no avail.
This is the controller:
class TableViewController: UITableViewController {
let tableViewCellID = "tableViewCellID"
//MARK: Loading view
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(TableViewCell.self, forCellReuseIdentifier: tableViewCellID)
navigationBar()
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let tableViewCell = tableView.dequeueReusableCell(withIdentifier: tableViewCellID) as? TableViewCell else { return UITableViewCell() }
tableViewCell.firstLayout()
return tableViewCell
}
func navigationBar() {
let emptyButton = UIBarButtonItem(image: UIImage(named: "icon"), style: .done, target: self, action: #selector(buttonTapped))
navigationItem.rightBarButtonItems = [emptyButton]
navigationItem.largeTitleDisplayMode = .never
}
#objc func buttonTapped() {
let tableViewCell = TableViewCell()
tableViewCell.secondLayout()
}
}
This is the cell:
class TableViewCell: UITableViewCell {
let firstColorView: UIView = {
let coverView = UIView()
coverView.translatesAutoresizingMaskIntoConstraints = false
coverView.backgroundColor = .red
return coverView
}()
let secondColorView: UIView = {
let cameraViewClosure = UIView()
cameraViewClosure.translatesAutoresizingMaskIntoConstraints = false
cameraViewClosure.backgroundColor = .yellow
return cameraViewClosure
}()
func firstLayout() {
contentView.addSubview(firstColorView)
NSLayoutConstraint.activate([
firstColorView.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 1),
firstColorView.heightAnchor.constraint(equalTo: contentView.heightAnchor, multiplier: 1),
])
}
func secondLayout() {
print("This prints, but no changes are made to the cell")
contentView.addSubview(secondColorView)
NSLayoutConstraint.activate([
secondColorView.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 0.5),
secondColorView.heightAnchor.constraint(equalTo: contentView.heightAnchor, multiplier: 1),
secondColorView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
])
}
}
I have of course tried all these:
layoutIfNeeded()
setNeedsLayout()
setNeedsDisplay()
layoutSubviews()
setNeedsUpdateConstraints()
updateConstraints()
updateConstraintsIfNeeded()
... and I have tried them in all kinds combinations, but I still don't get the results I want.
Let me know if you need anymore code or information, please and thank you in advance for any help!
Try the following modifications.
#objc func buttonTapped() {
let cell = tableView.visibleCells.first as? TableViewCell
cell?.secondLayout()
}

Adding two UITableViews in one UIVIewController programmatically and want to change the View of Controller with UISegmentedControl

I want to change the View of my ViewController based on 2 tableVIews with segmentedControl. I have reached it with programmatic approach. I created two TableViews and One SegmentedControl. But When I change the segmentedControl it stays on the same Index but changing the View. I have to tap twice on each Segment to reach it. Why it is happening?
Here is my code:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
configureFirstTableView()
}
var firstTableView = UITableView()
var secondTableView = UITableView()
func configureFirstTableView() {
firstTableView.frame = self.view.frame
firstTableView.delegate = self
firstTableView.dataSource = self
firstTableView.register(UITableViewCell.self, forCellReuseIdentifier: "FirstCell")
view.addSubview(firstTableView)
}
func configureSecondTableView() {
secondTableView.frame = self.view.frame
secondTableView.delegate = self
secondTableView.dataSource = self
secondTableView.register(UITableViewCell.self, forCellReuseIdentifier: "SecondCell")
view.addSubview(secondTableView)
}
func configureSegmentedControl() -> UISegmentedControl {
let segmentedControl = UISegmentedControl(frame: CGRect(x: 10, y: 5, width: view.frame.width - 10, height: 30))
segmentedControl.insertSegment(withTitle: "First", at: 0, animated: false)
segmentedControl.insertSegment(withTitle: "Second", at: 1, animated: false)
segmentedControl.selectedSegmentIndex = 0
segmentedControl.addTarget(self, action: #selector(changeSegmentedControlValue(_:)), for: .valueChanged)
return segmentedControl
}
#objc func changeSegmentedControlValue(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
print("1")
configureFirstTableView()
case 1:
print("2")
configureSecondTableView()
default:
break
}
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var count: Int?
if tableView == firstTableView {
count = 3
return count!
} else if tableView == secondTableView {
count = 4
return count!
}
return count!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == firstTableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "FirstCell", for: indexPath)
cell.textLabel?.text = "First"
return cell
} else if tableView == secondTableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "SecondCell", for: indexPath)
cell.textLabel?.text = "Second"
return cell
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let v = UIView()
v.backgroundColor = .white
v.addSubview(configureSegmentedControl())
return v
}
}

Custom UISearchBar using TextField

I need to make custom UISearchBar using UITextField.
I try to make it myself, but nothing works. Please, write a code for UITextField, which will work like UISearchBar
It's code where I use UISearchBar, but I need to change to UITextField
class FoodViewController: UIViewController {
override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent }
let tableView = UITableView()
var foods = [FoodModel]()
var searchedFoods = [FoodModel]()
var searching = false
override func viewDidLoad() {
super.viewDidLoad()
fetchFoods()
self.modalPresentationCapturesStatusBarAppearance = true
self.view.backgroundColor = UIColor.white
let controller = UIViewController()
self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
self.view.addSubview(self.tableView)
tableView.delegate = self
tableView.dataSource = self
let searchBar = UISearchBar(frame: CGRect(x: 0, y: 5, width: 350, height: 40))
searchBar.searchBarStyle = .minimal
searchBar.barStyle = .black
searchBar.delegate = self
self.view.addSubview(searchBar)
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
self.updateLayout(with: self.view.frame.size)
}
func updateLayout(with size: CGSize) {
self.tableView.frame = CGRect.init(x: 0, y: 45, width: size.width, height: 400)
}
func fetchFoods() {
Database.database().reference().child("food").observe(.childAdded) { (snapshot) in
if let dict = snapshot.value as? [String: AnyObject] {
let newTitle = dict["title"] as! String
let exCell = FoodModel(title: newTitle)
self.foods.append(exCell)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
}
extension FoodViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
if searching {
let food = searchedFoods[indexPath.item]
cell.textLabel?.text = food.title
} else {
let food = foods[indexPath.item]
cell.textLabel?.text = food.title
}
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searching {
return searchedFoods.count
} else {
return foods.count
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
var titleOfFood = String()
if searching == true {
titleOfFood = searchedFoods[indexPath.row].title
print(titleOfFood)
} else {
titleOfFood = foods[indexPath.row].title
print(titleOfFood)
}
let alertController = UIAlertController(title: "Hello", message: "Message", preferredStyle: .alert)
let cancel = UIAlertAction(title: "Cancel", style: .default)
let save = UIAlertAction(title: "Save", style: .cancel) { (action) in
self.dismiss(animated: true, completion: nil)
}
alertController.addTextField { (textField) in
textField.keyboardType = .numberPad
textField.borderStyle = .roundedRect
textField.layer.borderColor = UIColor.clear.cgColor
textField.addConstraint(textField.heightAnchor.constraint(equalToConstant: 50))
textField.font = UIFont(name: "Roboto-Medium", size: 30)
// textField.cornerRadius = 8
}
alertController.addAction(save)
alertController.addAction(cancel)
self.present(alertController, animated: true)
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
}
}
extension FoodViewController: UITableViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView == self.tableView {
SPStorkController.scrollViewDidScroll(scrollView)
}
}
}
extension FoodViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
searchedFoods = foods.filter({ $0.title.lowercased().prefix(searchText.count) == searchText.lowercased() })
searching = true
tableView.isHidden = false
tableView.reloadData()
let transitionDelegate = SPStorkTransitioningDelegate()
transitionDelegate.customHeight = 620
transitionDelegate.showIndicator = false
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searching = false
searchBar.text = ""
tableView.reloadData()
}
}
Basically (if i'm understanding you correctly) after you add your UITextField to the view, all you need to have is some method to trigger whenever the value of the UITextField changes.
Something like this:
textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
And then:
func textFieldDidChange(_ textField: UITextField) {
let searchText = textField.text!
searchedFoods = foods.filter({ $0.title.lowercased().prefix(searchText.count) == searchText.lowercased() })
searching = true
tableView.isHidden = false
tableView.reloadData()
let transitionDelegate = SPStorkTransitioningDelegate()
transitionDelegate.customHeight = 620
transitionDelegate.showIndicator = false
}

How do I configure the menu options in slide menu in Swift 3?

I have successfully setup a slide menu, but am unable to display the menu options. The menu is empty.
I have searched high and low. I'm unable to find an answer. I have been looking at my code for days and (of course) it looks right to me.
class LeftTableViewController: UITableViewController {
#IBOutlet var menuTableView: UITableView!
let menuItems = ["First", "Second", "Third", "Fourth"]
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.setNavigationBarHidden(true, animated: true)
if (tableView(tableView: self.tableView, numberOfRowsInSection: 1) == 0 ) {
let emptyStateLabel = UILabel(frame: tableView.frame)
emptyStateLabel.text = "At this time, nothing is here."
tableView.backgroundView = emptyStateLabel
} else {
tableView.backgroundView = nil
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Added a background view to the table view
let backgroundImage = UIImage(named: "growlTaps.png")
let imageView = UIImageView(image: backgroundImage)
self.tableView.backgroundView = imageView
// Remove lines where there aren't cells
tableView.tableFooterView = UIView(frame: CGRect.zero)
// Center and scale background image
imageView.contentMode = .scaleAspectFit
// Center and scale background image
imageView.contentMode = .scaleAspectFill
// Set the background color
tableView.backgroundColor = .lightGray
}
// MARK: - Table view data source
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return menuItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "LeftTableViewControllerCellIdentifier")!
cell.textLabel?.text = menuItems[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
switch indexPath.row {
case 0:
self.sideMenuViewController!.setContentViewController(contentViewController: UINavigationController.init(rootViewController: self.storyboard!.instantiateViewController(withIdentifier: "ViewController")), animated: true)
self.sideMenuViewController!.hideMenuViewController()
break
case 1:
self.sideMenuViewController!.setContentViewController(contentViewController:UINavigationController.init(rootViewController: self.storyboard!.instantiateViewController(withIdentifier: "AboutViewController")), animated: true)
self.sideMenuViewController!.hideMenuViewController()
break
case 2:
self.sideMenuViewController!.setContentViewController(contentViewController:UINavigationController.init(rootViewController: self.storyboard!.instantiateViewController(withIdentifier: "ContactVC")), animated: true)
self.sideMenuViewController!.hideMenuViewController()
break
default:
break
}
}
}
EDIT: Outlets for the tableview.