I have a table view with a tap gesture recognizer inside of it and when I double click on the cell, I wanted to pass data from the cell to another view controller. Now it works only once and doesnt update the string in the view controller. The string remains permanent. Now I need help updating the string so that when I try to double tap another cell, the string will update instead of only work once by keeping the value of the string in the view controller constant with that of the first cell tapped. Here is my code.
Code in tableview for double tap gesture recognizer.
func CellTappedTwice(sender: UITapGestureRecognizer!) {
if let index = sender.view?.tag{
if let object = objects?[index]{
if let objectId = object.objectId{
popupViewController.objectId = objectId
}
}
}
self.present(popupViewController, animated: true, completion: nil)
}
Code in view controller:
var objectId : String?
#IBOutlet weak var QrCode: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
if let object = objectId {
let qrcode = DCQRCode(info: object, size: CGSize(width: 170, height: 170))
qrcode.positionStyle = [
(UIImage(named: "RedOuterPosition")!, DCQRCodePosition.topRight),
(UIImage(named: "RedOuterPosition")!, DCQRCodePosition.topLeft),
(UIImage(named: "RedOuterPosition")!, DCQRCodePosition.bottomLeft)
]
qrcode.maskImage = UIImage(named: "RedColors")
QrCode.image = qrcode.image()
print("hello\(objectId)")
}
}
Move the code that handles objectId to your viewWillAppear(_:) method, not viewDidLoad. The viewDidLoad method only gets called once during the life of a view controller, so if you're using the same view controller over and over, you'll only every process objectId the first time it's displayed.
Related
I have a segue named "hydrogenSegue" from a "hydrogenBoxButton" to a "Hydrogen" view controller. However, I also wanted to implement a table view so I could search for an element. I tried to make the code so when the cell is clicked it will segue over to the element's view. I used hydrogen as an example here.
In my main ViewController.swift file, I have this to transfer the data:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//If identifier equals the hydrogen element go to the elements Swift file
if segue.identifier == "hydrogenSegue" {
let hydrogenAtomicNumberPassing = segue.destination as! hydrogenViewController
hydrogenAtomicNumberPassing.hydrogenAtomicNumberPassed = hydrogenAtomicNumber
let hydrogenAtomicMassPassing = segue.destination as! hydrogenViewController
hydrogenAtomicMassPassing.hydrogenAtomicMassPassed = hydrogenAtomicMass
}
}
In the hydrogenViewController.swift file I have this:
import UIKit
class hydrogenViewController: UIViewController {
var hydrogenAtomicNumberPassed: Int!
var hydrogenAtomicMassPassed: Float!
#IBOutlet weak var hydrogenInformationLabel: UILabel!
#IBOutlet weak var hydrogenAtomicNumberLabel: UILabel!
#IBOutlet weak var hydrogenAtomicMassLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
//Setting the background color
self.view.backgroundColor = UIColor.gray
//Converting hydrogen's atomic number from an Int to a String
let hydrogenAtomicNumberString = String("\(hydrogenAtomicNumberPassed!)")
hydrogenAtomicNumberLabel.text = "Atomic Number: \(hydrogenAtomicNumberString)"
//Converting hydrogen's atomic mass from a Float to a String
let hydrogenAtomicMassString = String("\(hydrogenAtomicMassPassed!)")
hydrogenAtomicMassLabel.text = "Atomic Mass: \(hydrogenAtomicMassString)"
}
}
I am getting the error at:
let hydrogenAtomicNumberString = String("\(hydrogenAtomicNumberPassed!)")
I'm assuming it would happen to this line also if I fix only that line:
let hydrogenAtomicMassString = String("\(hydrogenAtomicMassPassed!)")
I have this code in my "searchViewController" (the .swift file used for the table view):
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("row selected : \(indexPath.row)")
if indexPath.row == 0 {
let hydrogenSearchSegue = UIStoryboard(name:"Main",
bundle:nil).instantiateViewController(withIdentifier: "hydrogenView") as!
hydrogenViewController
self.navigationController?.pushViewController(hydrogenSearchSegue,
animated:true)
}
}
When I click on the "Hydrogen" cell in the table view it crashes to this error:
Hydrogen cell
The crash
When I click on the "H" button in this image it will take me to the hydrogen view controller:
Image of the Hydrogen Button in the simulator (Top Left)
Image of the Hydrogen View Controller
I want the hydrogen cell to segue over to the hydrogen view controller just like the button can.
When this same issue came up earlier I just had an issue with the name of the segue in the storyboard. However, because there is no visible segue from the table view, I don't know how to fix the issue.
I've tried this:
performSegue(withIdentifier: "hydrogenSegue", sender: nil)
I was thinking that I could just reuse the "hydrogenSegue" from the button to the view controller but I get a SIGABRT error. It just says that there is no segue with the name "hydrogenSegue." It would be best if I could just reuse that segue in a way because everything is already connected but I now found out that the "searchViewController" can't recognize the segue. Any help is appreciated and my main goal is to just get the cell that is clicked on to move over to the element's designated view. I tried to provide as much information as possible without making it to long and if there is any more information needed, I should be able to provide it.
well. first answer
in your hydrogenViewController try with this lines.
var hydrogenAtomicNumberPassed: Int?
var hydrogenAtomicMassPassed: Float?
override func viewDidLoad(){
super.viewDidLoad()
self.viewBackgroundColor = .gray
}
override func viewWillAppear(){
super.viewWillAppear()
if let number = hydrogenAtomicNumberPassed
{
hydrogenAtomicNumberLabel.text = "Atomic Number: \(number)"
}
if let mass = hydrogenAtomicMassPassed
{
hydrogenAtomicMassLabel.text = "Atomic Mass: \(mass)"
}
}
Now, the segues only "lives" between a couple viewControllers, if you have a third view controller, the last will not recognize him.
other thing, you are using segues and navigation controller, from my point of view, it's a bad idea mixed both, I mean, there are specific apps that can use both ways to present views, only is a advice.
if you want to pass data with pushviewcontroller only use this line
if indexPath.row == 0 {
let hydrogenSearchSegue = UIStoryboard(name:"Main",bundle:nil).instantiateViewController(withIdentifier: "hydrogenView") as! hydrogenViewController
hydrogenSearchSegue.VAR_hydrogenViewController = YOURVAR_INYOURFILE
self.navigationController?.pushViewController(hydrogenSearchSegue, animated:true)
}
tell me if you have doubts, and I will try to help you.
I have tried looking at answers on similar questions to this, but I am not particularly experienced and have had trouble following them, so any help would be much appreciated! My situation is as follows: when I press a button in my Parent ViewController, the following code is used to call a Child ViewController (by the way, the Child is actually a TableViewController, but it seems to work fine "thinking" it's a normal ViewController?):
controller = (storyboard?.instantiateViewController(withIdentifier: "People"))
addChildViewController(controller!)
controller?.view.frame = CGRect(x: 10, y: 200, width: 394, height: 300)
self.view.addSubview((controller?.view)!)
controller?.didMove(toParentViewController: self)
What I would then like is to transfer an array from the Parent to the Child, where it will be used as the TableView's data?
Secondly, when I select a cell from the Child's TableView, I would like the relevant information to be sent to the Parent, and for the Child to disappear.
In case it is of interest, I have managed to close the Child under different circumstances (when a click occurs in the Parent while the Child is displayed) using the following:
controller?.willMove(toParentViewController: nil)
controller?.view.removeFromSuperview()
controller?.removeFromParentViewController()
I would really appreciate any advice, even if it's a link to something which would help!
You can pass value from Parent to Child Controller like this
controller = (storyboard?.instantiateViewController(withIdentifier: "People"))
addChildViewController(controller!)
controller?.view.frame = CGRect(x: 10, y: 200, width: 394, height: 300)
controller.tableDataSource = // Pass your required value to child controller
self.view.addSubview((controller?.view)!)
controller?.didMove(toParentViewController: self)
Now you want to transfer back your select value to Parent view controller. For this purpose your have a create a Delegate in ChildController like
#protocol ChildControllerDelegate : class {
func selectedValue(Value : String)
}
After that make a variable of that delegate in ChildController like this
weak var delegate : ChildControllerDelegate?
and when in rowDidSelect method add following code
if(delegate != nil) {
delegate.selectedValue(Value :"Your selected value")
}
Now step when you are going to show ChildController from ParentController at that time you have to set that delegate object to ParentController like this
controller = (storyboard?.instantiateViewController(withIdentifier: "People"))
addChildViewController(controller!)
controller?.view.frame = CGRect(x: 10, y: 200, width: 394, height: 300)
controller.delegate = self
self.view.addSubview((controller?.view)!)
controller?.didMove(toParentViewController: self)
and after that just implement the delegate method in ParentController like that
func selectedValue(Value : String) {
// you select val
}
Try This.
First Create Public Method For Add And Remove childVC.
For Add childVC.
public class func openChildViewController(parentVC:UIViewController, with childVC:UIViewController){
parentVC.addChildViewController(childVC)
childVC.view.frame = parentVC.view.frame
parentVC.view.addSubview(childVC.view)
parentVC.didMove(toParentViewController: childVC)
}
For Remove childVC.
public class func removeChildViewController(childVC:UIViewController){
childVC.willMove(toParentViewController: nil)
childVC.view.removeFromSuperview()
childVC.removeFromParentViewController()
}
Use Above Method.
1.ParentVC.swift
class ParentVC: UIViewController , ChildVCDelegate {
var arrType = NSMutableArray()
//add ChildVC
#IBAction func btnAddChildVC(_ sender: UIButton) {
let ChildVC = self.storyboard?.instantiateViewController(withIdentifier: "ChildVC") as! ChildVC
PickerVC.arrPass = arrType //for data passing create any object in ChildVC for ex. arrPass is NSMutableArray
ChildVC.delegate = self
openChildViewController(parentVC: self, with: ChildVC)
}
// MARK: ChildVC Delegate
func SetSelectedPickerValue(strSelectOption: String) {
print(strSelectOption)
}
}
}
2.ChildVC.swift
class ChildVC: UIViewController{
// MARK: Variable for ParentVCData Passing
var arrPass = NSMutableArray()
override func viewWillAppear(_ animated: Bool) {
print(arrPass)
}
//Remove ChildVC
#IBAction func btnRemoveChildVC(_ sender: UIButton) {
self.delegate?.SetSelectedPickerValue!(strSelectOption: “any String you pass ChildVC To ParentVC”)
removeChildViewController(childVC: self)
}
}
// MARK: Create Delegate Method
#objc protocol ChildVCDelegate{
#objc optional func SetSelectedPickerValue(strSelectOption:String)
}
You can:
Cast the controller to the appropriate class for the child view controller (I'm using ChildViewController below, but hopefully you have a more descriptive name); and
Pass the array (which I guessed you might have called people, but use whatever your array names are in these two respective view controllers) from the current view controller (the parent) to this new child view controller.
Thus:
let child = storyboard!.instantiateViewController(withIdentifier: "People") as! ChildViewController
addChildViewController(child)
child.people = people
child.view.frame = ...
view.addSubview(child.view)
child.didMove(toParentViewController: self)
Personally, I wouldn't hard code the child coordinates like you did in your original question. I'd set translatesAutoresizingMaskIntoConstraints to false and then add the appropriate leading/trailing/top/bottom constraints, but that's up to you. It was just too painful to see hardcoded coordinates in your example.
I'm trying to pass the content of a UIImage() variable to the Cell of the next View Controller.
Basically my layout looks like this:
An image is loaded in ControllerA and then saved in a model.
In the next controller, a TableViewCell is loaded.
I want the picture to load inside the cell.
How do I achieve this?
My code:
First part:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Save the poem.
savePoem()
}
func savePoem() {
// Save the poem current completion date.
poem.date = NSDate()
// Save the theme name for the poem.
poem.theme = theme.name
// Save the currently displayed picture.
poem.image = ImageView.image
poem.words = textField.words
// Make the poem object persist.
PoemPersistence.sharedInstance.persistPoem(poem)
}
The cell loads the pic:
func configureWithPoem(poem: Poem) {
themeLabel.text = "#\(poem.theme)"
poemLabel.text = poem.words
pictureImageView.image = poem.image
}
func capturePoemImage() -> UIImage {
// Hide the share button.
shareButton.hidden = true
// Capture a PNG of the view.
UIGraphicsBeginImageContextWithOptions(frame.size, false, 0)
layer.renderInContext(UIGraphicsGetCurrentContext()!)
let containerViewImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// Show the share button.
shareButton.hidden = false
return containerViewImage
}
cell gets loaded in second controller:
func poemCellWantsToSharePoem(poemCell: PoemCell) {
// Find the poem displayed at this index path.
let indexPath = tableView.mp_indexPathForCell(poemCell)
let poem = poems[indexPath.row]
// Generate the image of the poem.
let poemImage = poemCell.capturePoemImage()
if you want just you use prepareForSegue() to send data to the next UIViewController
- Create the segue to next controller (control + Drag), then give the identifier a name.
Now set up your destination controller by declaring
#IBOutlet weak var imageView:UIImageView!
var image:String ?
override func viewDidLoad()
{
imageView.image = image
}
this image variable will receive data then assigned it to the #IBOutlet.
func prepareForSegue (segue:UIStoryboardSegue, sender:AnyObject?)
{
if segue.identifier == "NAMEOFSEGUEIDENTIFIER"
{
let destinationController = segue.destinationViewController as! NAMEOFTHEDESTIONCONTROLLER
let indexPath = tableView.indexPathForSelectedRow!
// now the data structure that contains your information, use it there
let data = dataContainer[indexPath.row]
// i noticed that you might be using struct so
// let's passed the picture from that specific row to the next conroller
destinationController.image = data.image
}
}
I hope that helps :)
I just started with iOS programming and I could not find anywhere an answer about this.
I have a Textview, containing a large text divided in paragraphs.
I would like to trigger the reload of a Tableview whenever each paragraph reaches the middle of the TextView.
How could I do it?
Here is the code I wrote so far:
#IBOutlet weak var testo: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
if databaseDB.open() {
// Here I definethe string attributes
var style = NSMutableParagraphStyle()
style.lineSpacing = 15
let font = UIFont(name: "Georgia", size: 18.0) ?? UIFont.systemFontOfSize(18.0)
let textFont = [NSFontAttributeName:font, NSParagraphStyleAttributeName : style]
let fontSuper = UIFont(name: "Georgia-Italic", size: 13.0) ?? UIFont.systemFontOfSize(13.0)
let superFont = [NSFontAttributeName:fontSuper, NSBaselineOffsetAttributeName:6]
// and here the variables
let mainText = NSMutableAttributedString()
var paragraphId : String = ""
// I load the text from a table in the database
let querySQL = "SELECT id, versetext FROM table1"
let results:FMResultSet? = databaseDB.executeQuery(querySQL, withArgumentsInArray: nil)
while results!.next(){
paragraphId = results!.stringForColumn("id")
// I add some other information from another table (here goes also other code, but I have skipped it for simplicity)
let queryDescrSQL = "SELECT paragraph FROM table2 WHERE id = \(paragraphId)"
let paragraphResults:FMResultSet? = databaseDB.executeQuery(queryDescrSQL, withArgumentsInArray: nil)
if paragraphResults?.next() == true {
// here I add the attributes to the text to be shown
let numberParagraph = paragraphResults!.stringForColumn("paragraph")
let paragraphNumber = NSAttributedString(string: numberParagraph, attributes:superFont)
mainText.appendAttributedString(paragraphNumber)
let textParagraph = results!.stringForColumn("versetext")+" "
let paragraphText = NSAttributedString(string: textParagraph, attributes:textFont)
mainText.appendAttributedString(paragraphText)
}
}
databaseDB.close()
// and finally everything is loaded on the TextView
testo.attributedText = mainText
}
}
// I'm letting out the code for the TableView, as it is probably not relevant for the matter
I was thinking of adding some other attribute to paragraphNumber, something like here, but I haven't been able to find how to do it.
Thanks in advance,
Silvo
It's not clear how your paragraphs are divided up (is each in its own UITextView, or do they all form one large text view), but the basics of this are that you need to reload a table view when the scroll view reaches a certain scrolled position.
UITableView has a method reloadData, so call this when your scroll view is at the position.
Scrolling a scroll view just means you are modifying its contentOffset, and the scroll view sends its delegate a message every time the content offset changes. Make your controller the delegate of the scroll view, and implement the scrollViewDidScroll(_:) delegate method. In here, check the current content offset, and if it's at the value you're looking for, reload the table view:
class MyViewController: UIViewController, UIScrollViewDelegate {
// var scrollView = ...
// var tableView = ...
override viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
}
func scrollViewDidScroll(scrollView: UIScrollView) {
// var scrollThreshold = (calculate some scroll threshold based on your paragraph text)
if scrollView.contentOffset.y > scrollThreshold {
tableView.reloadData()
}
}
}
I am trying to capture the textLabel.text value of a cell in my tableView, and using nsuserdefaults, transferring it to another view. In this final view, a label should be updated with the captured value.
Here is my code from TableViewController.swift that captures the value:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
//actions that will proceed immediately a cell row is clicked
var cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? PFTableViewCell
//here I do the capture
let captureCellVals = NSUserDefaults.standardUserDefaults()
captureCellVals.setValue(cell?.textLabel?.text, forKey: "restoname")
//code that transitions to the final view
let view2 = self.storyboard?.instantiateViewControllerWithIdentifier("finalView") as IndividualViewController
self.navigationController?.pushViewController(view2, animated: true)
}
And this is the code in the final view that is supposed to set the label's text value:
override func viewDidLoad() {
super.viewDidLoad()
let values = NSUserDefaults.standardUserDefaults()
let resname = values.valueForKey("restoname")
Restaurant.text = resname as? String
// Do any additional setup after loading the view, typically from a nib.
}
#IBOutlet var Restaurant: UILabel!
But for some reason, when I run it in the simulator, it crashes. No error report or nothing. Just a crash. Any help would be appreciated, Thanks!
Try using the "??" nil coalescing operator to return an empty string in case you try to access it before storing any value to it:
Restaurant.text = NSUserDefaults().stringForKey("restoname") ?? ""
Note. NSUserDefaults has a specific method for loading your stored string called stringForKey()
So I figured it out.
It turns out that the problem was with the transition from the tableview to the final view. I needed to set the class for view2 as FinalView instead of IndividualViewController. Thanks nonetheless.