Filtering UItableview Swift IOS - ios

I am trying to filter a UITableView based on variables that have been passed back from another VC which is a Eureka form handling the filter UI.
I would like to filter the tableview based on these two variables :
var filterByPrice: Float?
var filteredRentalTypes: Set<String>?
I have got the price filter working but I am having trouble filtering with the rental type. There may be a more efficient way of doing this but this is my code so far. With my current code I get an 'index out of range' crash for the rental type filter.
This is my TableViewVC:
class RentalTableViewVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
var rentalsArray = [Rental]()
var filteredArrary = [Rental]()
var myRentals = [String]()
var filterByPrice: Float?
var filteredRentalTypes: Set<String>?
static var imageCache: NSCache<NSString, UIImage> = NSCache()
#IBOutlet weak var tableView: UITableView!
var hidingBarMangar: HidingNavigationBarManager?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toDetailVC" {
let destination = segue.destination as? DetailVC
let value = tableView.indexPathForSelectedRow?.row
if filteredArrary.count != 0 {
destination?.emailAdress = filteredArrary[value!].email!
destination?.bond = filteredArrary[value!].bond!
destination?.dateAval = filteredArrary[value!].dateAval!
destination?.pets = filteredArrary[value!].pets!
destination?.rent = filteredArrary[value!].price!
destination?.rentalTitle = filteredArrary[value!].title!
destination?.imageURL = filteredArrary[value!].imageURL!
destination?.des = filteredArrary[value!].description!
destination?.rentalType = filteredArrary[value!].rentalType!
destination?.streetName = filteredArrary[value!].streetName!
destination?.city = filteredArrary[value!].city!
destination?.postcode = filteredArrary[value!].postcode!
} else {
destination?.emailAdress = rentalsArray[value!].email!
destination?.bond = rentalsArray[value!].bond!
destination?.dateAval = rentalsArray[value!].dateAval!
destination?.pets = rentalsArray[value!].pets!
destination?.rent = rentalsArray[value!].price!
destination?.rentalTitle = rentalsArray[value!].title!
destination?.imageURL = rentalsArray[value!].imageURL!
destination?.des = rentalsArray[value!].description!
destination?.rentalType = rentalsArray[value!].rentalType!
destination?.streetName = rentalsArray[value!].streetName!
destination?.city = rentalsArray[value!].city!
destination?.postcode = rentalsArray[value!].postcode!
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if filteredArrary.count != 0 {
return filteredArrary.count
} else {
return rentalsArray.count
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var rental = rentalsArray[indexPath.row]
if self.filteredArrary.count != 0 {
rental = filteredArrary[indexPath.row]
}
if let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? RentalCell {
var rentalImage = ""
if rental.imageURL != nil {
rentalImage = rental.imageURL!
}
if let img = RentalTableViewVC.imageCache.object(forKey: rentalImage as NSString) {
cell.configureCell(rental: rental, image: img)
return cell
} else {
cell.configureCell(rental: rental, image: nil)
return cell
}
} else {
return RentalCell()
}
}
#IBAction func backPressed(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
hidingBarMangar?.viewWillAppear(animated)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
hidingBarMangar?.viewDidLayoutSubviews()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
hidingBarMangar?.viewWillDisappear(animated)
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.dataSource = self
//Firebase observer
DataService.ds.DBrefRentals.observe(.value) { (snapshot) in
self.rentalsArray = []
self.filteredArrary = []
if let snapshots = snapshot.children.allObjects as? [DataSnapshot] {
for snap in snapshots {
if let dicOfRentals = snap.value as? Dictionary<String,AnyObject> {
let key = snap.key
let rental = Rental(postID: key, userData: dicOfRentals)
self.rentalsArray.append(rental)
//Placing filtered items in the filtered array
if self.filterByPrice != nil {
let priceAsFloat = (rental.price! as NSString).floatValue
if self.filterByPrice! >= priceAsFloat {
self.filteredArrary.append(rental)
}
}
if self.filteredRentalTypes != nil {
for rentals in self.filteredRentalTypes! {
if rental.rentalType == rentals {
print("******hh\(String(describing: self.filteredRentalTypes))")
self.filteredArrary.append(rental)
}
}
}
}
}
self.tableView.reloadData()
}
}
addHidingBar()
}
override func viewDidAppear(_ animated: Bool) {
print("**********\(String(describing: filterByPrice)))")
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
rentalsArray[indexPath.row].incrimentViews()
let postViewsToFB = DataService.ds.DBrefRentals.child(rentalsArray[indexPath.row].postID!)
postViewsToFB.child("views").setValue(rentalsArray[indexPath.row].views)
performSegue(withIdentifier: "toDetailVC" , sender: nil)
}
func addHidingBar() {
let extensionView = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 40))
extensionView.layer.borderColor = UIColor.lightGray.cgColor
extensionView.layer.borderWidth = 1
extensionView.backgroundColor = UIColor(white: 230/255, alpha: 1)
/*let label = UILabel(frame: extensionView.frame)
label.text = "Extension View"
label.textAlignment = NSTextAlignment.center
extensionView.addSubview(label) */
let btn = UIButton(frame: CGRect(x: 20, y: 15, width: 75, height: 10))
btn.setTitle("Filter", for: .normal)
let btnColour = UIColor(displayP3Red: 0.0, green: 122.0/255.0, blue: 1.0, alpha: 1.0)
btn.setTitleColor(btnColour, for: .normal)
btn.titleLabel?.font = headerFont
btn.addTarget(self, action: #selector(filterBtnPressed), for: .touchUpInside)
extensionView.addSubview(btn)
hidingBarMangar = HidingNavigationBarManager(viewController: self, scrollView: tableView)
hidingBarMangar?.addExtensionView(extensionView)
}
#objc func filterBtnPressed() {
performSegue(withIdentifier: "toFilterVC", sender: nil)
}
}

