Swift3 SearchBar Tutorial with TableView Sections - ios

Does somebody have a good Tutorial for a Search Bar with Sections? I did not found a good one yet. Or maybe you can help me straight with my project!?
The section Title is static but i integrated some customized subtitles to show the regions and the total time i spend to make all this Locations(Liegenschaften) in this section. I create this values in the function createWinterdienstDetail. This values should not change when i search for one Location.
I get the Values for my tableview from a different ViewController as
var AllWinterdienstTourInfos: [Int:[Int:[String]]] = [:] // Section - Locationnumber - Locationinformations
Here is my ViewController File:
import UIKit
class WinterdienstTourVC: UIViewController {
var sections = ["Tour 1","Tour 2","Tour 3","Tour 4"]
var LiegenschaftDetail: [String] = []
// VARIABLEN WINTERDIENST
var WinterdienstregionTour1: [String] = []
...
var WinterdienstregionTour15: [String] = []
var WinterdienstaufwandTour1String: [String] = []
...
var WinterdienstaufwandTour15String: [String] = []
var WinterdienstaufwandTour1: [Double] = []
...
var WinterdienstaufwandTour15: [Double] = []
var Totaltouraufwand1 = Double()
...
var Totaltouraufwand15 = Double()
var AllWinterdienstTourInfos: [Int:[Int:[String]]] = [:]
// Initialisierung
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
createWinterdienstDetail()
tableView.delegate = self
tableView.dataSource = self
tableView.tableFooterView = UIView(frame: CGRect.zero)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "WinterdienstDetailSegue1") {
let DetailviewController = segue.destination as! WinterdienstLiegenschaftDetailVC
DetailviewController.LiegenschaftDetail = LiegenschaftDetail
}
}
func createWinterdienstDetail() {
if let liegenschaftenTour1 = AllWinterdienstTourInfos[0],
let liegenschaftenTour2 = AllWinterdienstTourInfos[1],
let liegenschaftenTour3 = AllWinterdienstTourInfos[2],
let liegenschaftenTour4 = AllWinterdienstTourInfos[3]{
self.myGroup.enter()
// DETAILS TOUR 1
for liegenschaften in liegenschaftenTour1.keys {
WinterdienstregionTour1.append(AllWinterdienstTourInfos[0]![liegenschaften]![6])
WinterdienstaufwandTour1String.append(AllWinterdienstTourInfos[0]![liegenschaften]![15])
for i in 0 ..< WinterdienstregionTour1.count-1 {
var j = WinterdienstregionTour1.count - 1
while(j > i) {
if WinterdienstregionTour1[i] == WinterdienstregionTour1[j] {
WinterdienstregionTour1.remove(at: j)
}
j -= 1
}
}
}
for WinterdienstaufwandTour1Array in WinterdienstaufwandTour1String {
WinterdienstaufwandTour1.append((WinterdienstaufwandTour1Array as NSString).doubleValue)
}
Totaltouraufwand1 = WinterdienstaufwandTour1.reduce(0,+)
// DETAILS TOUR 2
// DETAILS TOUR 3
// DETAILS TOUR 4
self.myGroup.leave()
self.myGroup.notify(queue: .main) {}
DispatchQueue.main.async {}
} // ENDE Function Create Winterdienst
} // ENDE CLASS WinterdienstTourVC
// DataSource-Methoden
extension WinterdienstTourVC: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int
{
return sections.count
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView()
// SECTION HEADER ALLGEMEIN
view.backgroundColor = UIColor.lightGray
// SECTION HEADER TOUR - NR
let tournr = UILabel()
tournr.text = sections[section]
tournr.font = UIFont.boldSystemFont(ofSize: 20.0)
tournr.frame = CGRect(x: 15,y:0, width: 100, height: 30)
view.addSubview(tournr)
// SECTION HEADER - TOURREGION / TOURAUFWAND
let tourregion = UILabel()
WinterdienstregionTour1.sort()
WinterdienstregionTour1.sort()
WinterdienstregionTour3.sort()
WinterdienstregionTour4.sort()
switch section{
case 0:
let tourregion1 = WinterdienstregionTour1.joined(separator: ", ")
tourregion.text = "\(tourregion1)"
case 1:
let tourregion2 = WinterdienstregionTour2.joined(separator: ", ")
tourregion.text = "\(tourregion2)"
.....
default:
tourregion.text = "Keine Angaben"
}
tourregion.font = UIFont.systemFont(ofSize: 16)
tourregion.frame = CGRect(x: 15,y:22, width: 200, height: 30)
view.addSubview(tourregion)
let touraufwand = UILabel()
switch section{
case 0:
touraufwand.text = "\(Totaltouraufwand1) h"
case 1:
touraufwand.text = "\(Totaltouraufwand2) h"
....
default:
touraufwand.text = "Keine Angaben"
}
touraufwand.frame = CGRect(x: -5,y:12, width: 370, height: 30)
touraufwand.font = UIFont.boldSystemFont(ofSize: 22.0)
touraufwand.textAlignment = .right
view.addSubview(touraufwand)
return view
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int
{
switch section{
case 0:
return self.AllWinterdienstTourInfos[0]!.count
// self.WinterdienstadressTourAll[0]!.count
case 1:
return self.AllWinterdienstTourInfos[1]!.count
//self.WinterdienstAlltourinfosAll[1]![section]!.count
....
default:
return 1
}
}
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath)
-> UITableViewCell
{
// versuchen, eine Zelle wiederzuverwenden
var cell = tableView.dequeueReusableCell(
withIdentifier: "cell")
if cell == nil {
// nicht möglich, daher neue Zelle erzeugen
cell = UITableViewCell(
style: .default, reuseIdentifier: "cell")
}
// Eigenschaften der Zelle einstellen
cell!.textLabel!.text = AllWinterdienstTourInfos[indexPath.section]![indexPath.row]?[4]
cell!.textLabel!.adjustsFontSizeToFitWidth = true
cell!.textLabel!.textAlignment = .left
// Zelle zurückgeben
return cell!
}
}
// TableView-Delegates
extension WinterdienstTourVC: UITableViewDelegate {
func tableView(_ tableView: UITableView,
didSelectRowAt indexPath: IndexPath)
{
LiegenschaftDetail = AllWinterdienstTourInfos[indexPath.section]![indexPath.row]!
performSegue(withIdentifier: "WinterdienstDetailSegue1", sender: self)
}
}

