swift 3 table view with slide out menu - swift

I got problem with making table view on the same view with slide menu, could you help me how to do that, I created view controller and embeded navigation controller, now I just want add table vie behind the slide menu and show table view with two section and show data with one custom cell.

#Egle Matutyte, I am supposing that you have done all work except SlideBar.
I am providing code for SlideBar. Just add and try.
First Add the SideBar class i.e. below without any change
import UIKit
#objc protocol SideBarDelegate{
func sideBarDidSelectButtonAtIndex(_ index:Int)
#objc optional func sideBarWillClose()
#objc optional func sideBarWillOpen()
}
class SideBar: NSObject, SideBarTableViewControllerDelegate {
let barWidth:CGFloat = 150.0
let sideBarTableViewTopInset:CGFloat = 64.0
let sideBarContainerView:UIView = UIView()
let sideBarTableViewController:SideBarTableViewController = SideBarTableViewController()
var originView:UIView = UIView()
var animator:UIDynamicAnimator!
var delegate:SideBarDelegate?
var isSideBarOpen:Bool = false
override init() {
super.init()
}
init(sourceView:UIView, menuItems:Array<String>){
super.init()
originView = sourceView
sideBarTableViewController.tableData = menuItems
setupSideBar()
animator = UIDynamicAnimator(referenceView: originView)
let showGestureRecognizer:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(SideBar.handleSwipe(_:)))
showGestureRecognizer.direction = UISwipeGestureRecognizerDirection.right
originView.addGestureRecognizer(showGestureRecognizer)
let hideGestureRecognizer:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(SideBar.handleSwipe(_:)))
hideGestureRecognizer.direction = UISwipeGestureRecognizerDirection.left
originView.addGestureRecognizer(hideGestureRecognizer)
}
func setupSideBar(){
//sideBarContainerView.frame = CGRect(x: -barWidth - 1, y: originView.frame.origin.y, width: barWidth, height: originView.frame.size.height)
sideBarContainerView.frame = CGRect(x: -barWidth - 1, y: sideBarTableViewTopInset, width: barWidth, height: originView.frame.size.height)
sideBarContainerView.backgroundColor = UIColor.clear
sideBarContainerView.clipsToBounds = false
originView.addSubview(sideBarContainerView)
let blurView:UIVisualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.light))
blurView.frame = sideBarContainerView.bounds
sideBarContainerView.addSubview(blurView)
sideBarTableViewController.delegate = self
sideBarTableViewController.tableView.frame = sideBarContainerView.bounds
sideBarTableViewController.tableView.clipsToBounds = false
sideBarTableViewController.tableView.separatorStyle = UITableViewCellSeparatorStyle.none
sideBarTableViewController.tableView.backgroundColor = UIColor.clear
sideBarTableViewController.tableView.scrollsToTop = false
//sideBarTableViewController.tableView.contentInset = UIEdgeInsetsMake(sideBarTableViewTopInset, 0, 0, 0)
sideBarTableViewController.tableView.contentInset = UIEdgeInsetsMake(1, 0, 0, 0)
sideBarTableViewController.tableView.reloadData()
sideBarContainerView.addSubview(sideBarTableViewController.tableView)
}
func handleSwipe(_ recognizer:UISwipeGestureRecognizer){
if recognizer.direction == UISwipeGestureRecognizerDirection.left{
showSideBar(false)
delegate?.sideBarWillClose?()
}else{
showSideBar(true)
delegate?.sideBarWillOpen?()
}
}
func showSideBar(_ shouldOpen:Bool){
animator.removeAllBehaviors()
isSideBarOpen = shouldOpen
let gravityX:CGFloat = (shouldOpen) ? 0.5 : -0.5
let magnitude:CGFloat = (shouldOpen) ? 20 : -20
let boundaryX:CGFloat = (shouldOpen) ? barWidth : -barWidth - 1
let gravityBehavior:UIGravityBehavior = UIGravityBehavior(items: [sideBarContainerView])
gravityBehavior.gravityDirection = CGVector(dx: gravityX, dy: 0)
animator.addBehavior(gravityBehavior)
let collisionBehavior:UICollisionBehavior = UICollisionBehavior(items: [sideBarContainerView])
collisionBehavior.addBoundary(withIdentifier: "sideBarBoundary" as NSCopying, from: CGPoint(x: boundaryX, y: 20), to: CGPoint(x: boundaryX, y: originView.frame.size.height))
animator.addBehavior(collisionBehavior)
let pushBehavior:UIPushBehavior = UIPushBehavior(items: [sideBarContainerView], mode: UIPushBehaviorMode.instantaneous)
pushBehavior.magnitude = magnitude
animator.addBehavior(pushBehavior)
let sideBarBehavior:UIDynamicItemBehavior = UIDynamicItemBehavior(items: [sideBarContainerView])
sideBarBehavior.elasticity = 0.3
animator.addBehavior(sideBarBehavior)
}
func sideBarControlDidSelectRow(_ indexPath: IndexPath) {
delegate?.sideBarDidSelectButtonAtIndex(indexPath.row)
showSideBar(false)
}
}
After this, add a new swift class
SideBarTableViewController
which inherit UITableViewController
import UIKit
protocol SideBarTableViewControllerDelegate{
func sideBarControlDidSelectRow(_ indexPath:IndexPath)
}
class SideBarTableViewController: UITableViewController {
var delegate:SideBarTableViewControllerDelegate?
var tableData:Array<String> = []
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell:UITableViewCell? = tableView.dequeueReusableCell(withIdentifier: "Cell")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
cell!.backgroundColor = UIColor.clear
cell!.textLabel?.textColor = UIColor.darkText
let selectedView:UIView = UIView(frame: CGRect(x: 0, y: 0, width: cell!.frame.size.width, height: cell!.frame.size.height))
selectedView.backgroundColor = UIColor.black.withAlphaComponent(0.3)
cell!.selectedBackgroundView = selectedView
}
cell!.textLabel?.text = tableData[indexPath.row]
return cell!
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 45
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
delegate?.sideBarControlDidSelectRow(indexPath)
}
}
Now paste the code below in your TableViewController or the page on which you want to add SlideBar.
let the name of your page is Dashboard, add the delegate as below
class Dashboard: UIViewController, SideBarDelegate
{
//declare sidebar
var sideBar:SideBar = SideBar()
override func viewWillAppear(_ animated: Bool)
{
//Initialise the content of SlideBar Row
sideBar = SideBar(sourceView: self.view, menuItems: ["Home", "Dashboard"])
sideBar.delegate = self
}
func sideBarControlDidSelectRow(_ indexPath: IndexPath) {
print("Selected from SlideBar")
}
func sideBarDidSelectButtonAtIndex(_ index: Int)
{
//
}
//Add a button(Optional)in ViewDidLoad()
override func viewDidLoad()
{
super.viewDidLoad()
let btn_Hamburger = UIButton(frame: CGRect(x: 10, y: 70, width: 100, height: 25))
btn_Hamburger.addTarget(self, action: #selector(btn_hamburger(sender:)), for: .touchUpInside)
//add Image on Hamburger button
btn_Hamburger.setImage(#imageLiteral(resourceName: "img_hemberger"), for: .normal)
view.addSubview(btn_Hamburger)
}
//To in and out SideBar menu
var flag:Bool = true
func btn_hamburger(sender: UIButton!)
{
if flag == true {
sideBar.showSideBar(true)
flag = false
}
else{
sideBar.showSideBar(false)
flag = true
}
}
}

Related

Value of type 'SSBadgeButton' has no member 'animationZoom'

I have following productviewcontroller which says "Value of type 'SSBadgeButton' has no member 'animationZoom'" -
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]()
if selectedIndexPaths.contains(indexPath) {
if let index = selectedIndexPaths.firstIndex(of: indexPath) {
selectedIndexPaths.remove(at: index)
removeProductFromCart(indexPath: indexPath)
}
} else {
selectedIndexPaths.append(indexPath)
addProductToCart(indexPath: indexPath)
}
addProductToCart(indexPath: indexPath)
//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) ***//Error - Value of type 'SSBadgeButton' has no member 'animationZoom'***
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()
}
}
}
}
}
}
This is my code for "SSBadgeButton" -
import UIKit
class SSBadgeButton: UIButton {
var badgeLabel = UILabel()
var badge: String? {
didSet {
addBadgeToButon(badge: badge)
}
}
public var badgeBackgroundColor = UIColor.red {
didSet {
badgeLabel.backgroundColor = badgeBackgroundColor
}
}
public var badgeTextColor = UIColor.white {
didSet {
badgeLabel.textColor = badgeTextColor
}
}
public var badgeFont = UIFont.systemFont(ofSize: 12.0) {
didSet {
badgeLabel.font = badgeFont
}
}
public var badgeEdgeInsets: UIEdgeInsets? {
didSet {
addBadgeToButon(badge: badge)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
addBadgeToButon(badge: nil)
}
func addBadgeToButon(badge: String?) {
badgeLabel.text = badge
badgeLabel.textColor = badgeTextColor
badgeLabel.backgroundColor = badgeBackgroundColor
badgeLabel.font = badgeFont
badgeLabel.sizeToFit()
badgeLabel.textAlignment = .center
let badgeSize = badgeLabel.frame.size
let height = max(18, Double(badgeSize.height) + 5.0)
let width = max(height, Double(badgeSize.width) + 10.0)
var vertical: Double?, horizontal: Double?
if let badgeInset = self.badgeEdgeInsets {
vertical = Double(badgeInset.top) - Double(badgeInset.bottom)
horizontal = Double(badgeInset.left) - Double(badgeInset.right)
let x = (Double(bounds.size.width) - 10 + horizontal!)
let y = -(Double(badgeSize.height) / 2) - 10 + vertical!
badgeLabel.frame = CGRect(x: x, y: y, width: width, height: height)
} else {
let x = self.frame.width - CGFloat((width / 2.0))
let y = CGFloat(-(height / 2.0))
badgeLabel.frame = CGRect(x: x, y: y, width: CGFloat(width), height: CGFloat(height))
}
badgeLabel.layer.cornerRadius = badgeLabel.frame.height/2
badgeLabel.layer.masksToBounds = true
addSubview(badgeLabel)
badgeLabel.isHidden = badge != nil ? false : true
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.addBadgeToButon(badge: nil)
fatalError("init(coder:) has not been implemented")
}
}
Earlier, it used to work fine. It used to zoom the animation Now, I don't know why it does not work fine ? please help me with this. The code also seems okay. still, it does not work fine.

Style content in a TableView without causing the scrolling to lag

I have a TableView, with about 15 to 20 displayed cells. The cell has a Label with the following class:
import Foundation
import UIKit
class RoundedLabel: UILabel {
var inset: CGFloat = 16
override func drawText(in rect: CGRect) {
let insets = UIEdgeInsets(top: 2, left: 2, bottom: 2, right: 2)
super.drawText(in: rect.inset(by: insets))
}
override func layoutSubviews() {
super.layoutSubviews()
updateCornerRadius()
}
override var intrinsicContentSize: CGSize {
let size = super.intrinsicContentSize
return CGSize(
width: size.width + inset,
height: size.height
)
}
#IBInspectable var rounded: Bool = false {
didSet {
updateCornerRadius()
}
}
func updateCornerRadius() {
layer.cornerRadius = rounded ? frame.size.height / 2 : 0
layer.masksToBounds = true
}
}
In my VC I have the following (I have to TableViews in one VC):
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == tableViewMainLatest {
let cell = tableViewMainLatest.dequeueReusableCell(withIdentifier: "cellMainLatest", for: indexPath) as! MainLatestTableViewCell
let postDate = posts[indexPath.row].postDate ?? 0
let formattedPostDate = Date(timeIntervalSince1970: postDate)
let timeAgo = formattedPostDate.timeAgo(numericDates: false)
let postCity = posts[indexPath.row].postFromCity ?? "?"
let postCountry = posts[indexPath.row].postFromCountry ?? "?"
let postComments = posts[indexPath.row].comments ?? 0
let maxPostComments: String?
// Only show the number if comment amount is less than 100
if postComments > 99 {
maxPostComments = "99+"
} else {
maxPostComments = String(postComments)
}
cell.labelPostDate.text = timeAgo
cell.labelPostFrom.text = postCity + ", " + postCountry
cell.labelAmountComments.text = maxPostComments
return cell
} else if tableView == tableViewCategories {
let cell = tableViewCategories.dequeueReusableCell(withIdentifier: "cellMainCategories", for: indexPath) as! MainApplicationCategoriesTableViewCell
cell.labelCategories.text = pseudo[indexPath.row] as? String
cell.alpha = 0.55
UIView.animate(withDuration: 0.5, animations: {
cell.alpha = 1
})
return cell
}
return UITableViewCell()
}
My CustomCell:
class MainApplicationCategoriesTableViewCell: UITableViewCell {
// Storyboard
#IBOutlet weak var labelCategories: UILabel! {
didSet {
labelCategories.layer.borderWidth = 1
labelCategories.layer.borderColor = UIColor(red:0.88, green:0.88, blue:0.88, alpha:1.0).cgColor
}
}
override func awakeFromNib() {
super.awakeFromNib()
self.selectionStyle = .none
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
When I use this piece of code:
// Storyboard
#IBOutlet weak var labelCategories: UILabel! {
didSet {
labelCategories.layer.borderWidth = 1
labelCategories.layer.borderColor = UIColor(red:0.88, green:0.88, blue:0.88, alpha:1.0).cgColor
}
}
The scrolling of the TableView is lagging. Where do I have to apply the borderWidth / borderColor, to still have a good user experience without lagging?

