Whole UITableviewcell is highlighted instead of rounded view inside the cell - ios

I was trying to achieve the rounded tableview cell effect, so I tried to mess with layoutSubviews in my custom cell class:
override func layoutSubviews() {
// Set the width of the cell
self.bounds = CGRectMake(self.bounds.origin.x, self.bounds.origin.y, self.bounds.size.width - 40, self.bounds.size.height)
super.layoutSubviews()
}
I heard that it is not recommended to change the width of the cell itself, and that adding a UIView (called mainView in the code) to the cell and adding constraints + corner radius would do the job.
My custom cell class is now:
class customTableViewCell: UITableViewCell {
#IBOutlet weak var mainView: UIView!
override func awakeFromNib() {
super.awakeFromNib()
mainView.layer.borderWidth = 2
mainView.layer.cornerRadius = 20
mainView.layer.borderColor = UIColor.black.cgColor
mainView.layer.masksToBounds = true
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
and here are the relevant components to my ViewController that holds the mainTableView:
override func viewDidLoad() {
super.viewDidLoad()
mainTableView.rowHeight = 100
mainTableView.backgroundColor = UIColor.clear
mainTableView.delegate = self
mainTableView.dataSource = self
// Do any additional setup after loading the view, typically from a nib.
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.mainTableView.dequeueReusableCell(withIdentifier: "customCell") as! customTableViewCell
// note that indexPath.section is used rather than indexPath.row
cell.textLabel?.text = self.animals[indexPath.row]
cell.textLabel?.font = UIFont.boldSystemFont(ofSize: 16)
cell.textLabel?.textAlignment = .center
// add border and color
cell.backgroundColor = UIColor.clear
cell.layer.borderColor = UIColor.clear.cgColor
cell.layer.borderWidth = 1
//cell.layer.cornerRadius = 8
cell.clipsToBounds = true
return cell
}
My result is this:
screenshot of simulator
As you can tell, the whole cell is highlighted and not just what is inside.
My remaining question is - Is there a way to make only the UIView inside the contentView of the cell to be highlighted instead of the whole cell? Or should I just not enable selection and highlighting.
Please let me know. Thanks.

For Swift 4.1, in your tableView(_ tableView: UITableView, cellForRowAt...) or Storyboard tableview cell scene:
cell.selectionStyle = .none
in your cell subclass:
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
super.setHighlighted(highlighted, animated: animated)
// do your custom things with the cell subviews here
if highlighted == true {
self.contentView.backgroundColor = .gray
} else {
self.contentView.backgroundColor = .white
}
}

You can achieve the desire effect. You just have to follow these steps.
Step 1 - Set your tableview cell's selection style to UITableViewCellSelectionStyleNone
cell.selectionStyle = UITableViewCellSelectionStyleNone;
Step 2 - In your customTableViewCell, override the default implementation of setHighlighted(_:animated:) and decide what you are going to highlight.
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
super.setHighlighted(highlighted, animated: animated)
self.backgroundColor = UIColor.blue // Change this to any color you want.
}
You can also highlight individual elements of your custom UITableViewCell in this method.
I hope this helps.

Related

Swift UITableView separator hidden until scroll