Related

TableView Collapse, why it's sticking up like this?

I'm setting up a collapsable tableView, but something strange happens on the collapsable item. When you look at the video keep an eye on the "Where are you located" line.. (I'm using a .plist for the question and answer items)
Where do I go wrong, is it somewhere in my code? I don't want to let that line stick on the top :(
Here is the code I'm using but I can't find anything strange...
class FAQViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var questionsArray = [String]()
var answersDict = Dictionary<String, [String]>() // multiple answers for a question
var collapsedArray = [Bool]()
#IBOutlet weak var tableView: UITableView!
override func viewWillAppear(_ animated: Bool) {
// Hide the navigation bar on the this view controller
self.navigationController?.setNavigationBarHidden(true, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
addTableStyles()
readQAFile()
tableView.delegate = self
tableView.dataSource = self
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
func addTableStyles(){
navigationController?.isNavigationBarHidden = false
self.tableView?.backgroundView = {
let view = UIView(frame: self.tableView.bounds)
return view
}()
tableView.estimatedRowHeight = 43.0;
tableView.rowHeight = UITableView.automaticDimension
tableView.separatorStyle = UITableViewCell.SeparatorStyle.singleLine
}
func readQAFile(){
guard let url = Bundle.main.url(forResource: "QA", withExtension: "plist")
else { print("no QAFile found")
return
}
let QAFileData = try! Data(contentsOf: url)
let dict = try! PropertyListSerialization.propertyList(from: QAFileData, format: nil) as! Dictionary<String, Any>
// Read the questions and answers from the plist
questionsArray = dict["Questions"] as! [String]
answersDict = dict["Answers"] as! Dictionary<String, [String]>
// Initially collapse every question
for _ in 0..<questionsArray.count {
collapsedArray.append(false)
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return questionsArray.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
if collapsedArray[section] {
let ansCount = answersDict[String(section)]!
return ansCount.count
}
return 0
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
// Set it to any number
return 70
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 1
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if collapsedArray[indexPath.section] {
return UITableView.automaticDimension
}
return 2
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView(frame: CGRect(x:0, y:0, width:tableView.frame.size.width, height:40))
headerView.tag = section
let headerString = UILabel(frame: CGRect(x: 10, y: 10, width: tableView.frame.size.width, height: 50)) as UILabel
headerString.text = "\(questionsArray[section])"
headerView .addSubview(headerString)
let headerTapped = UITapGestureRecognizer (target: self, action:#selector(sectionHeaderTapped(_:)))
headerView.addGestureRecognizer(headerTapped)
return headerView
}
#objc func sectionHeaderTapped(_ recognizer: UITapGestureRecognizer) {
let indexPath : IndexPath = IndexPath(row: 0, section:recognizer.view!.tag)
if (indexPath.row == 0) {
let collapsed = collapsedArray[indexPath.section]
collapsedArray[indexPath.section] = !collapsed
//reload specific section animated
let range = Range(NSRange(location: indexPath.section, length: 1))!
let sectionToReload = IndexSet(integersIn: range)
self.tableView.reloadSections(sectionToReload as IndexSet, with:UITableView.RowAnimation.fade)
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cellIdentifier = "Cell"
let cell: UITableViewCell! = self.tableView.dequeueReusableCell(withIdentifier: cellIdentifier)
cell.textLabel?.adjustsFontSizeToFitWidth = true
cell.textLabel?.numberOfLines = 0
let manyCells : Bool = collapsedArray[indexPath.section]
if (manyCells) {
let content = answersDict[String(indexPath.section)]
cell.textLabel?.text = content![indexPath.row]
}
return cell
}
override var prefersStatusBarHidden: Bool {
return true
}
}
You need to change the style of the tableView to grouped, when you initialize it:
let tableView = UITableView(frame: someFrame, style: .grouped)
or from Storyboard:
After that you will have this issue, which I solved by setting a tableHeaderView to the tableView that has CGFloat.leastNormalMagnitude as its height:
override func viewDidLoad() {
super.viewDidLoad()
var frame = CGRect.zero
frame.size.height = .leastNormalMagnitude
tableView.tableHeaderView = UIView(frame: frame)
}
Just remove your headerView from view hierarchy here
#objc func sectionHeaderTapped(_ recognizer: UITapGestureRecognizer) {
headerView.removeFromSuperview()
...
}
By the way, yes creating a openable tableview menu with using plist is one of the methods but it could be more simple. In my opinion you should refactor your code.

tableview last section is scrambled when setting row height to 0 swift

I added an arrow to fold the section when clicked, when I fold the last section (e.g. setting the row height to 0 in cellForRow, all the rows in the last section get mixed up, as can be seen in the image below:
Can anyone suggest any reason why this should happen if I'm setting the height of the row to 0?
Here's the relevant code:
viewForHeaderInSection:
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section == 0 {
let profileCompletion = clientFields?.profileCompletion ?? 0
headerView.profileComplete.text = "Profile".localized() + " \(profileCompletion)% " + "Complete".localized()
headerView.profileProgress.progress = Float(profileCompletion) * 0.01
headerView.profileProgress.progressTintColor = Constants.Client.getProfileCompletenessColor(profileCompletion)
headerView.delegate = self
headerView.section = section
headerView.isOpen = self.sectionsStatuses[section].shouldDisplaySection
return headerView
}
else {
let height = (section == 0) ? FIRST_HEADER_HEIGHT : HEADER_HEIGHT
let nib = UINib(nibName: "ClientDetailsSectionHeaderCell", bundle: nil)
guard let returnedView = nib.instantiate(withOwner: self, options: nil)[0] as? ClientDetailsSectionHeaderCell else {
return UIView()
}
returnedView.delegate = self
returnedView.section = section
returnedView.isOpen = self.sectionsStatuses[section].shouldDisplaySection
returnedView.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: height)
returnedView.heightConstraint.constant = height
returnedView.mainView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
returnedView.mainView.backgroundColor = Constants.ParentForm.headerBgColor
// Draw separators
if DRAW_SECTION_SEPARATORS || DRAW_SECTION_TOP_SEPARATOR {
returnedView.createTopSeparator(color: Constants.ParentForm.separatorColor)
}
if DRAW_SECTION_SEPARATORS || DRAW_SECTION_BOTTOM_SEPARATOR {
returnedView.createBottomSeparator(color: Constants.ParentForm.separatorColor)
}
if isSectionTitleHidden == false {
let xOffset = HEADER_X_OFFSET
let yOffset = section == 0 ? FIRST_HEADER_Y_OFFSET : HEADER_Y_OFFSET
returnedView.title.frame = CGRect(x: xOffset, y: yOffset, width: view.frame.size.width - xOffset, height: height - yOffset)
returnedView.title.text = self.sectionsArray[section].uppercased().localized()
returnedView.title.font = Constants.ParentForm.headerFont
returnedView.title.textColor = Constants.ParentForm.headerTextColor
returnedView.title.sizeToFit()
}
return returnedView
}
}
heightForRow
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if sectionsStatuses[indexPath.section].shouldDisplaySection {
return super.tableView(tableView, heightForRowAt: indexPath)
}
return CGFloat(0)
}
cellForRow
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if self.sectionsArray[indexPath.section] != "ADDRESSES" {
if let clientFields = self.clientFields {
self.dataMap = Utils.convertObjectToMap(item: clientFields)
let birthdayDate = clientFields.birthdayDateString
self.dataMap["birthdayDate"] = birthdayDate
let createdDate = clientFields.createdDateString
self.dataMap["createdDate"] = createdDate
}
}
else {
if let clientAddresses = self.clientAddresses, clientAddresses.count > 0 {
self.dataMap = Utils.convertObjectToMap(item: clientAddresses[Int(floor(Double(indexPath.row) / 8.0))])
}
}
return super.tableView(tableView, cellForRowAt: indexPath)
}
protocol function
func openCloseSection(openSection: Bool, section: Int) {
self.sectionsStatuses[section].shouldDisplaySection = openSection
self.tableView.reloadData()
}
ClientDetailsSectionHeaderCell
import UIKit
protocol SectionViewerProtocol {
func openCloseSection(openSection: Bool, section: Int)
}
class ClientDetailsSectionHeaderCell: UITableViewCell {
#IBOutlet weak var mainView: UIView!
#IBOutlet weak var heightConstraint: NSLayoutConstraint!
#IBOutlet weak var accessoryButton: UIButton!
#IBOutlet weak var title: UILabel!
var section = 0
var delegate: SectionViewerProtocol?
var isOpen: Bool? {
didSet {
if let isOpen = self.isOpen {
accessoryButton.setImage(UIImage(named: isOpen ? "fill588": "fill589"), for: .normal)
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
}
#IBAction func openCloseSection(_ sender: UIButton) {
if let isOpen = self.isOpen {
self.isOpen = !isOpen
delegate?.openCloseSection(openSection: !isOpen, section: section)
}
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
Try setting clipsToBounds of your cell or any enclosing UIView to true.

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)
}
}