how to add swipe gesture or swipe function between two overlap container view using segmented control, like instagram profile?

I am new to iOS and trying to build an app to learn more. I'm stuck at the last stage of my application. I want to be able to swipe between two container views using segmented control. I want to add two overlapping container views (container views with an embed segue with child controller) of the same size on half screen in single controller like instagram profile. I want to add a tableview to both child controllers. When I run the app the data of the first child view should be seen but when I swipe left, the second child controller should be seen with same size and in the same position. I want this to be like an instagram profile.
Currently, when I swipe left the second child controller opens in full screen and hides everything else on that screen. I have tried various tutorials, but to no avail.
Can you help me to do this?
Thank You!
This is my view controller's code
// CODE //
{
//
// ViewController.swift
// BeautyParlor
//
// Created by Mohammad Affan Siddiqui on 20/11/2019.
// Copyright © 2019 Mohammad Affan Siddiqui. All rights reserved.
//
import UIKit
//import PinterestLayout
class ViewController: UIViewController {
#IBOutlet weak var SegmentedControl: UISegmentedControl!
#IBOutlet weak var thirdView: UIView!
#IBOutlet weak var collectionViewOutletPortfolio: UICollectionView!
#IBOutlet weak var collectionViewOutletAbout: UICollectionView!
#IBOutlet weak var secondView: UIView!
#IBOutlet weak var firstView: UIView!
#IBOutlet weak var collectionViewOutletStatic: UICollectionView!
// FOR STATIC DATA
var arrimgbackground = [UIImage]()
var arrimglogo = [UIImage]()
var arrimglocation = [UIImage]()
var arrimginsta = [UIImage]()
var arrlblname = ["ABC Saloon"]
var arrlblrating = ["Rating 4.5/5"]
var arrlbllocation = ["ABC,Street,karachi"]
var arrlblinsta = ["qqq"]
var arrlblservicename = ["We are serving you"]
var arrlblrs = ["Rs:200"]
// FOR ABOUT DATA
var arrlbldescription = ["Before you can begin to determine what the will grow. The whole process is an organic one—a natural progression from a seed to a full-blown "]
// FOR PORTFOLIO DATA
var arrimgportfolio = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
//
//
//
//
// setupSegmentedContrl()
setupHorizontalBar()
// let swipright = UISwipeGestureRecognizer(target: self, action: #selector(self.swipGesture))
// swipright.direction = UISwipeGestureRecognizer.Direction.right
// self.thirdView?.addGestureRecognizer(swipright)
// let rightSwipe = UISwipeGestureRecognizer(target: SegmentCotroller, action: Selector("swiped:"))
// rightSwipe.direction = .Right
// self.SegmentCotroller.addGestureRecognizer(rightSwipe)
//
let rightSwipe = UISwipeGestureRecognizer(target: self, action: Selector(("swiped:")))
rightSwipe.direction = .right
self.secondView?.addGestureRecognizer(rightSwipe)
// let swipright = UISwipeGestureRecognizer(target: self, action: #selector(self.swipGesture))
// swipright.direction = UISwipeGestureRecognizer.Direction.right
// self.secondView?.addGestureRecognizer(swipright)
//
//
// let layout = PinterestLayout()
// collectionViewOutletPortfolio.collectionViewLayout = layout
//
// layout.delegate = self
// layout.cellPadding = 5
// layout.numberOfColumns = 2
//
//
//
// if let layout = collectionViewOutletPortfolio?.collectionViewLayout as? PinterestLayout {
// layout.delegate = self as! PinterestLayoutDelegate
// }
//
thirdView?.isHidden = true
arrimgbackground = [#imageLiteral(resourceName: "d.png")]
arrimglogo = [#imageLiteral(resourceName: "roundimage.png")]
arrimglocation = [#imageLiteral(resourceName: "location.jpeg")]
arrimginsta = [#imageLiteral(resourceName: "insta.png")]
arrimgportfolio = [#imageLiteral(resourceName: "c.png"), #imageLiteral(resourceName: "d.png"), #imageLiteral(resourceName: "down.png"), #imageLiteral(resourceName: "down.png"), #imageLiteral(resourceName: "c.png"), #imageLiteral(resourceName: "c.png"), #imageLiteral(resourceName: "c.png"), #imageLiteral(resourceName: "c.png"), #imageLiteral(resourceName: "d.png"), #imageLiteral(resourceName: "d.png"), #imageLiteral(resourceName: "d.png"), #imageLiteral(resourceName: "d.png"), #imageLiteral(resourceName: "down.png"), #imageLiteral(resourceName: "down.png"), #imageLiteral(resourceName: "down.png")]
// setupSegmentedControl().topAnchor.constraintEqualToAnchor(topLayoutGuide)
}
private func setupHorizontalBar(){
}
private func setupSegmentedControl(){
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// SegmentedControl
}
// #objc func swipGesture(sender: UISwipeGestureRecognizer?){
// // #objc func swipeAction (swipe: UISwipeGestureRecognizer) {
// if let swipGesture = sender{
// switch swipGesture.direction {
// case UISwipeGestureRecognizer.Direction.right:
// print ("i just swip right")
// let redVC = UIViewController()
// redVC.view.backgroundColor = UIColor.red
// //self.navigationController?.popViewController(animated: true)
// //performSegue(withIdentifier: "goRight", sender: self)
// default:
// break
// }
// }
//
// }
// thirdView = uivi(frame: thirdView)
//self.collectionViewOutletPortfolio? = UICollectionView()
// ViewController.swipGesture(index: index)(index: index)
// case UISwipeGestureRecognizer.Direction.left:
// print ("i just swiped left")
////
// // arrlbl = UICollectionView()
// default:
// break
//
// }
// }
// FOR SWIPPING CHECK WORKING OR NOT
// #IBAction func swipBetweenViews(_ sender: UISwipeGestureRecognizer) {
// print ("HelowSwipped")
//
//}
#IBAction func switchViews(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0{
firstView.isHidden = false
secondView?.isHidden = false
thirdView?.isHidden = true
// firstView.alpha = 0
// secondView.alpha = 1
// thirdView.alpha = 0
//
}else{
firstView.isHidden = false
secondView?.isHidden = true
thirdView?.isHidden = false
// firstView.alpha = 0
// secondView.alpha = 0
// thirdView.alpha = 1
}
}
}
extension ViewController: UICollectionViewDataSource , UICollectionViewDelegate{
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if (collectionView == collectionViewOutletStatic){
let cell = collectionViewOutletStatic.dequeueReusableCell(withReuseIdentifier: "cellone", for: indexPath)as! CollectionViewCellStatic
cell.imgbackground.image = arrimgbackground[indexPath.row]
cell.imglogo.image = arrimglogo[indexPath.row]
cell.imglocation.image = arrimglocation[indexPath.row]
cell.imginsta.image = arrimginsta[indexPath.row]
cell.lblname.text = arrlblname[indexPath.row]
cell.lblrating.text = arrlblrating[indexPath.row]
cell.lbllocation.text = arrlbllocation[indexPath.row]
cell.lblinstaname.text = arrlblinsta[indexPath.row]
cell.lblservicename.text = arrlblservicename[indexPath.row]
cell.lblrs.text = arrlblrs[indexPath.row]
return cell
}else{
if (collectionView == collectionViewOutletAbout){
let cello = collectionViewOutletAbout.dequeueReusableCell(withReuseIdentifier: "celltwo", for: indexPath)as! CollectionViewCellAbout
cello.lbldescription.text = arrlbldescription[indexPath.row]
return cello
}else{
let cellt = collectionViewOutletPortfolio?.dequeueReusableCell(withReuseIdentifier: "cellthree", for: indexPath)as! CollectionViewCellPortfolio
cellt.imgPortfolio.image = arrimgportfolio[indexPath.row]
return cellt
// THIS CODE FOR 3 COLUMNS OF IMAGES COLLECTION LIKE PORFOLIO
// _ = UIScreen.main.bounds.width/2-2
// let layout = UICollectionViewFlowLayout()
//
// collectionViewOutletPortfolio?.collectionViewLayout = layout
//
// layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
// // layout.itemSize = CGSize(width: itemSize, height: itemSize)
////
//// layout.minimumInteritemSpacing = 0
//// layout.minimumLineSpacing = 0
}
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// let x = CGFloat(indexPath.item) * frame.width
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if (collectionView == collectionViewOutletStatic){
return arrimgbackground.count
}else{
if (collectionView == collectionViewOutletAbout){
return arrlbldescription.count
}else{
return arrimgportfolio.count
}
}
}
}
extension ViewController: UICollectionViewDelegateFlowLayout{
// THIS FOR 3 COLUMNS OF IMAGES IN CLLECTION VIEW CELL
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let collectionwidth = collectionView.bounds.width
return CGSize(width: collectionwidth/3, height: collectionwidth/3)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
}
//extension ViewController: PinterestLayoutDelegate{
// func collectionView(_ collectionView: UICollectionView, heightForItemAtIndexPath indexPath: IndexPath) -> CGSize {
// //return UIImage(named: row[indexPath.item].imageename)?.size
//
// }
//}
//
//extension ViewController: PinterestLayoutDelegate{
// func collectionView(_ collectionView: UICollectionView, heightForItemAtIndexPath indexPath: IndexPath) -> CGFloat {
// return 100
// }
//
//
//
// func collectionView(
// _ collectionView: UICollectionView,
// heightForPhotoAtIndexPath indexPath:IndexPath) -> CGFloat {
// return arrimgportfolio[indexPath.row]
// //return arrimgportfolio[indexPath.item].image.size.height
// }
This is the simple example that you want. This is design for full screen. I think you can get an idea and customize this for your requirement
class ContainerController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 13.0, *) {
view.backgroundColor = .systemBackground
} else {
view.backgroundColor = .white
}
navigationItem.titleView = sgControll
updateView()
sgControll.addTarget(self, action: #selector(segmentControllValueChanged (_:)), for:.valueChanged)
}
//MARK: Components
let sgControll:UISegmentedControl = {
let sg = UISegmentedControl()
sg.insertSegment(withTitle: "first Child", at: 0, animated: true)
sg.insertSegment(withTitle: "Second Child", at: 1, animated: true)
sg.selectedSegmentIndex = 0
return sg
}()
private lazy var secondView : SecondChildViewController = {
let vc = SecondChildViewController()
self.add(asChildViewController: vc)
return vc
}()
private lazy var firstView:FirstChildViewController = {
let vc = FirstChildViewwController()
self.add(asChildViewController: vc)
return vc
}()
}
//MARK: Functions
extension ContainerController {
#objc func segmentControllValueChanged(_ sender : UISegmentedControl){
print(sender.selectedSegmentIndex)
updateView()
}
private func add(asChildViewController viewController: UIViewController){
addChild(viewController)
view.addSubview(viewController.view)
viewController.view.translatesAutoresizingMaskIntoConstraints = false
viewController.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
viewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
viewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
viewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
viewController.didMove(toParent: self)
}
private func remove(asChildViewController viewController: UIViewController) {
viewController.willMove(toParent: nil)
viewController.view.removeFromSuperview()
viewController.removeFromParent()
}
private func updateView() {
if sgControll.selectedSegmentIndex == 0 {
remove(asChildViewController: firstView)
add(asChildViewController: secondView)
} else {
remove(asChildViewController: seconView)
add(asChildViewController: firstView)
}
}
}