I have implemented a custom table view cell which appears but without the separator until you scroll. In the viewDidAppear I have set the separator style, the label border is not overlapping the cell edges. Help
Before Scrolling
After Scrolling
Larger Sim Window
On device testing
The pattern is MVVM with a custom cell.
Model
import Foundation
struct OAuthList {
let providers: [String]
init() {
self.providers = OAuthProviders.providers
}
}
View Model
import Foundation
struct OAuthListViewModel {
var providerList: [String]
init(providers: [String]) {
self.providerList = providers
}
}
LoginViewController
import UIKit
class LoginViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableView: UITableView!
var providerButtons = OAuthListViewModel(providers: OAuthProviders.providers)
override func viewDidLoad() {
super.viewDidLoad()
let attributes = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 17)]
self.navigationController?.navigationBar.titleTextAttributes = attributes
self.navigationController?.navigationBar.isTranslucent = false
self.navigationController?.navigationBar.barTintColor = #colorLiteral(red: 1, green: 0.738589704, blue: 0.9438112974, alpha: 1)
self.navigationItem.title = "LOGIN / SIGNUP"
self.navigationItem.leftBarButtonItem?.tintColor = .white
self.navigationItem.leftBarButtonItem?.isEnabled = false
self.tableView.separatorColor = .white
self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView.register(CustomCell.self, forCellReuseIdentifier: TextCellIdentifier.textCellIdentifier)
self.tableView.layoutMargins = UIEdgeInsets.zero
self.tableView.separatorInset = UIEdgeInsets.zero
self.tableView.tableFooterView = UIView()
}
}
extension LoginViewController {
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return providerButtons.providerList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: TextCellIdentifier.textCellIdentifier, for: indexPath) as! CustomCell
let row = indexPath.row
cell.backgroundColor = #colorLiteral(red: 1, green: 0.738589704, blue: 0.9438112974, alpha: 1)
cell.buttonLabel.text = providerButtons.providerList[row]
cell.layoutMargins = UIEdgeInsets.zero
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(providerButtons.providerList[indexPath.row])
}
}
Custom Cell
class CustomCell: UITableViewCell {
var labelText: String?
var buttonLabel: UILabel = {
var label = UILabel()
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: TextCellIdentifier.textCellIdentifier)
self.addSubview(buttonLabel)
buttonLabel.translatesAutoresizingMaskIntoConstraints = false
buttonLabel.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
buttonLabel.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
buttonLabel.textColor = UIColor.white
}
override func layoutSubviews() {
if let labelText = labelText {
buttonLabel.text = labelText
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
You can hide the separator and simply add UIView to act as a separator inside your custom cells
Enlarge your simulator window or try it on an actual device not sim.
When the sim window is small enough it can have a hard time displaying separators in a tableview since the separators are normally only 0.5pt in height.
A good indicator that the issue I mentioned above is occurring is when you scroll the tableview on the simulator and random separators start to appear while some are hidden. Which is what appears to be happening in your second screenshot.

Change text color in tableview cell in didHighlightRowAt

I have this code:
func tableView(_ tableView: UITableView, didHighlightRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
cell!.contentView.backgroundColor = .blue
cell?.textLabel?.textColor = UIColor.white
var cell2 = tableView.cellForRow(at: indexPath) as! DataTableViewCell
cell2.textLabel.textColor = UIColor.white
}
The background change works fine, but the text color change does not work.
Does anyone know why and how to fix this problem?
I think instead of writing these two lines:
cell!.textLabel?.textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
cell?.textLabel?.textColor = UIColor.white
writing only a single line as:
cell.textLabel?.highlightedTextColor = .black
will work fine for you!
Use this function in your DataTableViewCell
func setHighlighted(_ highlighted: Bool,
animated: Bool)
See Apple Developer Documentation
Try any one of these:
// set highlighted color in `tableView cellForRowAt indexPath`
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
cell?.textLabel?.highlightedTextColor = UIColor.white
}
or try this
class CustomCell: UITableViewCell {
// As an alternate of `tableView cellForRowAt indexPath`, label text highlighted color can be set in both these methods of cell - `awakeFromNib` and `prepareForReuse`
override func awakeFromNib() {
super.awakeFromNib()
self.textLabel?.highlightedTextColor = UIColor.white
}
override func prepareForReuse() {
super.prepareForReuse()
self.textLabel?.highlightedTextColor = UIColor.white
}
// or textColor can be directly set here
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
super.setHighlighted(highlighted, animated: animated)
self.textLabel?.textColor = UIColor.white
}
}
The tableView(_:didHighlightRowAt:) function is part of the Controller domain of your app while setting colors is part of the View domain (as per Model—View—Controller pattern). To keep up a good separation of responsibilities you might want to consider changing colors outside of the controller, i. e. in the cell itself. For this to work, you would create a simple UITableViewCell subclass, like so:
class MyCell: UITableViewCell {
class var reuseIdentifier: String { return "MyCell" }
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
if selected {
textLabel?.textColor = UIColor.white
} else {
textLabel?.textColor = UIColor.black
}
}
}
This way the cell itself (instead of the controller) handles its own graphical representation which is the recommended way.
cell.textLabel.highlightedTextColor = [UIColor greencolor];
OK, this code works:
override func awakeFromNib () {
         super.awakeFromNib ()
         // Initialization code
         self.titleCell? .xtxtColor = UIColor.black
         self.titleCell? .highlightedTextColor = UIColor.white
  }
     override func setSelected (_ selected: Bool, animated: Bool) {
         super.setSelected (selected, animated: animated)
         // Configure the view for the selected state
     }
    
    
     override func prepareForReuse () {
         super.prepareForReuse ()
         self.titleCell? .highlightedTextColor = UIColor.white
     }