You may return different array in numberOfRows and their sizes may be different so check count before indexing any array as if array count != 0 doesn't mean you can index it with index path.row that may be greater then 0 ,Change this line in cellForRow
if self.filteredArrary.count != 0 {
rental = filteredArrary[indexPath.row]
}
to
if indexPath.row < self.filteredArrary.count {
rental = filteredArrary[indexPath.row]
}

Related

iOS Charts in a tableview: correct use of a delegate and global zoom

I'm using iOS Charts in my project, and I've been able to embed my charts in a tableview (every cell will contain a chart, up to maximum number of possible entries to keep under control the performance).
I would like to use the 'touchMatrix' feature in order zoom the x axis on one chart (in a cell) and have all of the other visible charts to follow along with the zoom scale (the x axis), possibly with a vertical axis showing the Y value on every visible chart for that x coordinate, but I'm kind of stuck, since even the delegate methods such as 'chartValueNothingSelected' are not working (I probably got it wrong when I tried to associate the delegate to the chartview, since the chart it's embedded in the cell, and it's not the tipical case of associating the delegate to a view controller).
Assigning the delegate to the cell just doesn't seem to be working.
Any tips?
Thanks in advance.
Here is the code:
import UIKit
import Charts
class CustomChartCell: UITableViewCell, ChartViewDelegate {
#IBOutlet weak var lineChartView: LineChartView!
var yValues = [Double]()
var xValues = [Double]()
var chartColor = UIColor()
var channelName = ""
var yMin = 0.0
var yMax = 0.0
var yAvg = 0.0
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.lineChartView.noDataFont = UIFont.systemFont(ofSize: 28.0)
self.lineChartView.noDataText = NSLocalizedString("No chart data available", comment: "No Chart Data Available Title")
self.lineChartView.xAxis.labelPosition = .bottom
self.lineChartView.highlightPerTapEnabled = true
self.lineChartView.autoScaleMinMaxEnabled = true
self.lineChartView.chartDescription?.enabled = true
self.lineChartView.dragEnabled = true
self.lineChartView.setScaleEnabled(true)
self.lineChartView.pinchZoomEnabled = false
self.lineChartView.xAxis.gridLineDashLengths = [10, 10]
self.lineChartView.xAxis.gridLineDashPhase = 0
self.lineChartView.leftAxis.gridLineDashLengths = [5, 5]
self.lineChartView.leftAxis.drawLimitLinesBehindDataEnabled = true
self.lineChartView.rightAxis.enabled = false
let marker = BalloonMarker(color: UIColor(white: 180/255, alpha: 1),
font: .systemFont(ofSize: 12),
textColor: .white,
insets: UIEdgeInsets(top: 8, left: 8, bottom: 20, right: 8))
marker.chartView = self.lineChartView
marker.minimumSize = CGSize(width: 80, height: 40)
self.lineChartView.marker = marker
self.lineChartView.legend.form = .line
self.lineChartView.delegate = self
}
func setChart(_ xValues: [Double], _ yValues: [Double]) {
var dataEntries: [ChartDataEntry] = []
for i in 0..<xValues.count {
let dataEntry = ChartDataEntry(x: xValues[i], y: yValues[i])
dataEntries.append(dataEntry)
}
let chartDataSet = LineChartDataSet(values: dataEntries, label: self.channelName)
let chartData = LineChartData(dataSets: [chartDataSet])
chartDataSet.setColor(self.chartColor.withAlphaComponent(0.5))
chartDataSet.drawCirclesEnabled = false
chartDataSet.lineWidth = 2
chartDataSet.drawValuesEnabled = false
chartDataSet.highlightEnabled = true
chartDataSet.drawFilledEnabled = false
lineChartView.data = chartData
self.lineChartView!.leftAxis.axisMinimum = self.yValues.min()! - self.yValues.max()!*0.2
self.lineChartView!.leftAxis.axisMaximum = self.yValues.max()! + self.yValues.max()!*0.2
self.lineChartView!.chartDescription?.font = UIFont.systemFont(ofSize: 11.0)
self.lineChartView!.chartDescription?.text = "y_min: \(self.yMin), y_max: \(self.yMax), y_avg: \(self.yAvg)"
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
class ChartTableViewController: UITableViewController, ChartViewDelegate {
var dataSet : [LineChartData] = []
let data = LineChartData()
var channelNames : [String] = []
let channelColors = [UIColor.blue, UIColor.green, UIColor.red,
UIColor.orange, UIColor.purple, UIColor.darkGray]
var averageValues : [Double] = []
var minValues : [Double] = []
var maxValues : [Double] = []
var xValues : [[Double]] = []
var yValues : [[Double]] = []
#IBAction func chartZoomOut(_ sender: Any) {
tableView?.visibleCells.forEach { cell in
if let cell = cell as? CustomChartCell {
cell.lineChartView.zoomOut()
}
}
}
#IBAction func chartZoom100(_ sender: Any) {
tableView?.visibleCells.forEach { cell in
if let cell = cell as? CustomChartCell {
cell.lineChartView.zoomToCenter(scaleX: 0, scaleY: 0)
}
}
}
#IBAction func chartZoomIn(_ sender: Any) {
tableView?.visibleCells.forEach { cell in
if let cell = cell as? CustomChartCell {
cell.lineChartView.zoomIn()
}
func chartValueNothingSelected(_ chartView: ChartViewBase) {
chartView.chartDescription?.text = ""
}
func chartScaled(chartView: ChartViewBase, scaleX: CGFloat, scaleY: CGFloat) {
print(scaleX)
print(scaleY)
}
func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
chartView.chartDescription?.text = "x: \(entry.x), y: \(entry.y), y_min: \(minValues[0]), y_max: \(maxValues[0]), y_avg: \(averageValues[0])"
chartView.reloadInputViews()
}
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.isEditing = false
self.editButtonItem.title = NSLocalizedString("Edit", comment: "Edit Title")
self.tableView.separatorColor = UIColor.clear
self.navigationItem.rightBarButtonItem = self.editButtonItem
self.loadFile()
self.tableView.reloadData()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tableView.isEditing = false
self.editButtonItem.title = NSLocalizedString("Edit", comment: "Edit Title")
}
// MARK: Load Chart File
func loadFile() {
// Try to load the file content
do {
// get the documents folder url
let documentDirectoryURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
// create the destination url for the text file to be saved
let fileDestinationUrl = documentDirectoryURL.appendingPathComponent(Constants.CHART_FILE_NAME)
// reading from disk
do {
let file = try String(contentsOf: fileDestinationUrl)
let newFile = file.replacingOccurrences(of: "\r", with: "") // Get rid of additional new lines
let cleanChannels = self.generateCleanChannels(newFile) // // a function used to retrieve the channels from the file (since the file it's not a plain CSV file but something different)
channelNames.removeAll()
dataSet.removeAll()
channelNames = self.getChannelNames(newFile) // a function used to retrieve the channel names from the file (since the file it's not a plain CSV file but something different)
var lineChartEntry = [ChartDataEntry]()
data.clearValues()
for (index,channel) in cleanChannels.enumerated() {
if (index <= Constants.MAX_CHART_CHANNELS) {
let csvImage = CSV(string: channel, delimiter: ";")
var y_max = 0.0
var firstXValueSampled : Bool = false
var firstXValue : Double = 0.0
var average = 0.0
var min = 0.0
var max = 0.0
var count = 0
var new_xValues : [Double] = []
var new_yValues : [Double] = []
csvImage.enumerateAsDict { dict in
print(dict["X_Value"]!)
new_xValues.append(Double(dict["X_Value"]!)!)
new_yValues.append(Double(dict["Y_Value"]!)!)
if !firstXValueSampled {
firstXValueSampled = true
firstXValue = Double(dict["X_Value"]!)!
}
average = average + Double(dict["Y_Value"]!)!
count = count + 1
let value = ChartDataEntry(x: (Double(dict["X_Value"]!)! - firstXValue), y: Double(dict["Y_Value"]!)! )
lineChartEntry.append(value)
if Double(dict["Y_Value"]!)! > max {
max = Double(dict["Y_Value"]!)!
}
if Double(dict["Y_Value"]!)! < min {
min = Double(dict["Y_Value"]!)!
}
if Double(dict["Y_Value"]!)! > y_max {
y_max = Double(dict["Y_Value"]!)!
}
}
xValues.append(new_xValues)
yValues.append(new_yValues)
average = average / Double(count)
averageValues.append(average)
minValues.append(min)
maxValues.append(max)
let line = LineChartDataSet(values: lineChartEntry, label: channelNames[index])
line.axisDependency = .left
line.colors = [channelColors[index]] // Set the color
line.setColor(channelColors[index].withAlphaComponent(0.5))
line.setCircleColor(channelColors[index])
line.lineWidth = 2.0
line.circleRadius = 3.0
line.fillAlpha = 65 / 255.0
line.fillColor = channelColors[index]
line.highlightColor = UIColor(red: 244/255, green: 117/255, blue: 117/255, alpha: 1)
line.drawCircleHoleEnabled = false
line.highlightLineWidth = 2.0
line.drawHorizontalHighlightIndicatorEnabled = true
data.setValueFont(.systemFont(ofSize: 9))
data.addDataSet(line) // Add the line to the dataSet
let newData = LineChartData()
newData.setValueFont(.systemFont(ofSize: 9))
newData.addDataSet(line)
dataSet.append(newData)
}
}
} catch let error as NSError {
print("error loading contentsOf url \(fileDestinationUrl)")
print(error.localizedDescription)
}
} catch let error as NSError {
print("error getting documentDirectoryURL")
print(error.localizedDescription)
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return dataSet.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "CustomChartCell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier,
for: indexPath) as! CustomChartCell
cell.lineChartView.delegate = self
if dataSet.count > 0 {
cell.xValues = xValues[indexPath.row]
cell.yValues = yValues[indexPath.row]
cell.chartColor = channelColors[indexPath.row]
cell.channelName = channelNames[indexPath.row]
cell.yMin = minValues[indexPath.row]
cell.yMax = maxValues[indexPath.row]
cell.yAvg = averageValues[indexPath.row]
cell.lineChartView.leftAxis.axisMaximum = cell.yValues.max()! + 1
cell.lineChartView.leftAxis.axisMinimum = cell.yValues.min()! - 1
cell.setChart(cell.xValues, cell.yValues)
} else {
cell.lineChartView.clearValues()
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//tableView.deselectRow(at: indexPath, animated: true)
let selectedCell = tableView.cellForRow(at: indexPath) as! CustomChartCell
selectedCell.contentView.backgroundColor = UIColor.lightGray
//let currentMatrix = selectedCell.lineChartView.viewPortHandler.touchMatrix
//let selectedCell:UITableViewCell = tableView.cellForRow(at: indexPath)! as! CustomChartCell
//selectedCell.contentView.backgroundColor = UIColor.lightGray
//let currentMatrix = selectedCell.lineChartView.viewPortHandler.touchMatrix
/*
tableView.visibleCells.forEach { cell in
if let cell = cell as? CustomChartCell {
if cell.channelName != selectedCell.channelName {
cell.lineChartView.viewPortHandler.refresh(newMatrix: currentMatrix, chart: cell.lineChartView, invalidate: true)
}
}
}
*/
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 250
}
override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
return .none
}
override func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
return false
}
override func setEditing (_ editing:Bool, animated:Bool)
{
super.setEditing(editing,animated:animated)
if (self.isEditing) {
//self.editButtonItem.title = "Editing"
self.editButtonItem.title = NSLocalizedString("Done", comment: "Done Title")
}
else {
self.editButtonItem.title = NSLocalizedString("Edit", comment: "Edit Title")
}
}
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let movedObject = self.dataSet[sourceIndexPath.row]
dataSet.remove(at: sourceIndexPath.row)
dataSet.insert(movedObject, at: destinationIndexPath.row)
}
}

