Swift 2 Table View Cell with Hyperlink - xcode

I've created a UITableView with different Sections and cells like: "Follow us on Instagram" or "Like us on Facebook".
This cells should have a link to each page.
I tried this:
#IBAction func WebLink(sender: AnyObject) {
if let url = NSURL(string: "http://...") {
UIApplication.sharedApplication().openURL(url)
}
}
But i can't link the #IBAction with the Cell...
It should look like this and on every Cell should be a Hyperlink.

You can directly use:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!
// launch your func WebLink with the currentCell
...
}

I'm not finding anything that would allow us to do so with a simple label. But there is a library available that does so in github. It seems you can't do so with a simple label in Swift. However, there is a library called TTTAttributedLabel that I think does what you're looking for. Here's a link to the library: https://github.com/TTTAttributedLabel/TTTAttributedLabel
#IBOutlet var exampleLabel: TTTAttributedLabel!
//...
let exampleString: NSString = "My super cool link"
exampleLabel.delegate = self
exampleLabel.text = exampleString as String
var range : NSRange = exampleString.rangeOfString("link")
exampleLabel.addLinkToURL(NSURL(string: "http://www.stackoverflow.com")!, withRange: range)
func attributedLabel(label: TTTAttributedLabel!, didSelectLinkWithURL url: NSURL!) {
UIApplication.sharedApplication().openURL(url)
}
Side note: Did not ever imagine I'd miss Objective-C. I'll update with a Swift 3.0 answer if this is what you were looking for.

Related

Set a custom cell style with right detail ,but it does not show detailTextLabel?

I'm using Xcode7.2.1 iOS9.2 SDK.
set the custom cell style with Right detail
Register cell nib:
Code:
self.TbuserList.registerNib(UINib.init(nibName: "UserCell", bundle: NSBundle.mainBundle()), forCellReuseIdentifier: "idUserList")
set the cell detailTextLabel text:
Code:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("idUserList",forIndexPath: indexPath ) as! UserCell
//print(self.users)
cell.textLabel?.text = self.users[indexPath.row]["nickname"] as? String
cell.detailTextLabel?.text = (users[indexPath.row]["isConnected"] as! Bool) ? "Online" : "Offline"
cell.detailTextLabel?.textColor = (users[indexPath.row]["isConnected"] as! Bool) ? UIColor.greenColor() : UIColor.redColor()
return cell
}
Note:When I change the cell style from "Right detail" to "subtitle" or "Left detail", it's ok.
Since you are using a custom cell created from a xib file, I would advise avoiding trying to use the default cell elements (textLabel and detailTextLabel), and instead just add the views you need to create the cell you require. You can add additional views to the standard cells, but it can be a little more complicated to make sure your views work with the existing standard cell views. If a standard cell type would suit your needs, you can register the UITableViewCell class with the tableView instead of a custom xib file. Have a look at the section Customizing Cells in the Apple docs
I don't use Storyboard so I'm not sure if this is any help to you, but what I so in my custom cell is this:
class CustomTableViewCell: UITableViewCell {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
//MARK: Setting ".value1" in super.init(style: .value1, ...) is the key to do this
super.init(style: .value1, reuseIdentifier: reuseIdentifier)
textLabel?.text = "Main Label"
detailTextLabel?.text = "Detail Label"
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
So long as you add a new Swift file and register the same names for your custom cell it should work.

How to open an external link by clicking on an image using SWIFT2.0?

I am using SwiftyJSON to download images from external website and show them in table view. I want to click on a particular image and have it open an external URL. How to achieve this?
Basically what I am doing by button press (as show below), I want to do by clicking image.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! myCell
let str = TableData[indexPath.row].thumbnail
let imagePath = (str.substringToIndex(str.startIndex.advancedBy((str.characters.count)-11)))+".png" //Removing "-100x90.png" from each thumbnail path and appending extension .png later on to fetch original sized image
cell.myImageView.kf_setImageWithURL(NSURL(string: imagePath)!)
cell.myLabel.text = String(TableData[indexPath.row].date) + ":" + String(TableData[indexPath.row].title)
print(TableData[indexPath.row].permalink)
cell.myButton.tag = indexPath.row
cell.myButton.addTarget(self, action: "openURL:", forControlEvents: UIControlEvents.TouchUpInside)
print(cell.myButton.tag)
return cell
}
func openURL(sender:UIButton){
print("Button Pressed")
UIApplication.sharedApplication().openURL(NSURL(string: TableData[sender.tag].permalink)!)
}
Add a UITapGestureRecognizer to the image view in the cell:
let tapRecognizer = UITapGestureRecognizer(target: self, action: "openURL:")
cell.myImageView.addGestureRecognizer(tapRecognizer)
It works with following code:
let singleTap = UITapGestureRecognizer(target: self, action:"tapDetected:")
singleTap.numberOfTapsRequired = 1
cell.myImageView.userInteractionEnabled = true
cell.myImageView.tag = indexPath.row
cell.myImageView.addGestureRecognizer(singleTap)
func tapDetected(sender: UITapGestureRecognizer) {
UIApplication.sharedApplication().openURL(NSURL(string: TableData[(sender.view!.tag)].link)!)
}

