I have a list of PDF's embedded in my app. I would like to use webView to display one pdf at a time, selected from a table view controller. The example program, from Neil Smith, uses the webView to display web pages using the following code snippet from a detail view controller:
if let address = webSite {
let webURL = NSURL(string: address)
let urlRequest = NSURLRequest(URL: webURL!)
webView.loadRequest(urlRequest)
The following code snippet does what I want it to do, but only for the file "TestPDF"
if let pdf = NSBundle.mainBundle().URLForResource("TestPDF", withExtension: "pdf",
subdirectory: nil, localization: nil) {
let req = NSURLRequest(URL: pdf)
let webView = UIWebView(frame: CGRectMake(20,20,self.view.frame.size.width-40,self.view.frame.size.height-40))
webView.loadRequest(req)
self.view.addSubview(webView)
I would like to change this so that it selects a PDF from a list, for example:
pdfAddresses = [
"TestPDF.pdf",
"TestPDF2.pdf",
"TestPDF3.pdf",
"TestPDF4.pdf",
"testPDF5.pdf"]
The segue code works on the webAddress list just fine:
if segue.identifier == "ShowAttractionDetails" {
let detailViewController = segue.destinationViewController
as! AttractionDetailViewController
let myIndexPath = self.tableView.indexPathForSelectedRow()
let row = myIndexPath?.row
detailViewController.webSite = webAddresses[row!]
So what I don't know what to do is how to select the pdf file, based on the table view controller. I think I need to create a variable... but I'm not sure. Thank you for you suggestions.
Here is simple example for you:
TableViewController.swift
import UIKit
class TableViewController: UITableViewController {
//Your PDF list
var pdfAddresses = [
"TestPDF",
"TestPDF2",
"TestPDF3",
"TestPDF4"]
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return pdfAddresses.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell
// Configure the cell...
cell.textLabel?.text = pdfAddresses[indexPath.row] //Display PDF list in tableView
return cell
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ShowAttractionDetails" {
let detailViewController = segue.destinationViewController as! AttractionDetailViewController
let myIndexPath = self.tableView.indexPathForSelectedRow()
let row = myIndexPath?.row
//Pass selected cell title to next View
detailViewController.webSite = pdfAddresses[row!]
}
}
}
AttractionDetailViewController.swift
import UIKit
class AttractionDetailViewController: UIViewController {
//Outlet of webView but you can create it programatically too.
#IBOutlet weak var webView: UIWebView!
//This will hold data which is passed from first View
var webSite : String?
override func viewDidLoad() {
super.viewDidLoad()
//Load selected PDF into webView.
if let webSite = webSite {
println(webSite)
if let pdf = NSBundle.mainBundle().URLForResource(webSite, withExtension: "pdf", subdirectory: nil, localization: nil) {
let req = NSURLRequest(URL: pdf)
webView.loadRequest(req)
}
}
}
}
Check this SAMPLE project for more Info.
Related
I have a Segmented control with a UIView in it as shown below:
I have added two custom views inside UIView by the following code:
class NotificationViewController: UIViewController {
#IBOutlet weak var viewContainer: UIView!
//create a variable for view
var views : [UIView]!
override func viewDidLoad() {
super.viewDidLoad()
//initialize the view
views = [UIView]()
//appened the view inside the views array
views.append(ImportantNotification().view)
views.append(GeneralNotificaton().view)
//start the loop to add the subviews inside the view
for v in views{
viewContainer.addSubview(v)
}
//bring the default view to the front while we launch it
viewContainer.bringSubview(toFront: views[0])
}
#IBAction func notificationSegemntsPressed(_ sender: UISegmentedControl) {
//finally bring the subview inside the segmented view
self.viewContainer.bringSubview(toFront: views[sender.selectedSegmentIndex])
}
}
And it Works!
The sub views with its .xib file are as follows:
I have kept a UI Table view inside the first sub view as shown below:
And, I have made a custom cell for the first subview as shown below:
I loaded the Json data from api and wanted to show it in the table view with the custom cell and the JSON data successfully loads but it doesnot populate in the table view.
My code for loading the data in table view is shown below:
import UIKit
class ImportantNotification: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var importantNotificationTableView: UITableView!
var nontificatonData = [NotificationDataModel]()
override func viewDidLoad() {
super.viewDidLoad()
importantNotificationTableView.delegate = self
importantNotificationTableView.dataSource = self
let nib = UINib(nibName: "TableViewCell", bundle: nil)
importantNotificationTableView.register(nib, forCellReuseIdentifier: "customCell")
downloadJSON {
self.importantNotificationTableView.reloadData()
}
}
func downloadJSON(completed: #escaping () -> () ) {
guard let url = URL(string : "http://www.something.com/notice/get") else {return}
var request = URLRequest.init(url: url)
request.httpMethod = "POST"
request.addValue("cf7ab8c9d4efae82b575eabd6bec76cbb8c6108391e036387f3dd5356a582171519367747000", forHTTPHeaderField: "app_key")
let postDictonary = "school_id=1"
//send value directly to server without chaging to json
request.httpBody = postDictonary.data(using: .utf8)
URLSession.shared.dataTask(with: request) { (data, response, error) in
if error == nil{
do{
self.nontificatonData = try JSONDecoder().decode([NotificationDataModel].self, from: data!)
print(self.nontificatonData)
DispatchQueue.main.async {
completed()
}
}catch{
print(error)
}
}
}.resume()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return nontificatonData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as! TableViewCell
cell.lblTitileNotification.text = nontificatonData[indexPath.row].notice_title
cell.lblDiscriptionNotificaiton.text = nontificatonData[indexPath.row].notice_desc
return cell
}
}
My Struct is as follows:
import Foundation
struct NotificationDataModel : Decodable{
let notice_id : String
let notice_title : String
let notice_desc : String
let notice_date : String
let content_name : String
let notice_link : String
let is_important : String
let parent_availability : String
let is_pinned : String
let created_at : String
}
I'm sorry, but prototype cells are available only in storyboard-based projects. Hopefully you won't have gone too far down the xib approach and can try multiple storyboards instead. If you find them a bit overwhelming, it's OK; they get better – note that you don't have to have one storyboard for all your view controllers. You can have several, either linked in code or using storyboard references.
If you want to stick with xibs, another option is to use registerNib in code. So you design your prototype cells in xibs, then register them in code. Not quite as smooth, but it might suit your needs.
I have an empty view with a tab bar pictured below, when i load a routine a table appears containing the contents, however it seems to overlay the tab bar killing off app navigation. Its not sized in the storyboard to overlay it and its constraint locked to not do so, so im unsure why this is happening, pics of the issue and VC's code below:
VC Code:
import Foundation
import UIKit
import CoreData
class RoutineController: UIViewController, UITableViewDataSource, UITableViewDelegate {
// MARK: - DECLARATIONS
#IBAction func unwindToRoutine(segue: UIStoryboardSegue) {}
#IBOutlet weak var daysRoutineTable: UITableView!
#IBOutlet weak var columnHeaderBanner: UIView!
#IBOutlet weak var todaysRoutineNavBar: UINavigationBar!
#IBOutlet weak var addTOdaysRoutineLabel: UILabel!
let date = Date()
let dateFormatter = DateFormatter()
let segueEditUserExerciseViewController = "editExerciseInRoutineSegue"
//This is the selected routine passed from the previous VC
var selectedroutine : UserRoutine?
// MARK: - VIEWDIDLOAD
override func viewDidLoad() {
super.viewDidLoad()
setupView()
daysRoutineTable.delegate = self
daysRoutineTable.dataSource = self
view.backgroundColor = (UIColor.customBackgroundGraphite())
dateFormatter.dateStyle = .short
dateFormatter.dateFormat = "dd/MM/yyyy"
let dateStr = dateFormatter.string(from: date)
todaysRoutineNavBar.topItem?.title = dateStr + " Routine"
}
// MARK: - VIEWDIDAPPEAR
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.daysRoutineTable.reloadData()
self.updateView()
}
// MARK: - TABLE UPDATE COMPONENTS
private func setupView() {
updateView()
}
// MARK: - TABLE SETUP
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let count = self.selectedroutine?.userexercises?.count
{
print("exercises: \(count)")
return count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? TodaysRoutineTableViewCell else {
fatalError("Unexpected Index Path")
}
cell.backgroundColor = UIColor.customBackgroundGraphite()
cell.textLabel?.textColor = UIColor.white
configure(cell, at: indexPath)
return cell
}
// MARK: - VIEW CONTROLER ELEMENTS VISIBILITY CONTROL
fileprivate func updateView() {
var hasUserExercises = false
if let UserExercise = self.selectedroutine?.userexercises {
hasUserExercises = UserExercise.count > 0
}
addTOdaysRoutineLabel.isHidden = hasUserExercises
columnHeaderBanner.isHidden = !hasUserExercises
daysRoutineTable.isHidden = !hasUserExercises
}
// MARK: - SETTING DATA FOR A TABLE CELL
func configure(_ cell: TodaysRoutineTableViewCell, at indexPath: IndexPath) {
if let userExercise = selectedroutine?.userexercises?.allObjects[indexPath.row]
{
print("\((userExercise as! UserExercise).name)")
cell.todaysExerciseNameLabel.text = (userExercise as! UserExercise).name
cell.todaysExerciseRepsLabel.text = String((userExercise as! UserExercise).reps)
cell.todaysExerciseSetsLabel.text = String((userExercise as! UserExercise).sets)
cell.todaysExerciseWeightLabel.text = String((userExercise as! UserExercise).weight)
}
}
}
requested table constraints
Debug hierarchy
The Segue that sends the user back to the view that looses its tab bar
if segue.identifier == "addToTodaySegue" {
let indexPath = workoutTemplateTable.indexPathForSelectedRow
let selectedRow = indexPath?.row
print("selected row\(selectedRow)")
if let selectedRoutine = self.fetchedResultsController.fetchedObjects?[selectedRow!]
{
if let todaysRoutineController = segue.destination as? RoutineController {
todaysRoutineController.selectedroutine = selectedRoutine
}
}
}
I also feel perhaps the viewDidAppear code may cause the issue, perhaps the super class?
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.daysRoutineTable.reloadData()
self.updateView()
Updated storyboard image
I suspect you need to embed your viewController in a UINavigationController.
Consider the following setup:
I suspect your setup is like the upper one:
TapBar -> ViewController -show segue-> ViewController
Which results in a hidden tapbar, like in your description:
While the bottom setup:
TapBar -> NavigationCntroller -rootView-> ViewController -show segue-> ViewController
results in:
which is what you want, how I understood.
Update
It's hard to see. The screenshot of your Storyboard is in pretty low resulution, but the segues look wrong. Double check them. A Segue of type show (e.g push) looks like this:
Also clear project and derived data. Segue type changes sometime are ignored until doing so.
Try calling this self.view.bringSubviewToFront(YourTabControl).
The previous suggestion should work. But the content at the bottom part of tableview will not be visible as the tabbar comes over it. So set the bottom constraint of tableview as the height of tabbar.
I'm trying to make a Query with a Pointer in Parse. I have two classes "Discover" and "DiscoveryDetails". I want to get the discovery details of an object that's picked from the discovery class.
Discovery Class
DiscoveryDetails Class - with the discoverID as the pointer.
The discovery objects are displayed in a DiscoveryTableView and on selecting one of the items, I want to query the objects of with an ID related to that selection in a DiscoveryDetailsTableView.
The DiscoveryTableView shows the objects as they appear in the class but the DiscoveryDetailsTableView shows all the objects instead of those related to the Cell I selected.
This is my didSelectRowAtIndexPath Code in the DiscoveryTableView:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let mainStoryboard = UIStoryboard(name: "Discovery", bundle: nil)
let discoveryDetailView = mainStoryboard.instantiateViewControllerWithIdentifier("discoveryDetailTVC") as! DiscoveryDetailTableViewController
let object = self.objectAtIndexPath(indexPath)
discoveryDetailView.titleString = object?.objectForKey("workoutName") as! String
discoveryDetailView.describtionString = object?.objectForKey("workoutDetails") as! String
discoveryDetailView.numberOfWorkouts = object?.objectForKey("numberOfWorkouts") as! Int
discoveryDetailView.imageFile1 = object?.objectForKey("image1") as! PFFile
discoveryDetailView.imageFile2 = object?.objectForKey("image2") as! PFFile
discoveryDetailView.imageFile3 = object?.objectForKey("image3") as! PFFile
let row = indexPath.row //we know that sender is an NSIndexPath here.
let selectedObj = objects![row] // some var where you hold your data
discoveryDetailView.varInDDT = selectedObj
self.navigationController?.pushViewController(discoveryDetailView, animated: true)
}
In my DiscoveryDetailsTableView I have this code:
var titleString: String!
var describtionString: String!
var numberOfWorkouts: Int!
var imageFile1: PFFile!
var imageFile2: PFFile!
var imageFile3: PFFile!
var varInDDT : PFObject?
//MARK: Query for Table with the details
override func queryForTable() -> PFQuery {
let discoveryQuery = PFQuery(className: "DiscoveryDetails")
discoveryQuery.cachePolicy = .CacheElseNetwork
discoveryQuery.whereKey("discoveryID", equalTo: PFObject(withoutDataWithClassName: "Discovery", objectId: "\(varInDDT!.objectId!)"))
discoveryQuery.orderByDescending("createdAt")
return discoveryQuery
}
override func viewDidLoad() {
super.viewDidLoad()
//Header Display
let imagesArray = [imageFile1, imageFile2, imageFile3]
let imagePicked = randomIntergerInRange(0, high: imagesArray.count)
titleLabel.text = titleString.uppercaseString
self.subtitleLabel.text = describtionString
self.numberOfWorkoutsLabel.text = "\(numberOfWorkouts!) Workouts"
//Pick a random Image from the Images
imagesArray[imagePicked].getDataInBackgroundWithBlock({ (imageData, error) -> Void in
if error == nil
{
if let imageData = imageData
{
let image = UIImage(data:imageData)
self.backgroundImage.image = image
}
}
})
...
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell? {
var discoveryDetailItemsCell:DiscoveryDetailTableViewCell! = tableView.dequeueReusableCellWithIdentifier("DiscoveryDetailTableViewCell") as? DiscoveryDetailTableViewCell
...
discoveryDetailItemsCell.titleLabel.text = object?.objectForKey("exerciseName") as? String
discoveryDetailItemsCell.titleLabel.textColor = UIColor.whiteColor()
discoveryDetailItemsCell.durationAndSetsLabel.text = "\((object?.objectForKey("durationOrSets"))!)"
discoveryDetailItemsCell.minAndSetLabel.text = "mins"
...
return discoveryDetailItemsCell
}
There may be similar questions out there but I have not found anything that answers this or I am probably not seeing my mistake clearly.
Thanks for the help in advance. :)
for query with pointer U have to use query like that
let discoveryQuery = PFQuery(className: "DiscoveryDetails")
discoveryQuery.cachePolicy = .CacheElseNetwork
discoveryQuery.whereKey("discoveryID", equalTo: PFObject(withoutDataWithClassName: "Discovery", objectId: "\(varInDDT!.objectId!)"))
discoveryQuery.orderByDescending("createdAt")
return discoveryQuery
for downloading the detail you have to pass at least ID of the object you want to download from the first viewController to the second or you can pass the whole PFObject
DiscoveryTableView
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("showDetail", sender: indexPath)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "showDetail"){ // define the segue Name
let controller = (segue.destinationViewController as! DiscoveryDetailTableViewController)
let row = sender!.row //we know that sender is an NSIndexPath here.
let selectedObj = discoveryObjects[row] // some var where you hold your data
controller.varInDDT = selectedObj
}
}
and define the var of PFObject in detailVC
DiscoveryDetailTableViewController
var varInDDT : PFObject?
How can I transfer an image from table cell to the Newviewcontroller using prepare for segue? I was able to transfer the label data but not the image. I am using parse.com as my backend to retrieve the image. thanks
import UIKit
class mainVC: UIViewController, UITableViewDataSource, UITableViewDelegate, {
#IBOutlet weak var resultsTable: UITableView!
var resultsStartdateArray = [String]()
var resultsTweetImageFiles = [PFFile?]()
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return resultsTweetImageFiles.count
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 350
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:mainCell = tableView.dequeueReusableCellWithIdentifier("Cell") as! mainCell
cell.dateLbl.text = self.resultsStartdateArray[indexPath.row]
resultsTweetImageFiles[indexPath.row]?.getDataInBackgroundWithBlock({
(imageData:NSData?, error:NSError?) -> Void in
if error == nil {
let image = UIImage(data: imageData!)
cell.tweetImg.image = image
}
})
return cell
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let upcoming: NewViewController = segue.destinationViewController as! NewViewController
let indexPath = self.resultsTable.indexPathForSelectedRow!
let titleString = self.resultsStartdateArray[indexPath.row] as String
let imageTitle = self.resultsTweetImageFiles[indexPath.row] as PFFile?// i have tried this but it didnt work
upcoming.imageTitle == imageTitle // << not working
upcoming.titleString = titleString
self.resultsTable.deselectRowAtIndexPath(indexPath, animated: true)
}
import UIKit
class NewViewController: UIViewController {
#IBOutlet weak var dateLbl: UILabel!
#IBOutlet weak var tweetImage: UIImageView!
var titleString: String!
var imageTitle: UIImage!
override func viewDidLoad()
{
super.viewDidLoad()
self.dateLbl.text = self.titleString
self.tweetImage.image = self.imageTitle
}
In this line of code you create imageTitle as PFFile object:
let imageTitle = self.resultsTweetImageFiles[indexPath.row] as PFFile?
And then you try set it to UIImage reference:
upcoming.imageTitle == imageTitle
But imageTitle from NewViewController expects the image with UIImage type and not some incomprehensible for it object like PFFile
That's why it does not work.
To fix it you need to convert data from your PFFile object to UIImage and only then transmit it to your NewViewController object. You did not write the form in which the data contained in your PFFile object so assume that it NSData format for example. In this case you can do something like this:
if let imageObject = self.resultsTweetImageFiles[indexPath.row] as? PFFile {
if let imageData = imageObject.getData as? NSData {
if let image = UIImage(data: imageData) {
upcoming.imageTitle = image
}
}
}
Or if you have the some String object that contain your image in base64 format you can first convert it to NSData object like this:
let imageData = NSData(base64EncodedString: imageString, options: .IgnoreUnknownCharacters)
trying to get from my UITableViewController to the detail view controller with these PFObjects...thanks in advance!
error i can't seem to reconcile..."Cannot subscript a value of type 'String' with an index of type 'String'"
I want the queried objects to present on the detail view controller...
here is my query and my prepare for segue...i can't seem to access the objects in the prepare for segue...
var customerName = [String]()
var customerAddress = [String]()
var query = Pfuser.query
query.whereKey("userId",equalTo:adminFollowingUser)
query.findObjectsInBackgroundWithBlock({ (adminObjects, error) -> Void in
if let objects = adminObjects {
for object in objects {
self.customerName.append(object["customerName"] as! String)
self.customerAddress.append(object["customerStreetAddress"] as! String)
// Here is the prepare for segue....
override func prepareForSegue(segue: UIStoryboardSegue, sender:
AnyObject?)
{
if (segue.identifier == "thesePools")
{
let employeeDetailVC: EmployeeDetailViewController = segue.destinationViewController
as! EmployeeDetailViewController
// indexPath is set to the path that was tapped
let indexPath = self.tableView.indexPathForSelectedRow
let customerNameLabel = self.customerName[indexPath!.row]
let customerAddressLabel = self.customerAddress[indexPath!.row]
employeeDetailVC.customerString = customerNameLabel
employeeDetailVC.addressString = customerAddressLabel
here is my detail view controller receiving the Strings.
//DetailViewController
var customerString = String()
var addressString = String()
override func viewDidLoad() {
super.viewDidLoad()
self.customerLabel.text = customerString
self.addressLabel.text = addressString
var currentObject = String() is a string and you set it to a string in the prepareForSegue.This should do the trick:
self.customerTextField.text = curentObject
And remove all the other stuff.
Try that
let nav = segue.destinationViewController as! CustomerDetailViewController
var indexPath :NSIndexPath = self.tableview.indexPathForSelectedRow()!
var object = self.CustomerName[indexPath.row] as! String
nav.currentobject = object
I would recommend using a PFQueryTableViewController.
This is a UI object that is provided by Parse and loads data from your class 50x faster.
Here is an example of how to create it:
import UIKit
class YourTableViewController: PFQueryTableViewController {
// Initialise the PFQueryTable tableview
override init!(style: UITableViewStyle, className: String!) {
super.init(style: style, className: className)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
// Configure the PFQueryTableView
self.parseClassName = "yourClass"
self.textKey = "yourObject"
self.pullToRefreshEnabled = true
self.paginationEnabled = false
}
// Define the query that will provide the data for the table view
override func queryForTable() -> PFQuery! {
var query = PFQuery(className: "yourClass")
query.orderByAscending("yourObject")
return query
}
//override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject) -> PFTableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("Cell") as CustomTableViewCell!
if cell == nil {
cell = CustomTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
}
// Extract values from the PFObject to display in the table cell
cell.info.text = object["info"] as String
// Date for cell subtitle
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let dateForText = object["date"] as NSDate
cell.date.text = dateFormatter.stringFromDate(dateForText)
return cell
}
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using [segue destinationViewController].
var detailScene = segue.destinationViewController as YourDetailViewController
// Pass the selected object to the destination view controller.
if let indexPath = self.tableView.indexPathForSelectedRow() {
let row = Int(indexPath.row)
detailScene.currentObject = objects[row] as? PFObject
}
}
At the end make sure to also created a custom cell class.