How to make the UILabel replace the NavigationBar large title?

I am a beginner to Xcode and Swift and I am currently creating an application where the user adds a person on the application and after that it right the amount of money they owe that person or that person owes him/her.
I actually want to show the user their current balance with other user on NavigationBar Large title and currently I am doing that by using frame where I define the width, height and x,y positions of frame that is replaced by UILabel. However, I wish the balance to be replaced on the NavigationBar Large Title. I am trying to find a solution to this from past 3 days therefore can you please help me? Thanks a lot in advance
import UIKit
class PersonDetailTableViewController: UITableViewController {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var person: People?
var owe: Owe?
#IBOutlet var personTable: UITableView!
var dataInfo: [Owe] = []
var selectedObject: [Owe] = []
var balanceAmount = "Balance: "
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (dataInfo.count)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = personTable
.dequeueReusableCell(withIdentifier: "detailsCell", for: indexPath)
cell.textLabel?.text = dataInfo[indexPath.row].name
cell.detailTextLabel?.text = "₹ \(dataInfo[indexPath.row].amount)"
if dataInfo[indexPath.row].amount < 0 {
cell.detailTextLabel?.textColor = UIColor.red
} else {
cell.detailTextLabel?.textColor = UIColor.green
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedObject = [dataInfo[indexPath.row]]
performSegue(withIdentifier: "addOweDetails", sender: nil)
tableView.deselectRow(at: indexPath, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
getData()
personTable.dataSource = self
addTotalToNav()
print(dataInfo as Any)
}
// MARK: - Table view data source
func addTotalToNav() -> Void {
if let navigationBar = self.navigationController?.navigationBar {
let totalFrame = CGRect(x: 20, y: 0, width: navigationBar.frame.width/2, height: navigationBar.frame.height)
let totalLabel = UILabel()
totalLabel.text = balanceAmount
totalLabel.tag = 1
totalLabel.font = UIFont.boldSystemFont(ofSize: 14)
totalLabel.textColor = UIColor.red
navigationBar.addSubview(totalLabel)
}
}
func getData() -> Void {
do{
dataInfo = try context.fetch(Owe.fetchRequest())
var total:Double = 0.00
for i in 0 ..< dataInfo.count {
total += dataInfo[i].amount as! Double
}
balanceAmount = "Balance: ₹" + (NSString(format: "%.2f", total as CVarArg) as String)
}
catch{
print("Fetching Failed")
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! NewOweTableViewController
vc.dataInfo = selectedObject
selectedObject.removeAll()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
getData()
personTable.reloadData()
if (self.navigationController?.navigationBar.viewWithTag(1)?.isHidden == true){
self.navigationController?.navigationBar.viewWithTag(1)?.removeFromSuperview()
addTotalToNav()
}
}
}
Swift 3.0 Use below method to create NavigationBarTitle and NavigationBarSubTitle
func setTitle(title:String, subtitle:String) -> UIView {
let titleLabel = UILabel(frame: CGRect(x:0,y: -8 ,width: 0,height: 0))
titleLabel.backgroundColor = UIColor.clear
titleLabel.textColor = UIColor.black
titleLabel.font = UIFont.systemFont(ofSize: 22)
titleLabel.text = title
titleLabel.sizeToFit()
let subtitleLabel = UILabel(frame: CGRect(x:0,y:18,width: 0,height :0))
subtitleLabel.backgroundColor = UIColor.clear
subtitleLabel.textColor = UIColor.black
subtitleLabel.font = UIFont.systemFont(ofSize: 12)
subtitleLabel.text = subtitle
subtitleLabel.sizeToFit()
let titleView = UIView(frame: CGRect(x:0,y:0,width : max(titleLabel.frame.size.width, subtitleLabel.frame.size.width),height: 30))
titleView.addSubview(titleLabel)
titleView.addSubview(subtitleLabel)
let widthDiff = subtitleLabel.frame.size.width - titleLabel.frame.size.width
if widthDiff < 0 {
let newX = widthDiff / 2
subtitleLabel.frame.origin.x = abs(newX)
} else {
let newX = widthDiff / 2
titleLabel.frame.origin.x = newX
}
return titleView
}
Use this in viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.titleView = setTitle(title: "My Events", subtitle: "Sub Title")
}
Here is the code, just set the titleView to your label:
let customLabel = UILabel()
// config your label here
navigationItem?.titleView = customLabel
You can use navigationBar.topItem?.titleView = totalLabel instead of navigationBar.addSubview(totalLabel).

View disappears with delay swift

I have the navigationController with 2 UIViewControllers.
When I press "back button" view from secondViewController disappears with 1 second delay.
P.S. I use iCarousel pod for init the views in secondViewController.
See screenshots:
When I press "back" button from another:
FirstController after 1 second (view from second controller disappeared)
Update:
Second ViewController
class AppsController : UIViewController, iCarouselDataSource, iCarouselDelegate {
let xmlHelper = XmlHelper()
var apps = Apps(data:[App]())
var selectUrl = ""
var selectTitle = ""
var scrollIndex = 0
#IBOutlet var carousel: iCarousel!
override func viewDidLoad() {
super.viewDidLoad()
self.carousel.delegate = self
self.carousel.isPagingEnabled = true
DispatchQueue.main.async {
self.initApps()
}
}
func numberOfItems(in carousel: iCarousel) -> Int {
return apps.data.count
}
func carousel(_ carousel: iCarousel, viewForItemAt index: Int, reusing view: UIView?) -> UIView {
let appView: AppView = Bundle.main.loadNibNamed("appView",
owner: nil,
options: nil)?.first as! AppView!
appView.titleLabel?.text = apps.data[index].title
appView.descLabel?.text = apps.data[index].desc
appView.frame = CGRect(x:0, y:0, width:self.view.frame.width-30, height:carousel.frame.height-60)
appView.backgroundColor = UIColor.white
var shadowLayer: CAShapeLayer!
shadowLayer = CAShapeLayer()
shadowLayer.path = UIBezierPath(roundedRect: appView.bounds, cornerRadius: 0).cgPath
shadowLayer.fillColor = UIColor.white.cgColor
shadowLayer.shadowColor = UIColor.lightGray.cgColor
shadowLayer.shadowPath = shadowLayer.path
shadowLayer.shadowOffset = CGSize(width: 0.0, height: 0.0)
shadowLayer.shadowOpacity = 0.8
shadowLayer.shadowRadius = 2
appView.layer.insertSublayer(shadowLayer, at: 0)
appView.storeButton.addTarget(self, action: #selector(didTapApp), for: UIControlEvents.touchUpInside)
DispatchQueue.main.async {
appView.iconView?.sd_setImage(with: URL(string:self.apps.data[index].icon
), completed: { (image, error, cache, url) in
if error == nil {
appView.iconView.image = appView.iconView.image?.cropToBounds(image: image!, width: 30, height: 30)
}
})
}
return appView
}
func carousel(_ carousel: iCarousel, valueFor option: iCarouselOption, withDefault value: CGFloat) -> CGFloat {
if (option == .spacing) {
return value * 1.1
}
return value
}
func didTapApp() {
if self.apps.data.count != 0 {
UIApplication.shared.open(URL(string: "itms://itunes.apple.com/app/id" + self.apps.data[carousel.currentItemIndex].link)!, options: [:], completionHandler: nil)
}
}
func initApps() {
xmlHelper.getAnoutherApps { (apps) in
if apps != nil{
self.apps = apps!
self.carousel.reloadData()
}
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let backItem = UIBarButtonItem()
backItem.title = constants.back
navigationItem.backBarButtonItem = backItem
if segue.identifier == "toWeb" {
let vc = segue.destination as! WebController
vc.fileUrl = nil
vc.url = self.selectUrl
vc.title = self.selectTitle
self.tabBarController?.tabBar.isHidden = true
}
}
AppView (disappears with delay)
class AppView : UIView {
#IBOutlet var titleLabel : UILabel!
#IBOutlet var descLabel : UILabel!
#IBOutlet var iconView : UIImageView!
#IBOutlet var storeButton : UIButton!
}
First controller
class SettingsController : UITableViewController, MFMailComposeViewControllerDelegate {
var selectUrl : URL?
var selectTitle = ""
var selectStringUrl = ""
override func viewDidLoad() {
super.viewDidLoad()
self.initUI()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 4
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0:
return 2
case 1:
return 1
case 2:
return 1
case 3:
return 3
default:
return 0
}
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch section {
case 0:
return constants.info
case 1:
return constants.settings
case 2:
return constants.connect
case 3:
return constants.community
default:
return ""
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "settingsTitleCell")!
let itemSize = CGSize(width:30, height:30);
UIGraphicsBeginImageContextWithOptions(itemSize, false, UIScreen.main.scale);
let imageRect = CGRect(x:0.0, y:0.0, width:itemSize.width, height:itemSize.height);
cell.imageView?.image!.draw(in: imageRect)
cell.imageView?.image! = UIGraphicsGetImageFromCurrentImageContext()!;
UIGraphicsEndImageContext();
switch indexPath.section {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "settingsTitleCell")!
cell.textLabel?.text = constants.infoTitles[indexPath.row]
cell.detailTextLabel?.text = constants.infoDetail[indexPath.row]
cell.imageView?.image = cell.imageView?.image?.cropToBounds(image: constants.infoImages[indexPath.row], width: 30, height: 30)
return cell
case 1:
let cell = tableView.dequeueReusableCell(withIdentifier: "fontCell") as! FontCell
return cell
case 2:
let cell = tableView.dequeueReusableCell(withIdentifier: "settingsTitleCell")!
cell.textLabel?.text = constants.connectTitles[indexPath.row]
cell.imageView?.image = cell.imageView?.image?.cropToBounds(image: constants.connectImages[indexPath.row], width: 30, height: 30)
cell.detailTextLabel?.text = ""
return cell
case 3:
let cell = tableView.dequeueReusableCell(withIdentifier: "settingsTitleCell")!
cell.textLabel?.text = constants.communityTitles[indexPath.row]
cell.detailTextLabel?.text = constants.communityDetail[indexPath.row]
cell.imageView?.image = cell.imageView?.image?.cropToBounds(image: constants.communityImages[indexPath.row], width: 30, height: 30)
return cell
default:
return cell
}
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 1 {
return 80
} else {
return 45
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch indexPath.section {
case 0:
if indexPath.row == 0 {
self.initWebView(url: Bundle.main.url(forResource: "caution", withExtension: "html"), stringUrl: nil, titlePage: constants.infoTitles[indexPath.row])
} else {
self.selectTitle = constants.infoTitles[indexPath.row]
self.performSegue(withIdentifier: "toApps", sender: self)
}
case 2:
self.sendMessage()
break;
case 3:
switch indexPath.row {
case 0:
self.initWebView(url: Bundle.main.url(forResource: "about", withExtension: "html"), stringUrl: nil, titlePage: constants.communityTitles[indexPath.row])
break;
case 1:
self.initWebView(url: nil, stringUrl: "https://vk.com/electronicengineer", titlePage: constants.communityTitles[indexPath.row])
case 2:
self.initWebView(url: nil, stringUrl: "https://fb.com", titlePage: constants.communityTitles[indexPath.row])
break;
default:
break;
}
default:
break;
}
}
func initUI() {
self.title = constants.settings
self.tableView.tableFooterView = UIView()
}
func initWebView(url:URL?, stringUrl:String?, titlePage:String) {
if stringUrl != nil {
self.selectStringUrl = stringUrl!
self.selectUrl = nil
} else {
self.selectUrl = url!
}
self.selectTitle = titlePage
self.performSegue(withIdentifier: "toWeb", sender: self)
}
func sendMessage() {
let mailComposeViewController = configuredMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
self.present(mailComposeViewController, animated: true, completion: nil)
}
}
func configuredMailComposeViewController() -> MFMailComposeViewController {
let mailComposerVC = MFMailComposeViewController()
mailComposerVC.mailComposeDelegate = self
mailComposerVC.setToRecipients(["postboxapp#yandex.ru"])
mailComposerVC.setSubject("Электроник на Android")
mailComposerVC.setMessageBody("", isHTML: false)
return mailComposerVC
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let backItem = UIBarButtonItem()
backItem.title = constants.back
navigationItem.backBarButtonItem = backItem
if segue.identifier == "toWeb" {
let vc = segue.destination as! WebController
vc.fileUrl = self.selectUrl
vc.url = self.selectStringUrl
vc.title = self.selectTitle
self.tabBarController?.tabBar.isHidden = true
}
if segue.identifier == "toApps" {
let vc = segue.destination as! AppsController
vc.title = self.selectTitle
self.tabBarController?.tabBar.isHidden = true
}
}
}
Problem solved:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
self.carousel.isHidden = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
self.carousel.isHidden = false
}
Hiding and unhiding is just a work-around to the actual problem.
As answered to a similar question, set yourCarousel.clipsToBounds = true

Table view scrolling is erratic and jumpy even though I reuse cells?

Okay, so I'm not sure whats been happening with my Table view, but it seems to act a bit strange now that I load images from parse onto it. At first, it ran smoothly, but now that I'm working in ios 9, the scrolling is horrible
Optimizations I've used to reduce this(Keep in mind they do not really help.)
-Removed transparent objects and set them to default background
-reused table cells
-Tried to use lower quality images
Here is my code
import UIKit
class mainVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var resultsTable: UITableView!
#IBOutlet weak var menuButton:UIBarButtonItem!
var deleteArray = [String]()
var followArray = [String]()
var resultsLocationArray = [String]()
var datetextfielArray = [String]()
var imageDates = [String]()
var resultsNameArray = [String]()
var resulltsImageFiles = [PFFile]()
var resultsTweetArray = [String]()
var resultsHasImageArray = [String]()
var resultsTweetImageFiles = [PFFile?]()
var refresher:UIRefreshControl!
override func viewDidLoad() {
super.viewDidLoad()
if self.revealViewController() != nil {
menuButton.target = self.revealViewController()
menuButton.action = "revealToggle:"
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
// Uncomment to change the width of menu
//self.revealViewController().rearViewRevealWidth = 62
}
let theWidth = view.frame.size.width
let theHeight = view.frame.size.height
resultsTable.frame = CGRectMake(0, 0, theWidth, theHeight)
let tweetBtn = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Compose, target: self, action: Selector("tweetBtn_click"))
let searchBtn = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Search, target: self, action: Selector("searchBtn_click"))
let buttonArray = NSArray(objects: tweetBtn, searchBtn)
self.navigationItem.rightBarButtonItems = buttonArray as? [UIBarButtonItem]
refresher = UIRefreshControl()
refresher.tintColor = UIColor.blackColor()
refresher.addTarget(self, action: "refresh", forControlEvents: UIControlEvents.ValueChanged)
self.resultsTable.addSubview(refresher)
}
func refresh() {
print("refresh table")
refreshResults()
}
func refreshResults() {
followArray.removeAll(keepCapacity: false)
resultsNameArray.removeAll(keepCapacity: false)
resulltsImageFiles.removeAll(keepCapacity: false)
resultsTweetArray.removeAll(keepCapacity: false)
resultsLocationArray.removeAll(keepCapacity: false)
resultsHasImageArray.removeAll(keepCapacity: false)
resultsTweetImageFiles.removeAll(keepCapacity: false)
datetextfielArray.removeAll(keepCapacity: false)
let followQuery = PFQuery(className: "follow")
followQuery.whereKey("user", equalTo: PFUser.currentUser()!.username!)
followQuery.addDescendingOrder("createdAt")
let objects = followQuery.findObjects()
for object in objects! {
self.followArray.append(object.objectForKey("userToFollow") as! String)
}
let query:PFQuery = PFQuery(className: "tweets")
query.whereKey("userName", containedIn: followArray)
query.addDescendingOrder("createdAt")
query.findObjectsInBackgroundWithBlock {
(objects:[AnyObject]?, error:NSError?) -> Void in
if error == nil {
for object in objects! {
self.resultsNameArray.append(object.objectForKey("profileName") as! String)
self.resulltsImageFiles.append(object.objectForKey("photo") as! PFFile)
self.resultsTweetArray.append(object.objectForKey("tweet") as! String)
//resultsLocationArray
self.resultsLocationArray.append(object.objectForKey("tweetlocation") as! String)
self.resultsHasImageArray.append(object.objectForKey("hasImage") as! String)
self.resultsTweetImageFiles.append(object.objectForKey("tweetImage") as? PFFile)
self.datetextfielArray.append(object.objectForKey("datetextfield") as! String)
self.resultsTable.reloadData()
}
self.refresher.endRefreshing()
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(animated: Bool) {
self.navigationController?.navigationBarHidden = false
super.viewWillAppear(animated)
let nav = self.navigationController?.navigationBar
nav?.barStyle = UIBarStyle.Black
nav?.tintColor = UIColor.whiteColor()
nav?.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor()]
self.navigationItem.hidesBackButton = true
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// Return the number of sections.
return 1
}
override func viewDidAppear(animated: Bool) {
refreshResults()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return resultsNameArray.count
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if resultsHasImageArray[indexPath.row] == "yes" {
return self.view.frame.size.width + 130
} else {
return 130
}
}
//var theDtS = dtFormater.stringFromDate(self.dateArray[i])
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:mainCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! mainCell
cell.tweetImg.hidden = true
cell.locationTxt.text = self.resultsLocationArray[indexPath.row]
cell.profileLbl.text = self.resultsNameArray[indexPath.row]
cell.messageTxt.text = self.resultsTweetArray[indexPath.row]
cell.datetextfield.text = self.datetextfielArray[indexPath.row]
resulltsImageFiles[indexPath.row].getDataInBackgroundWithBlock {
(imageData:NSData?, error:NSError?) -> Void in
//resultsLocationArray
if error == nil {
let image = UIImage(data: imageData!)
cell.imgView.image = image
}
}
if resultsHasImageArray[indexPath.row] == "yes" {
let theWidth = view.frame.size.width
cell.tweetImg.frame = CGRectMake(0, 0, theWidth, theWidth)
cell.tweetImg.hidden = false
resultsTweetImageFiles[indexPath.row]?.getDataInBackgroundWithBlock({
(imageData:NSData?, error:NSError?) -> Void in
if error == nil {
let image = UIImage(data: imageData!)
cell.tweetImg.image = image
}
})
}
return cell
}
func tweetBtn_click() {
print("tweet pressed")
self.performSegueWithIdentifier("gotoTweetVCFromMainVC", sender: self)
}
func searchBtn_click() {
print("search pressed")
self.performSegueWithIdentifier("gotoUsersVCFromMainVC", sender: self)
}
}