Thank you very much for your help :)

How to add XYPieChart and PNBarChart in same prototype cell

My requirement is simple. I want to load a pie chart in first index of a UITableView. When I swipe right, pie chart (XYPieChart) should be replaced with a bar chart (PNBarChart). I have separately loaded pie chart and bar chart in separate rows. How can I achieve that swipe effect in UITableview.?
A UIView has to be added into the prototype cell and custom class of UIView has to set to XYPieChart and PNBarChart in the Identity Inspector in Xcode.
What I expect is an effect like page controller, but page controller loads two view controllers. Right?
Can I add a Page Control inside a prototype cell and add two UIViews into the page control?
Will the views change when I swipe the row?
I'm attaching some screenshots with this for clarity.
Pie Chart Screenshot
Pie Chart and Bar Chart in two rows
Try like this But code is in Swift
First Create Tableviewcontroller from Storyboard
Create CustomCell of TableView
import UIKit
class CustomCell: UITableViewCell {
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var pageControll: UIPageControl!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
Now In Tableviewcontroller and add delegate UIScrollViewDelegate,UITableViewDelegate,UITableViewDataSource
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:CustomCell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! CustomCell;
let scrollViewWidth:CGFloat = tableView.frame.width
let scrollViewHeight:CGFloat = cell.contentView.frame.height
let imgOne = UIImageView(frame: CGRect(x:0, y:0,width:scrollViewWidth, height:scrollViewHeight))
imgOne.image = UIImage(named: "image1")
imgOne.tag = 1
let imgTwo = UIImageView(frame: CGRect(x:scrollViewWidth, y:0,width:scrollViewWidth, height:scrollViewHeight))
imgTwo.image = UIImage(named: "image2")
imgTwo.tag = 1
cell.scrollView.addSubview(imgOne)
cell.scrollView.addSubview(imgTwo)
cell.scrollView.contentSize = CGSize(width:scrollViewWidth * 2, height:cell.scrollView.frame.height)
cell.scrollView.delegate = self
cell.pageControll.currentPage = 0
pageCtrl = cell.pageControll
return cell;
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView){
if (scrollView.superview?.superview as? CustomCell) != nil{
let cell = scrollView.superview?.superview as! CustomCell
let pageWidth:CGFloat = self.view.frame.width
let currentPage:CGFloat = floor((scrollView.contentOffset.x - pageWidth/2)/pageWidth)+1
cell.pageControll.currentPage = Int(currentPage)
}
}

UITableView inside UITableViewCell changes color to white when selected

I have a UITableView inside a UITableViewCell (Scrolling is disabled for the nested UITableView)
Everything works fine. However there is an issue when I tap on the cell. It gets highlighted, but the nested UITableView changes its color to white which does not look good.
Is there any way to change this? I already set the nested UITableView's backgroundView and its cells to transparent.
EDIT: Selection is disabled for the nested UITableView. The tap occurs on a cell of the outer UITableView, which makes the whole inner UITableView turn white.
EDIT2: Here are some screenshots before and during the tap
EDIT3:
Code of the first UITableView:
In the ViewControler's viewDidLoad
self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView.backgroundColor = UIColor.darkBlueColor()
self.tableView.registerNib(UINib(nibName: "TimelineDay", bundle: nil), forCellReuseIdentifier: TimelineDayTableViewCell.identifier)
In the TimelineDayTableViewCell's awakeFromNib()
self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView.backgroundColor = UIColor.darkBlueColor()
self.tableView.backgroundView = UIView.clearView()
self.selectedBackgroundView = UIView.viewWithBackgroundColor(UIColor.accentColor())
self.tableView.registerNib(UINib(nibName: "EventItemCell", bundle: nil), forCellReuseIdentifier: EventItemTableViewCell.identifier)
In the EventItemTableViewCell's awakeFromNib()
self.backgroundView = UIView.clearView()
self.selectedBackgroundView = UIView.clearView()
You may need to subclass your cell:
class YourTableViewCellClass: UITableViewCell
{
#IBOutlet weak var yourLabel: UILabel!
override func setSelected(_ selected: Bool, animated: Bool) {
if(selected) {
self.contentView.backgroundColor = UIColor.red //or what you want
self.yourLabel.textColor = UIColor.green //or what you want
} else {
self.contentView.backgroundColor = UIColor.white //or what you want
self.yourLabel.textColor = UIColor.green //or what you want
}
}
}
Try with this, good job:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var selectedCell:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
cellSelected.contentView.backgroundColor = UIColor.blueColor() }
// if tableView is set in attribute inspector with selection to multiple Selection it should work.
// Just set it back in deselect
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
var cellToDeSelect:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
cellDeselected.contentView.backgroundColor = UIColor.clearColor() }