Text Overlapping Text That Should've deleted

HI, so this is my vc for a view where I save info about a plane (the type and rego). It saves the plane and deletes and you can close the app and come back and it saves it there in the core data model but I have a weird problem. After you make a plane and it shows in the table view and add a few more planes (table view cell which has info) then the labels which display the info start to overlap with what should be deleted information. The pictures bellow show what I mean. Any help would be greatly appreciated.
var context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var typeField: UITextField?
var regoField: UITextField?
#IBAction func addPlaneButton(_ sender: Any) {
let alertController = UIAlertController(title: "New Plane", message: "Please Input The Type And Registration", preferredStyle: .alert)
alertController.addTextField(configurationHandler: typeField)
alertController.addTextField(configurationHandler: regoField)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
let saveAction = UIAlertAction(title: "Save", style: .default, handler: self.savePlane)
alertController.addAction(cancelAction)
alertController.addAction(saveAction)
self.present(alertController, animated: true)
print("Add Plane Pressed")
}
func typeField(textField: UITextField!) {
typeField = textField
typeField?.placeholder = "Aircraft Type"
}
func regoField(textField: UITextField!) {
regoField = textField
regoField?.placeholder = "Aircraft Registration"
}
#IBOutlet weak var tableView: UITableView!
var timer = Timer()
let utcItem = UIBarButtonItem()
let utcLbl = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
//Table View
tableView.delegate = self
tableView.dataSource = self
self.tableView.rowHeight = 88
setupView()
}
//////Functions////
func setupView() {
//UTC Time Formatter
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
dateFormatter.dateFormat = "HH:mm"
_ = Timer.scheduledTimer(timeInterval: 0.05, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true)
//UTC Time
utcLbl.frame = CGRect(x: 0, y: 0, width: 100, height: 20)
utcLbl.text = "\(dateFormatter.string(from: Date())) UTC"
utcItem.customView = utcLbl
utcLbl.backgroundColor = UIColor.init(fromHexCode: "4FB7F1")
utcLbl.layer.cornerRadius = 10
utcLbl.textAlignment = .center
utcLbl.layer.masksToBounds = true // Or utcLbl.clipsToBounds = true
self.navigationItem.setLeftBarButtonItems([utcItem], animated: true)
// Large Title
self.title = "Planes"
self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedString.Key.font: UIFont(name: "Avenir-Black", size: 35)!]
self.navigationController?.navigationBar.prefersLargeTitles = true
let customBlue = UIColor(red:0.08, green:0.38, blue:0.75, alpha:1.0)
navigationController?.navigationBar.barTintColor = customBlue
}
//Constant UTC Time Lbl
#objc func updateTime() {
let formatter = DateFormatter()
formatter.timeZone = TimeZone(abbreviation: "UTC")
formatter.dateFormat = "HH:mm"
utcLbl.text = formatter.string(from: Date()) + " UTC"
}
//Save the Plane Info
func savePlane(alert: UIAlertAction) {
if typeField?.text != "" || regoField?.text != "" {
let newLog = NSEntityDescription.insertNewObject(forEntityName: "Planes", into: context)
newLog.setValue(self.typeField?.text, forKey: "type")
newLog.setValue(self.regoField?.text, forKey: "rego")
do{
try context.save()
}
catch {
print(error)
}
//Making the table update itself when user logs the plane
self.fetchData()
self.tableView.reloadData()
}
print("Plane Saved")
}
func fetchData() {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
do{
planeArray = try context.fetch(Planes.fetchRequest())
}
catch{
print(error)
}
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
if editingStyle == .delete {
let save = planeArray[indexPath.row]
context.delete(save)
(UIApplication.shared.delegate as! AppDelegate).saveContext()
do {
planeArray = try context.fetch(Planes.fetchRequest())
}
catch {
print(error)
}
tableView.reloadData()
}
}
//Table View Functions
public func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (planeArray.count)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
//Plane Pic
let planeView = UIImageView()
planeView.frame = CGRect(x: 0, y: 0, width: 69, height: 67)
//planeView.center = CGPoint(x: cell.center.x - 150, y: cell.center.y)
planeView.center = CGPoint(x: cell.center.x - 145, y: cell.center.y)
let planeImage: UIImage = UIImage(named: "plane")!
planeView.image = planeImage
cell.addSubview(planeView)
//Type Label
let type = UILabel()
type.frame = CGRect(x: 0, y: 0, width: 45, height: 21)
type.center = CGPoint(x: cell.center.x - 80, y: cell.center.y - 22.5)
type.text = "Type:"
type.font = UIFont(name: "Montserrat-Medium", size: 17)
cell.addSubview(type)
//Type Answer
let typeAnswer = UILabel()
typeAnswer.frame = CGRect(x: 0, y: 0, width: 220, height: 21)
typeAnswer.center = CGPoint(x: cell.center.x + 62.5, y: cell.center.y - 22.5)
typeAnswer.text = ""
typeAnswer.font = UIFont(name: "Montserrat-Light", size: 17)
typeAnswer.textAlignment = .right
cell.addSubview(typeAnswer)
//Rego Label
let rego = UILabel()
rego.frame = CGRect(x: 0, y: 0, width: 110, height: 21)
rego.center = CGPoint(x: cell.center.x - 47.5, y: cell.center.y + 18.5)
rego.text = "Registration:"
rego.font = UIFont(name: "Montserrat-Medium", size: 17)
cell.addSubview(rego)
//rego answer
let regoAnswer = UILabel()
regoAnswer.frame = CGRect(x: 0, y: 0, width: 160, height: 21)
regoAnswer.center = CGPoint(x: cell.center.x + 92.5, y: cell.center.y + 18.5)
regoAnswer.text = ""
regoAnswer.font = UIFont(name: "Montserrat-Light", size: 17)
regoAnswer.textAlignment = .right
cell.addSubview(regoAnswer)
let save = planeArray[indexPath.row]
typeAnswer.text = save.type
regoAnswer.text = save.rego
return cell
}
override func viewWillAppear(_ animated: Bool) {
//Making the table update itself when user logs the plane
fetchData()
tableView.reloadData()
}
}
UITableView reuses the cells. In your case, when the cells are created the first time, you add a UILabel to it. The next time this cell is loaded, UITableView reuses the existing cell and cellForRowAt adds another UILabel to this cell. The proper implementation is to create a custom UITableViewCell and reset the value of all the attributes in cellForRowAt method.
You can try something like below (please note that this is just a rough implementation and it is assumed that you know the basics of ios programming. If that is not the case, I'd recommend researching it a bit):
Add a custom tableview cell
class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var imgViewPlane: UIImageView!
#IBOutlet weak var lblType: UILabel!
#IBOutlet weak var lblTypeAnswer: UILabel!
#IBOutlet weak var lblRego: UILabel!
#IBOutlet weak var lblRegoAnswer: UILabel!
}
Create a dynamic prototype cell in storyboard tableview and link the IBOutlets. Then in your cellForRowAt, do something like this
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomTableViewCell
cell.imgViewPlane.image = planeImage
cell.lblType.text = "Type:"
cell.lblTypeAnswer.text = planeArray[indexPath.row].type
cell.lblRego.text = "Registration:"
cell.lblRegoAnswer.text = planeArray[indexPath.row].rego
return cell
}
You’re adding new subviews to your cell every time that cell is dequeued.
I would recommend you to create these views, labels, etc. as lazy variables inside UITableViewCell subclass and add them as subviews inside awakeFromNib()
class YourCell: UITableViewCell {
lazy var label: UILabel = {
var label = UILabel(...)
...
return label
}()
...
override func awakeFromNib() {
addSubview(label)
...
}
}
.... or use IBOutlet if you’re using storyboard
Then in cellForRowAt just change properties of you downcasted cell subclass’s views
let cell = ... as! YourCell
cell.label.text = ""
cell.anotherLabel.isHidden = true
...