UISearchBar not updating

I have a UIViewControllerand I added UITableViewController in it and I am adding search bar programmatically. I am able to print the result after searching on the console but when I click on the search bar the custom table cells are still populated and search doesn't update them at all.
I have print statement in the override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell to check if the search controller is active and it never prints that statement.
import UIKit
import Parse
class MasterViewController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {
#IBOutlet var mTableView: UITableView!
var detailViewController: DetailViewController? = nil
var objects = [AnyObject]()
var resultSearchController = UISearchController()
var filteredData : NSMutableArray = []
var sectionInTable : NSMutableArray = ["Grand Haven 9", "Holland 7"]
var movieTitle : NSMutableArray = ["The Hunger Game 2","Creed"]
var movieTimeSection1 : NSMutableArray = ["11:00am, 11:40, 12:10pm, 1:25, 2:30, 6:05, 6:55, 7:30, 9:05", "11:10am, 11:50, 12:20pm, 2:25, 3:30, 6:05, 6:55, 8:30, 10:05"]
var movieTimeSection2 = ["Title": "Martian", "Theatre": "Holland 7", "Time": "11:00am, 11:40, 12:10pm, 1:25, 2:30, 6:05, 6:55, 7:30, 9:05"]
var onlineMovieTitle : NSMutableArray = []
var movieSection1 : NSMutableArray = []
var movieSection2 : NSMutableArray = []
override func viewDidLoad() {
super.viewDidLoad()
print(movieSection1)
print(movieSection2)
self.tableView.separatorColor = UIColor.cloudsColor()
self.tableView.backgroundColor = UIColor.cloudsColor()
self.resultSearchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.delegate = self
controller.searchBar.sizeToFit()
controller.preferredStatusBarStyle() == UIStatusBarStyle.LightContent
controller.hidesNavigationBarDuringPresentation = false
self.mTableView.tableHeaderView = controller.searchBar
return controller
})()
//self.resultSearchController.searchBar.endEditing(true)
}
func updateSearchResultsForSearchController(searchController: UISearchController){
filteredData.removeAllObjects()
let searchPredicate = NSPredicate(format: "Title CONTAINS %#", searchController.searchBar.text!.uppercaseString)
let array = (movieSection1 as NSArray).filteredArrayUsingPredicate(searchPredicate)
let array2 = (movieSection2 as NSArray).filteredArrayUsingPredicate(searchPredicate)
//let array2 = (movieTimeSection1 as NSArray).filteredArrayUsingPredicate(searchPredicate)
filteredData.addObjectsFromArray(array)
filteredData.addObjectsFromArray(array2)
print(filteredData)
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.resultSearchController.searchBar.hidden = false
}
// MARK: - Segues
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetail" {
if let indexPath = self.tableView.indexPathForSelectedRow {
}
}
}
// MARK: - Table View
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var count : Int = 0
if (self.resultSearchController.active) {
return 2
}
else {
if section == 0 {
count = movieSection1.count
} else if section == 1 {
count = movieSection2.count
}
}
return count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : MainTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! MainTableViewCell
//Fancy Cells
var corners : UIRectCorner = UIRectCorner.AllCorners
if (tableView.numberOfRowsInSection(indexPath.section) == 1) {
corners = UIRectCorner.AllCorners
} else if (indexPath.row == 0) {
corners = UIRectCorner.TopLeft.union(UIRectCorner.TopRight)
} else if (indexPath.row == tableView.numberOfRowsInSection(indexPath.section) - 1) {
corners = UIRectCorner.BottomLeft.union(UIRectCorner.BottomRight)
}
cell.configureFlatCellWithColor(UIColor.greenSeaColor(), selectedColor: UIColor.cloudsColor(), roundingCorners: corners)
//Fancy Buttons
cell.cornerRadius = 7
if indexPath.row == 0 {
cell.trailorButton.addTarget(self, action: "openHunger:", forControlEvents: UIControlEvents.TouchUpInside)
}else if indexPath.row == 1{
cell.trailorButton.addTarget(self, action: "openCreed:", forControlEvents: UIControlEvents.TouchUpInside)
}
cell.trailorButton.layer.cornerRadius = 5
cell.trailorButton.tintColor = UIColor.whiteColor()
let movieNameStr = movieTitle[indexPath.row] as! String
cell.movieImage.image = UIImage(named: movieNameStr)
//Cell Data Insertion
if (self.resultSearchController.active){
print("search ---------------")
cell.movieName.text = filteredData[indexPath.row].valueForKey("Title") as? String
cell.movieDetail.text = filteredData[indexPath.row].valueForKey("Time") as? String
return cell
}else {
print("cell")
if indexPath.section == 0 {
cell.movieName.text = movieSection1[indexPath.row].valueForKey("Title") as? String
cell.movieDetail.text = movieSection1[indexPath.row].valueForKey("Time") as? String
} else if indexPath.section == 1 {
cell.movieName.text = movieSection2[indexPath.row].valueForKey("Title") as? String
cell.movieDetail.text = movieSection2[indexPath.row].valueForKey("Time") as? String
}
return cell
}
//return cell
}
#IBAction func openHunger(sender: AnyObject) {
UIApplication.sharedApplication().openURL(NSURL(string: "https://youtu.be/n-7K_OjsDCQ")!)
}
#IBAction func openCreed(sender: AnyObject) {
UIApplication.sharedApplication().openURL(NSURL(string: "https://youtu.be/fCBzWLVQgk8")!)
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sectionInTable[section] as? String
}
}
Any help will be highly appreciated. Thanks
I missed it and thanks to Larcerax the problem was solved by adding mTableView.reloadData()

Resources