iOS swift - insert second element in tableview

i have a textfield, when the user tap on it, a table1 appear with a list of countries currency, then the user choose a currency and add it to table2, i can add one currency , when i add another one to table2 the app crash with the following error: Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'request for rect at invalid index path ( {length = 2, path = 0 - 1})'
class CurrencySecondStep: UIViewController ,UITableViewDataSource, UITableViewDelegate,UITextFieldDelegate {
#IBOutlet weak var tableViewAddedByUser: UITableView!
#IBOutlet weak var amountToBeExchanged: UILabel!
#IBOutlet weak var tableViewFor: UITableView!
#IBOutlet weak var textFieldFor: UITextField!
//cell identifier
let cellReuseIdentifier = "cell"
//struct
struct Currency {
var country = String()
var currencyCode = String()
var currencyFlag = UIImage()
}
var addedCurrencyByUserArray = [Currency]()
var currencyArr = [
Currency(country: "United Arab Emirates Dirham", currencyCode: "AED",currencyFlag: UIImage(named:"United-Arab-Emirates")!),
Currency(country: "US Dollar", currencyCode: "USD",currencyFlag: UIImage(named:"United-States")!),
Currency(country: "Afghan Afghani (1927–2002)", currencyCode: "AFA",currencyFlag: UIImage(named:"Afghanistan")!),
Currency(country: "Albania Lek", currencyCode: "ALL",currencyFlag: UIImage(named:"Albania")!),
Currency(country: "Algerian Dinar", currencyCode: "DZD",currencyFlag: UIImage(named:"Algeria")!),
Currency(country: "Angolan Kwanza", currencyCode: "AOA",currencyFlag: UIImage(named:"Angola")!),
Currency(country: "Argentine Peso", currencyCode: "ARS",currencyFlag: UIImage(named:"Argentina")!),
Currency(country: "Armenian Dram", currencyCode: "AMD",currencyFlag: UIImage(named:"Armenia")!)
]
//searched results
var filteredCurrenciesOffer = [Currency]()
//currency code to be sent to google finance
var currencyCodeOffer = ""
var currencyPassed = ""
var countryChoice = ""
var countryCodeChoice = ""
var countryflagChoice = UIImage()
#IBAction func textFieldChanged(_ sender: AnyObject) {
tableViewFor.isHidden = true
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableViewFor.delegate = self
tableViewFor.dataSource = self
tableViewFor.isHidden = true
textFieldFor.delegate = self
textFieldFor.addTarget(self, action: #selector(textFieldActive), for: UIControlEvents.touchDown)
textFieldFor.addTarget(self, action:#selector(textFieldDidChange) , for: UIControlEvents.editingChanged)
//hide or show keyboard
textFieldFor.addTarget(self, action: #selector(textFieldShouldReturn), for: UIControlEvents.touchDown)
amountToBeExchanged.text = currencyPassed
//table added By User
tableViewAddedByUser.delegate = self
tableViewAddedByUser.dataSource = self
tableViewAddedByUser.isHidden = true
}
when the user press add Button to insert the second element the app crash
#IBAction func addPressed(_ sender: Any) {
if(textFieldFor.text == ""){
displayError(title: "Currency Type",message:"Please Pick Your Currency")
}else{
tableViewAddedByUser.isHidden = false
addedCurrencyByUserArray.append(Currency(country: countryChoice, currencyCode: countryCodeChoice,currencyFlag: countryflagChoice))
tableViewAddedByUser.beginUpdates()
let insert = IndexPath(row: addedCurrencyByUserArray.count - 1, section: 0)
tableViewAddedByUser.insertRows(at: [insert], with: .automatic)
tableViewAddedByUser.endUpdates()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: TextField Functions
func textFieldDidEndEditing(_ textField: UITextField) {
filteredCurrenciesOffer = currencyArr.filter { currencyGiven in
return currencyGiven.country.lowercased().contains(textFieldFor.text!.lowercased())
}
//reload table based on the user pick
tableViewFor.reloadData()
}
func textFieldDidChange(textField: UITextField) {
//update search based on user search
filteredCurrenciesOffer = currencyArr.filter { currencyGiven in
return currencyGiven.country.lowercased().contains(textFieldFor.text!.lowercased())
}
tableViewFor.reloadData()
}
// Toggle the tableView visibility when click on textField
func textFieldActive(textField: UITextField) {
tableViewFor.isHidden = !tableViewFor.isHidden
}
//hide keyboard
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
// MARK: TableView Functions
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var count:Int?
if (tableView == self.tableViewFor && textFieldFor.text != ""){
count = filteredCurrenciesOffer.count
}else if(tableView == self.tableViewFor && textFieldFor.text == ""){
count = currencyArr.count
}
if(tableView == self.tableViewAddedByUser){
count = addedCurrencyByUserArray.count
print("number of rows")
print(count!)
}
return count!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableViewFor.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomCell
var currency: Currency
if (tableView == self.tableViewFor){
if ( textFieldFor.text != "") {
currency = filteredCurrenciesOffer[indexPath.row]
} else {
currency = currencyArr[indexPath.row]
}
cell.flag.image = currency.currencyFlag
cell.country.text = currency.country
cell.currencyCode.text = currency.currencyCode
}
if (tableView == self.tableViewAddedByUser){
currency = addedCurrencyByUserArray[indexPath.row]
cell.flag.image = currency.currencyFlag
cell.country.text = currency.country
cell.currencyCode.text = currency.currencyCode
}
return cell
}
// MARK: UITableViewDelegate
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
var currency: Currency
if(tableView == tableViewFor){
if textFieldFor.text != "" {
currency = filteredCurrenciesOffer[indexPath.row]
} else {
currency = currencyArr[indexPath.row]
}
//add image to currency text field
let leftImageView = UIImageView()
leftImageView.image = currency.currencyFlag
let leftView = UIView()
leftView.addSubview(leftImageView)
leftView.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
leftImageView.frame = CGRect(x: 10, y: 10, width: 20, height: 20)
textFieldFor.leftViewMode = .always
textFieldFor.leftView = leftView
//add country to currency text field
textFieldFor.text = currency.country
countryChoice = currency.country
countryCodeChoice = currency.currencyCode
countryflagChoice = currency.currencyFlag
currencyCodeOffer = currency.currencyCode
tableViewFor.isHidden = true
textFieldFor.endEditing(true)
}
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 0.0
}
//hide the table and keyboard
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
{
guard let touch:UITouch = touches.first else
{
return;
}
if touch.view != tableViewFor
{
textFieldFor.endEditing(true)
tableViewFor.isHidden = true
}
}
func displayError(title:String,message:String){
// Create the alert controller
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
// Create the actions
let retryButton = UIAlertAction(title: "Ok", style: UIAlertActionStyle.cancel) {
UIAlertAction in
NSLog("Cancel Pressed")
}
// Add the actions
alertController.addAction(retryButton)
}
}
I think the problem happens in your
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
On the first line you always dequeue a cell from the tableViewFor even when you need a cell for tableViewAddedByUser.
Try replacing the first line with this which will dequeue a cell from the tableView sent in the parameters instead:
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomCell
If that doesn't work then try without specifying the indexPath like so:
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! CustomCell

Don't know how to fill expandable table view with dictionary

I have an expandable table view and fill it with static arrays and that works fine, But if I want to fill this table with NSDictionary or NSarrays, then what should I do !?
This is my first time with expandable table view so please guide me.
Here is my entire code:
import UIKit
class MenuViewController: UIViewController, UITableViewDataSource{
#IBOutlet weak var expandTableView: UITableView!
var expandedSections : NSMutableSet = []
var sectionData : [String] = ["Vegs ", "Fruits ", "Birds ", "Reptiles "]
var row1 = ["Tomato", "Onion", "Potato", "Pumpkin", "Babycorn", "Cucumber", "Carrot", "Beans", "Cabbage", "Corn", "EggPlant", "Pea", "Sweet Potato"]
var row2 = ["Mango", "Orange", "Watermelon", "Apple", "Apricot", "Banana", "Papaya", "Pineapple", "Melon", "Avocado", "Cherry", "Date", "Fig", "Grape", "Guava", "Kiwi", "Olive", "Pear"]
var row3 = ["Parrot", "Peacock", "Woodpecker", "Kingfisher", "Owl", "Eagle", "Pigeon", "Vulture", "Bats", "Nightingale", "Crow"]
var row4 = ["Lizard", "Crocodile", "Snake", "Turtle", "Dinosaur"]
func sectionTapped(_ sender: UIButton) {
let section = sender.tag
let shouldExpand = !expandedSections.contains(section)
if (shouldExpand) {
expandedSections.removeAllObjects()
expandedSections.add(section)
} else {
expandedSections.removeAllObjects()
}
self.expandTableView.reloadData()
}
} // end of class
extension MenuViewController: UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return sectionData.count
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView.init(frame: CGRect(x: 0, y: 0, width: 300, height: 28))
var imageView = UIImageView()
let headerTitle = UILabel.init(frame: CGRect(x: 38, y: 4, width: 250, height: 28))
headerTitle.text = sectionData[section]
headerTitle.textAlignment = .right
let tappedSection = UIButton.init(frame: CGRect(x: 0, y: 0, width: headerView.frame.size.width, height: headerView.frame.size.height))
tappedSection.addTarget(self, action: #selector(sectionTapped), for: .touchUpInside)
tappedSection.tag = section
headerView.addSubview(imageView)
headerView.addSubview(headerTitle)
headerView.addSubview(tappedSection)
headerView.tintColor = UIColor.white
return headerView
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 44
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(expandedSections.contains(section)) {
switch section {
case 0:
return row1.count
case 1:
return row2.count
case 2:
return row3.count
default:
return row4.count
}
} else {
return 0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "cell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)
cell?.textLabel?.textAlignment = .right
switch indexPath.section {
case 0:
cell?.textLabel?.text = row1[indexPath.row]
case 1:
cell?.textLabel?.text = row2[indexPath.row]
case 2:
cell?.textLabel?.text = row3[indexPath.row]
default:
cell?.textLabel?.text = row4[indexPath.row]
}
return cell!;
}
}
Here are my new values:
var expandedSections : NSMutableSet = []
var categoryLevel1 = [Category]()
var categoryLevel2 = [[Category]]()

Resources