Passing an image when taped on uicollectionview to a detail view controller in swift

Ive been at this for a while but cant seem to crack it in swift
I want a user to be able to select an image in uicollectionView and for that image to appear in a detailed view controller, i can do this quite easily with a peice of text,
and i can do this when there is a static array of images preloaded. but i cant seem to get anywhere with a collectionview which is loaded with images from a camera.
I understand i need to use
override func performSegueWithIdentifier(identifier: String, sender: AnyObject?) {
}
and this function to isolated selected cell.
func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
}
I do have these outlets
#IBOutlet weak var collectionView: UICollectionView!
var images = [UIImage]()
image picker stores all images to this array by
images.insert(newImage, atIndex: 0)
when the array would be passed to the detailviewcontroller, i understand that would have to be copied into another local array and then how would i get the current image that was highlighted to be shown first, perhaps using indexPath.Row
Regards
I'm not using segues, and actually I don't quite understand what your problem is, but I'll try to show you how it could be achieved.
First of all, you have an array with images, so I believe your image should be accessed as images[indexPath.row]
let's suppose that you already have UIViewController class with UIImageView in it.
if so, you can write something like that:
func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
let myVC = MyViewController()
myVC.imageView.image = images[indexPath.row]
self.presentViewController(myVC, animated: true, completion: nil)
}
for modal or
func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
let myVC = MyViewController()
myVC.imageView.image = images[indexPath.row]
self.navigationController?.pushViewController(myVC, animated: true)
}
if you want to show it as navigational.
I believe that with segues it's basically the same but I think you have to use func prepareForSegue for, you know, preparing the segue (func performSegueWithIdentifier will just perform it). In prepareForSegue you should check identifier of your segue
if segue.identifier == "myIdentifier" {
//your code here
}
and if this identifier is right, put your commands to your myVC there.

TableViewCell with UITextView not aligned and cutted until scolling

I've a TableViewCell with a UITextView, which content is not aligned and cutted at bottom at the first display:
When I scroll down and then up to the top, everything is fine:
My cellForRowAtIndexPath to get the content from a fetchedResultsController is simple:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TextViewCell") as! TextViewCell
let data = self.fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject
let text = data.valueForKey("textDu")!.description
cell.textContentView.text = text
return cell
}
How can I get the result after scrolling after start???
Use sizeToFit() after adding content to your textContentView.
cell.textContentView.text = text
cell.textContentView.sizeToFit()
Make sure for sizing cell
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "onContentSizeChange:",
name: UIContentSizeCategoryDidChangeNotification,
object: nil)
tableView.estimatedRowHeight = 89
tableView.rowHeight = UITableViewAutomaticDimension
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
NSNotificationCenter.defaultCenter().removeObserver(self)
}
func onContentSizeChange(notification: NSNotification) {
tableView.reloadData()
}
Hope it helps you.
In conjunction with #Ashish Kakkad's answer you may want to try to set heightDimensions in viewDidLoad or viewWillAppear:
yourTableView.estimatedRowHeight = 30.0 // Put a real estimate here
yourTableView.rowHeight = UITableViewAutomaticDimension
Use auto layout code to tie the bottom of the cells contentView to the bottom of the text box. When the text box resizes it'll expand the cell with it.
This is in addition to Asish's correct suggestion about automatic cell heights and is quite a high level suggestion as you need to do a few things to get auto layout working right in tableview cells but there's ample examples on that out on the web.
oh, oh. Think I found something. I removed the existing contraints and then I've tried to "add missing constaints". The result was thas the error "Failed to automatically update constraints". Seem's I've a problem with my storyboard-file...

Swift displaying passed data from prepareForSegue