Make UITableViewCell actions overlap content

I was trying to go about making the actions for a UITableViewCell overlap the content of the cell, like in the National Geographic app:
table view
table view when swiped
I tried using a listener on the contentView of the cell to track the frame and keep it constant, but I was unable to get that to work (although it's possible it would, I'm kinda new to iOS).
If anyone has any suggestions for creating a similar effect, they would be much appreciated!
u can make your own custom cell and add a delete button and swipe gestures to make like button overlap the contents of the cell for example, try it out yourself, first create a sample project with single view app, and proceed
subclass the tabview cell with xib option selected and name it something like CustomCell , and in CustomCell.swift class past below code
import UIKit
class CustomCell: UITableViewCell {
var deleteButton:UIButton!
//create a custom cell if not in the reuse pool
class func customCell() -> CustomCell?
{
let aVar:Array = NSBundle.mainBundle().loadNibNamed("CustomCell", owner: nil, options: nil)
if aVar.last!.isKindOfClass(UITableViewCell)
{
return aVar.last as? CustomCell
}
return nil
}
//handle your left swipe
func swipeLeft()
{
print("swipe Left")
self.contentView.bringSubviewToFront(deleteButton!)
var frameRect:CGRect! = deleteButton!.frame
frameRect.origin.x = self.contentView.bounds.size.width - self.deleteButton!.frame.size.width
UIView.animateWithDuration(0.5) { () -> Void in
self.deleteButton!.frame = frameRect
}
}
//aslo the right swipe
func swipeRight()
{
print("swipe right")
var rect:CGRect! = deleteButton?.frame
rect.origin.x = self.contentView.bounds.size.width
UIView.animateWithDuration(0.5) { () -> Void in
self.deleteButton!.frame = rect
}
}
//hear we are adding the delete button in code, if u want add it in xib or (if u are using storyboard )
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
deleteButton = UIButton.init(type: .Custom)
deleteButton.setTitle("Delete", forState: .Normal)
deleteButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
deleteButton.backgroundColor = UIColor.redColor()
self.contentView.addSubview(deleteButton)
let gestureLeft:UISwipeGestureRecognizer = UISwipeGestureRecognizer.init(target: self, action: "swipeLeft")
gestureLeft.direction = .Left
self .addGestureRecognizer(gestureLeft)
let gestureRight:UISwipeGestureRecognizer = UISwipeGestureRecognizer.init(target: self, action: "swipeRight")
gestureRight.direction = .Right
self .addGestureRecognizer(gestureRight)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
//set the initial frame of delete button
override func layoutSubviews() {
super.layoutSubviews()
var rect:CGRect! = deleteButton?.frame
rect.size = CGSizeMake(100, 100)
rect.origin.x = self.contentView.bounds.size.width
deleteButton?.frame = rect
}
}
and make sure the tableview cell height to be of 100pt and in view controller set up a tableview in storyboard with datasource and delegate and implement the required delegate and datasource methods
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:CustomCell? = tableView.dequeueReusableCellWithIdentifier("CELL") as? CustomCell
if cell == nil
{
cell = CustomCell .customCell()
}
return cell as CustomCell!
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 100
}

Resources