I'd like to set my own cellAccessoryType (an image) in an UITableViewCell. Do you know how I can do this? I'm using Swift, Xcode 6.2 and iOS 8.2. Thank you for you help!
Try this:
// first create UIImageView
var imageView : UIImageView
imageView = UIImageView(frame:CGRectMake(20, 20, 100, 320))
imageView.image = UIImage(named:"image.jpg")
// then set it as cellAccessoryType
cell.accessoryView = imageView
PS: I strongly advise you to upgrade to XCode 6.3.2 and using iOS 8.3 SDK
I assume you would like to get tap on accessory view, so I provide this answer with button.
If not, use shargath's answer with imageView.
var saveButton = UIButton.buttonWithType(.Custom) as UIButton
saveButton.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
saveButton.addTarget(self, action: "accessoryButtonTapped:", forControlEvents: .TouchUpInside)
saveButton.setImage(UIImage(named: "check-circle"), forState: .Normal)
cell.accessoryView = saveButton as UIView
func accessoryButtonTapped(sender:UIButton) {
}
Swift 5 version of Shmidt's answer, plus using sender.tag to keep track of which row the button was clicked on:
override func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell",
for: indexPath)
let checkButton = UIButton(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
checkButton.addTarget(self, action:#selector(YOUR_CLASS_NAME.checkTapped(_:)),
for: .touchUpInside)
checkButton.setImage(UIImage(named: "check"), for: .normal)
checkButton.tag = indexPath.row
cell.accessoryView = checkButton
return cell
}
#objc func checkTapped(_ sender: UIButton) {
print(sender.tag)
}
Swift 5 version, adding contentMode:
let imageView: UIImageView = UIImageView(frame:CGRect(x: 0, y: 0, width: 20, height: 20))
imageView.image = UIImage(named:Imge.Card.Link.download)
imageView.contentMode = .scaleAspectFit
cell.accessoryView = imageView
Xamarin.iOS version of Shmidt's answer
// Create the accessory
var accessory = new UIButton(UIButtonType.Custom);
accessory.Frame = new CGRect(0f, 0f, 24f, 24f);
accessory.AddTarget(accessoryButtonTapped, UIControlEvent.TouchUpInside);
accessory.SetImage(UIImage.FromBundle("check-circle"), UIControlState.Normal);
// Set the accessory to the cell
cell.AccessoryView = accessory as UIView;
void accessoryButtonTapped(object sender, EventArgs args)
{
}
SWIFT 5 solution
This example presents how to add simple button with SF Symbols to your accessory view.
inside cellForRowAt:
let plusButton = UIButton(type: .system)
plusButton.setImage(UIImage(systemName: "plus"), for: .normal)
plusButton.contentMode = .scaleAspectFit
plusButton.sizeToFit()
cell.accessoryView = plusButton
and instead of adding target to the button we can use delegate method from UITableViewDelegate
func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
//handle logic here
}
Related
I added custom tableview header with two buttons, but buttons are disabled , unable to make control events. i want to get layout like this. i'm new to development. any suggestions or solution
i tried to add view with buttons inside view in ViewforHeaderSection function
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let inviteSectionHeaderview = UIView.init(frame: CGRect(x:0, y:0, width: self.view.bounds.width, height: self.view.bounds.height))
let selectAllBtn = UIButton.init(frame:CGRect(x:16, y: inviteSectionHeaderview.bounds.height/2, width:130, height:20))
let sendButton = UIButton.init(frame:CGRect(x:inviteSectionHeaderview.bounds.width - 30, y: inviteSectionHeaderview.bounds.height/2, width:60, height:20))
selectAllBtn.setTitle("select all/Cancel", for: .normal)
selectAllBtn.backgroundColor = .black
sendButton.backgroundColor = .black
sendButton.setTitle("SEND", for: .normal)
self.contactsTable.addSubview(inviteSectionHeaderview)
inviteSectionHeaderview.addSubview(selectAllBtn)
inviteSectionHeaderview.addSubview(sendButton)
return inviteSectionHeaderview
}
You have two options:
Create your UIView in storyboard
Create programatically
Option 2
Create your UIView.
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
let headerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 30.0))
// Button1
let button1 = UIButton(frame: CGRect(x: 15.0, y: 0, width: 100, height: 28.0)
button1.setTitle("Button 1", for: .normal)
button1.addTarget(self, action: #selector(selectorButton1), for: .touchUpInside)
// Button2
let button2 = UIButton(frame: CGRect(x: tableView.frame.width-150, y: 0, width: 150, height: 30.0))
button2.setTitle("Button2", for: .normal)
button2.addTarget(self, action: #selector(selectorButton2), for: .touchUpInside)
button2.semanticContentAttribute = UIApplication.shared
.userInterfaceLayoutDirection == .rightToLeft ? .forceLeftToRight : .forceRightToLeft
headerView.addSubview(button1)
headerView.addSubview(button2)
return headerView
}
#objc func selectorButton1(_ sender : Any) {
}
#objc func selectorButton2(_ sender : Any) {
}
In this case, you must set correctely y and x positions when create UIView(frame: CGRect()) and UIButton(frame: CGRect())
EDIT
From your code, you just need add the targets:
selectAllBtn.addTarget(self, action: #selector(selectorAllBtn), for: .touchUpInside)
sendButton.addTarget(self, action: #selector(selectorSendButton), for: .touchUpInside)
#objc func selectorAllBtn(_ sender : Any) {
}
#objc func selectorSendButton(_ sender : Any) {
}
You can try this code.
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
var headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "headerView")
if headerView == nil {
headerView = UITableViewHeaderFooterView(reuseIdentifier: "headerView")
let button1 = UIButton(frame: CGRect(x: 8, y: 8, width: 80, height: 40))
button1.setTitle("Select", for: .normal)
button1.addTarget(self, action: #selector(self.buttonAction), for: .touchUpInside)
headerView?.addSubview(button1)
}
return headerView
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50 // set a height for header view
}
#objc func buttonAction(_ sender: UIButton) {
// write your code...
}
I have an expandable tableViewCell with a couple UITextFields, a UILabel and a UITextView. When the tableView expands the label disappears and the UITextFields and UITextView appear. In both UITextFields the cursor appears but in the UITextView no cursor appears. I have tried changing the tint color and nothing shoed up, however when I select text (which does appear) the text is highlighted in the tint color and is visible. I have also tried changing the frame but that didn't work. Also I have it setup now as a regular UITextView with no changes to any properties other than the frame. The textView is setup programmatically using a UITableViewCell class and everything seems to work but the cursor.
Here's how I set up the UITextView:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! StudentTableViewCell
cell.infoView.frame = CGRect(x: 23, y: 207, width: cell.frame.width - 36, height: cell.frame.height - 155)
cell.infoView.delegate = self
cell.infoView.text = classes[indexPath.row].info
cell.infoView.layer.cornerRadius = 5
cell.infoView.layer.masksToBounds = true
cell.placeholderField.frame = CGRect(x: 32, y: 92, width: self.view.frame.width - 38, height: 45)
if cell.infoView.text!.replacingOccurrences(of: " ", with: "") == "" {
cell.placeholderField.placeholder = "Description"
} else {
cell.placeholderField.placeholder = ""
}
cell.placeholderField.backgroundColor = UIColor.clear
cell.nameField.frame = CGRect(x: 23, y: 3, width: cell.frame.width - 70, height: 44)
cell.nameField.text = classes[indexPath.row].name
cell.nameField.delegate = self
cell.nameField.layer.cornerRadius = 5
cell.nameField.layer.masksToBounds = true
cell.nameField.borderStyle = .roundedRect
cell.teacherField.frame = CGRect(x: 23, y: 50, width: cell.frame.width - 36, height: 44)
cell.teacherField.text = classes[indexPath.row].teacher.name
cell.teacherField.delegate = self
cell.teacherField.layer.cornerRadius = 5
cell.teacherField.layer.masksToBounds = true
cell.teacherField.borderStyle = .roundedRect
cell.editButton.frame = CGRect(x: self.view.frame.width - 60, y: 15, width: 70, height: 20)
cell.editButton.addTarget(self, action: #selector(self.editInfoView), for: .touchUpInside)
cell.editButton.setTitle(cell.editButton.title(for: .normal) ?? "Edit", for: .normal)
cell.contentView.addSubview(cell.nameField)
cell.contentView.addSubview(cell.teacherField)
cell.contentView.addSubview(cell.infoView)
cell.contentView.addSubview(cell.editButton)
cell.contentView.addSubview(cell.placeholderField)
cell.textLabel?.text = classes[indexPath.row].name
cell.detailTextLabel?.text = classes[indexPath.row].teacher.name
return cell
}
Here is the Class definition:
class StudentTableViewCell: UITableViewCell {
var infoView = UITextView()
var placeholderField = UITextField()
var nameField = UITextField()
var teacherField = UITextField()
var editButton = UIButton()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Does anyone know why the cursor isn't appearing?
Thanks in advance for the help.
Here are photos from the debug hierarchy with the cursor selected:
Photo from the side
Photo from the front
The view in front of the cursor is the placeholderField and is not blocking the cursor because the cursor still doesn't appear when it is below the placeholderField.
First of all, I don't know how's your code is working for you as without compiling it I can see few major issues like.
Where you are returning the Cell in cellForRowAt indexPath?
cell.teacherNameField is not there in StudentTableViewCell
And frankly speaking, these things are not difficult they way you are trying to code, Just keep it simple and think before writing code (each and every possible approach) then only you will achieve the best practice.
Now coming back to your question, I tried with your codebase and thing are getting overlap that's you are not able to do this, so you are the best person who can solve it.
Use Debug View Hierarchy
And then you can see each and every runtime view layer on your screen.
I have created a UIButton programmatically on my ViewController. I want to perform different actions on the same button depending on the condition and want to change the title as well.
First I create the button like this:
func createButton(buttonTitle: String,buttonAction: Selector) -> UIButton{
let button = UIButton(type: UIButtonType.System) as UIButton
button.frame = CGRectMake(0, 0, 414, 65)
button.setTitle(buttonTitle, forState: UIControlState.Normal)
button.addTarget(self, action:buttonAction, forControlEvents: UIControlEvents.TouchUpInside)
button.setTitleColor(UIColor.whiteColor(), forState:UIControlState.Normal)
button.titleLabel?.font = UIFont(name: Variables.MONTESERRAT_REGULAR, size: 20.0)
button.backgroundColor = UIColor().blueColor() //top
button.titleEdgeInsets = UIEdgeInsetsMake(0.0,10.0, 10.0, 0.0)
return button
}
Then I am showing like this
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView(frame: CGRectMake(0, 0, tableView.frame.size.width, tableView.frame.size.height))
if(active == true){
bottomButton = createButton("UNPUBLISH", buttonAction: "unPublishToServer")
}else if(active == false){
bottomButton = createButton("PUBLISH", buttonAction: "publishToServer")
}else{
bottomButton = createButton("Request", buttonAction: "requestItem")
}
footerView.addSubview(bottomButton!)
return footerView
}
then on certain messages from server or conditions I am changing the button like this
func publishTripToServer(){
dispatch_async(dispatch_get_main_queue()) {
self.bottomButton?.setTitle("UNPUBLISH", forState: UIControlState.Normal)
}
}
func unPublishTripToServer(){
dispatch_async(dispatch_get_main_queue()) {
self.bottomButton?.setTitle("PUBLISH", forState: UIControlState.Normal)
}
}
The problem I am having is first it shows some background color behind the title when I click publish or unpublish. the second issue is button is not changing the action.
I'm not exactly sure what you mean for the background color issue.
But for your button, does something like this not work?
func publishTripToServer(){
self.bottomButton = createButton("UNPUBLISH", buttonAction: "unPublishToServer")
}
func unPublishTripToServer(){
self.bottomButton = createButton("PUBLISH", buttonAction: "publishToServer")
}
I don't know why you previously were trying to update the button title on the background thread, but you shouldn't ever update ui elements asynchronously.
And the reason your button action wasn't changing is that you never told it to change - you just changed the title
I'm trying to pass my app from Objective-C to Swift, but I have some problem with my UIButton action which are never called.
UIButton declaration (in footer view) :
let footerView = UIView.init(frame: CGRectMake(0, 0, self.view.frame.size.width, 140))
let acceptButton = UIButton(type: .Custom)
acceptButton.userInteractionEnabled = true
acceptButton.setTitle("Accepter", forState: .Normal)
acceptButton.addTarget(self, action: "acceptRequest:", forControlEvents: .TouchUpInside)
acceptButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
acceptButton.titleLabel!.font = UIFont(name: "AvenirNext-Medium", size:16.0)
acceptButton.frame = CGRectMake((self.view.frame.size.width/2)-115, 35,230, 40)
acceptButton.layer.cornerRadius = 4
acceptButton.layer.borderWidth = 1
acceptButton.layer.borderColor = UIColor.customGreen().CGColor
acceptButton.layer.backgroundColor = UIColor.customGreen().CGColor
footerView.addSubview(acceptButton)
return footerView;
Action :
func acceptRequest(sender:UIButton!) {
print("2")
}
I missed something with Swift ?
I looked at it carefully, your event should be no problem.I think what you said is UITableView seciton footer View, Would you determine whether or not to return to the height of the footerView, if there is no return footerView height, the event is also unable to response, because it is beyond the parent view display area.The hope can help you!
func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 44
}
Try this:
footerView.userInteractionEnabled = false
I have a UITableView that contains cells with a slider and two labels, each time a slider goes out of view it appears to be drawn again on top of the current content.
Here is a gif explaining what I mean.
http://i.imgur.com/4dYtyJy.gifv
And here is the relevant code.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let CellIdentifier: String = "\(indexPath.row) - \(indexPath.section)"
var cell: UITableViewCell! = self.tableView.dequeueReusableCellWithIdentifier(CellIdentifier)
if cell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: CellIdentifier)
}
let label = UILabel(frame: CGRect(x: 16.0, y: 16.0, width: 300, height: 30.0))
let percentageLabel = UILabel(frame: CGRect(x: 16.0, y: 0, width: 200.0, height: 30.0))
let slider = CustomUISlider(frame: CGRect(x: 16.0, y: 55.0, width: 300.0, height: 20.0))
slider.maximumTrackTintColor = Global().turqTint
slider.minimumTrackTintColor = Global().blueTint
slider.minimumValue = 0.0
slider.maximumValue = 1.0
slider.value = 0.0
slider.tag = indexPath.row
slider.setThumbImage(UIImage(named: "sliderThumbImage"), forState: .Normal)
slider.addTarget(self, action: "sliderValueChanged:", forControlEvents: .ValueChanged)
label.text = Array(selectedTypes)[indexPath.row].1
percentageLabel.text = "\(slider.value)"
percentageLabel.tag = indexPath.row
cell.tintColor = Global().tintColor
cell.addSubview(label)
cell.addSubview(slider)
cell.addSubview(percentageLabel)
return cell
}
I have had a similar problem. As Horst said in the comments, putting that snippet inside the block will do the trick:
if (cell == nil)
{
// Code that draws frames
}
If you insist to go with your way, you would like to have something more like
(Note: "\(indexPath.row) - \(indexPath.section)") this will create different CellIDs for every cell. What you would like to have is some common CellID to be able to benefit from the reuse logic of the TableView:
//Global constants for the View tags
let textLabelTag = 1
let percentageLabelTag = 2
let sliderTag = 3
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let CellIdentifier: String = "SomeUniqueID"
var cell: UITableViewCell! = self.tableView.dequeueReusableCellWithIdentifier(CellIdentifier)
if cell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: CellIdentifier)
self.createUIforCell(cell);
}
self.configureCell(cell, indexPath: indexPath)
return cell
}
Create the UI components for the cell and add them as subviews. This method will be called only once if the cell doesn't exist:
func createUIforCell(cell: UITableViewCell) {
let textLabel = UILabel(frame: CGRect(x: 16.0, y: 16.0, width: 300, height: 30.0))
textLabel.tag = textLabelTag
cell.addSubview(textLabel)
let percentageLabel = UILabel(frame: CGRect(x: 16.0, y: 0, width: 200.0, height: 30.0))
percentageLabel.tag = percentageLabelTag
cell.addSubview(percentageLabel)
let slider = CustomUISlider(frame: CGRect(x: 16.0, y: 55.0, width: 300.0, height: 20.0))
slider.tag = sliderTag
slider.maximumTrackTintColor = Global().turqTint
slider.minimumTrackTintColor = Global().blueTint
slider.minimumValue = 0.0
slider.maximumValue = 1.0
slider.setThumbImage(UIImage(named: "sliderThumbImage"), forState: .Normal)
slider.addTarget(self, action: "sliderValueChanged:", forControlEvents: .ValueChanged)
cell.addSubview(slider)
}
Update the UI with the correct data:
func configureCell(cell: UITableViewCell, indexPath: NSIndexPath) {
let textLabel: UILabel = cell.viewWithTag(textLabelTag) as! UILabel
textLabel.text = Array(selectedTypes)[indexPath.row].1
let slider: CustomUISlider = cell.viewWithTag(sliderTag) as! CustomUISlider
slider.value = 0.0
let percentageLabel: UILabel = cell.viewWithTag(percentageLabelTag) as! UILabel
percentageLabel.text = "\(slider.value)"
}
Note: It'll be cleaner if you've your own UITableViewCell subclass where the UI to be created (either in the code or in .xib)
You should subclass UITableViewCell and override prepeareForReuse method. With it you can set your cell to default mode.
-(void)prepareForReuse {
[super prepareForReuse];
//Reset your cell here to default state.
}