Ok, first time I have ever had to ask for help on here, usually I can search and find my answer but not this time. I have a table that displays a pictures and names. If one of them are selected it goes to another view and the data passes. However, I am trying to get that passed information to display in a table like: Name: (Passed Info), Age: (Passed Info), Gender: (Passed Info) etc. I know the data passes because I can display the info in a label, but I can not figure out how to get it to show in a table. Index issue? String Issue?
This is code that passes the info:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var detailsViewController: DetailsViewController = segue.destinationViewController as DetailsViewController
var horseIndex = appsTableView!.indexPathForSelectedRow()!.row
var selectedHorse = self.horses[horseIndex]
detailsViewController.horse = selectedHorse
This is the code on the controller getting the data where I want the table to display
class DetailsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tableView: UITableView!
#IBOutlet weak var titleLabel: UILabel!
var horse: Herd?
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.horse.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
cell.textLabel?.text = self.horse[indexPath.Row]
return cell
}
}
I get an error on the return self.horse.count stating not a member and an error on the self.horse[indexPath.Row] stating NSIndex does not have a member named row.
I feel like I am not unwrapping it properly or something, but I can not figure it out or find an answer in my searches. If you need more information please let me know and thanks in advance for any help.
CLARIFYING...
You correctly grab self.horses[horseIndex] in the segue method, so you've already done the work to get the 1 specific horse. No need to do it again. Is self.horses tied to the Herd type? Confusing why Herd shows up again in the DetailView - you don't seem to need it.
It sounds like what you actually want at this point is a tabular layout of the details of that single horse ... Correct? Like going from your entire "Contacts" list to the tabular view of a single contact?
That no longer involves the array of multiple horses, so your use of Herd? and herd.count aren't necessary. Use static labels or a static tableView to show the info from the 1 Horse.
WHAT'S YOUR DATA STRUCTURE & WHAT GOES IN DETAIL VIEW?
Presumably what you want to create (if you haven't already) is a Horse Type:
class Horse {
//you could use optional properties here, or require them for a fully initialized Horse.
let name:String?
let gender:String?
let breed:String?
var age:Int?
var restingHeartRate:Int?
init(name:String?, gender:String?, breed:String?, age:Int?, restingHeartRate:Int?) {
//set arguments passed in to respective properties of self...
}
func winTripleCrown() {
println("\(name!) Wins! Suck on that, Sea Biscuit!")
}
}
Ensure your horses array is declared to only take Horse instances, and fill it appropriately:
var horses = [Horse]()
let horse1 = Horse(name:"Bob" gender:"male" breed: "Yessir, I am a real horse" age:42 restingHeartRate: 30)
horses.append(horse1)
println(horses.count) //prints "1"
horses[0].winTripleCrown() //prints: "Bob Wins! Suck on that, Sea Biscuit!"
Use the Horse Type instead of Herd in the DetailViewController:
var horse: Horse? //nil until set in prepareForSegue
Then in the segue method:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
...
detailsViewController.horse = selectedHorse
Now, assuming you only put properly created Horse instances into the initial array, and there IS one at the selectedIndex, you're guaranteed that the horse variable in DetailViewController is a Horse instance, and that it's the one selected in the 1st "overall" tableView.
CREATE THE DETAIL VIEW
EASY:
The easy solution at this point is to create a detailView layout with labels, images, etc and hook them up to #properties in the DetailViewController. Then map the Horse properties to the #IBOutlets. Done. No need to mess w/tableViews anymore - just fake it or use a scrollView to make it look like a table.
TABLEVIEW ROUTE
But if you want to use a UITableView, then you'd need the delegate methods like you're using... The difference is you need to look at the # of properties of the single Horse instance - not anything about the overall list of Horses in a Herd or total array.
You COULD hard-code the # of rows if you're certain the # and order of Horse properties will always be consistent:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5 //1 row per property in a `Horse` instance as defined above
}
However, if you want to account for more dynamic results (like an array of wins/losses, or a photo gallery of variable length) you'd need to have enough cells to map all the Horse properties. How can you do that with a custom type that isn't an array or dictionary?
In Swift, you can determine how many properties a Type has by creating a "Mirror" type and using it for introspection, to reflect info back to you like the count property missing above.
let horseMirror = reflect(self.horse)
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.horseMirror.count //should also return "5" but no longer hard-coded
}
And then in cellForRowAtIndexPath: you can switch on the indexPath to assign the various Horse properties to the labels (or images, etc) in the tableView cells. Create custom tableView cell types w/unique identifiers if you want to show different information, or stick w/built-in options:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
//haven't played w/this to see if the optionals are correct. Consider it psuedocode...
switch indexPath.row {
case 1: cell.textLabel.text = self.horse.name?
case 2: cell.textLabel.text = self.horse.gender?
case 3: cell.textLabel.text = self.horse.breed?
case 4: cell.textLabel.text = String(self.horse.age?)
case 5: cell.textLabel.text = String(self.horse.restingHeartRate?)
default: cell.textLabel.text = ""
}
return cell
}

Resources