How to set the preferredContentSize of a UIViewController to the height of a containing UITableView contentSize?

I call a popover like the following:
if let vc = CalendarDetailViewControllerContainer.storyboardInstance() {
vc.preferredContentSize = CGSize(width: ((self.view.frame.width / 5) * 2), height: vc.view.frame.height);
vc.modalPresentationStyle = UIModalPresentationStyle.popover;
vc.popoverPresentationController?.delegate = self;
vc.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection.any;
vc.popoverPresentationController?.sourceView = sourceView;
vc.popoverPresentationController?.sourceRect = CGRect(x: 0, y: 0, width: sourceView.frame.size.width, height: sourceView.frame.size.height);
self.present(vc, animated: true, completion: nil);
}
As you can see for now I set the preferredContentSize height to vc.view.frame.height. But that should be different. For now, more code. In the following my CalendarDetailViewControllerContainer:
class CalendarDetailViewControllerContainer : UIViewController {
#IBOutlet weak var containerView: UIView!;
static func storyboardInstance() -> CalendarDetailViewControllerContainer? {
let storyboard = UIStoryboard(name: String(describing: NSStringFromClass(CalendarDetailViewControllerContainer.classForCoder()).components(separatedBy: ".").last!), bundle: nil);
return storyboard.instantiateInitialViewController() as? CalendarDetailViewControllerContainer;
}
override func viewDidLoad() {
super.viewDidLoad();
self.setupView();
self.setupDetailView();
}
func setupView() {
self.view.backgroundColor = UIColor.clear;
self.view.isOpaque = false;
}
func setupDetailView() {
if let vc = CalendarDetailViewController.storyboardInstance() {
let navigationController = UINavigationController(rootViewController: vc);
self.addChildViewController(navigationController);
navigationController.view.frame = self.containerView.frame;
self.containerView.addSubview(navigationController.view);
navigationController.didMove(toParentViewController: self);
}
}
}
I need this container because for later purposes and future segues I will need the navigation controller (and I wont build it in storyboard). So the last part of the code:
class CalendarDetailViewController : UITableViewController {
static func storyboardInstance() -> CalendarDetailViewController? {
let storyboard = UIStoryboard(name: String(describing: NSStringFromClass(CalendarDetailViewController.classForCoder()).components(separatedBy: ".").last!), bundle: nil);
return storyboard.instantiateInitialViewController() as? CalendarDetailViewController;
}
override func viewDidLoad() {
self.navigationController?.isNavigationBarHidden = true;
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 120.0;
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return CGFloat.leastNormalMagnitude;
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return CGFloat.leastNormalMagnitude;
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension;
}
}
What I now try to do is to set the preferredContentSize height of the popover to be exactly the contentSize of the table view.
How can I do that?
You can override preferredContentSize for CalendarDetailViewControllerContainer, but make sure that you reloaded table and calling layoutIfNeeded() before calculating the size.
public override var preferredContentSize: CGSize {
get {
return CGSize(width: tableView.contentSize.width,
height: tableView.contentSize.height + tableView.layoutMargins.top + tableView.layoutMargins.bottom)
}
set { super.preferredContentSize = newValue }
}