I'm experiencing a weird issue with my Swift app. I'm trying to create a UITableViewCell using a custom cell that I have created.
I have an empty label and a text label in the cell. The empty label is simply colored by setting the backgroundColor against some R, G, B colors.
However, when I select and deselect rows in my table, the background color of the label disappears. This happens until I scroll the cell out of view and back into view again, at which it shows me the color again.
Here's a few screenshot to illustrate what's happening:
This is what it looks like before selecting a color
This is what it looks like when I have a color selected - it seems to change the label background color to transparent. It shouldn't do this
This is what it looks like when I have selected a different color - the color remains transparent/white
Of course, I don't want this to happen. The intention was for the label color to remain the same.
Here's my code for cellForRowAtIndexPath
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! ScenesTableCell
cell.sceneNameLabel.text = scenesArr[indexPath.row].sceneName
let red = scenesArr[indexPath.row].sceneCol[0]
let green = scenesArr[indexPath.row].sceneCol[1]
let blue = scenesArr[indexPath.row].sceneCol[2]
let brightness = scenesArr[indexPath.row].sceneBrightnessMultiplier
cell.colourIndicatorLabel.layer.backgroundColor = UIColor(red: CGFloat(red), green: CGFloat(green), blue: CGFloat(blue), alpha: CGFloat(brightness)).CGColor
cell.colourIndicatorLabel.layer.cornerRadius = 5
cell.colourIndicatorLabel.layer.borderWidth = 1
cell.colourIndicatorLabel.layer.borderColor = UIColor(red: 77.0/255.0, green: 146.0/255.0, blue: 203.0/255.0, alpha: 1.0).CGColor
}
Please note that I have tried the following line of code to change the backgroundColor too, however the same thing happens, but it fills outside of the rounded borders:
cell.colourIndicatorLabel.backgroundColor = UIColor(red: CGFloat(red), green: CGFloat(green), blue: CGFloat(blue), alpha: CGFloat(brightness))
I really appreciate some help here! I know I'm not very good at asking questions on SO, so if you have any questions, please ask! ;)
iOS clears the background colour of all cell subviews when a cell is selected. You can avoid this by overriding the setSelected method on your UITableViewCell subclass:
extension ScenesTableCell {
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
self.colourIndicatorLabel.backgroundColor = .blue // Set with the color you need
}
}
In order to use rounded corners and UIView.backgroundColor without overflow, you can set cell.colourIndicatorLabel.clipsToBounds = true when you dequeue the cell or in the cell subclass.
Related
I have a tableview with multiple cells. Each one contains an image and a label in the center. When a user presses on a cell, I want it to become slightly darker so the user knows that they are pressing on the cell.
Please take button in above of imageview with same size as cell. Just drag outlet and action of it. Use this code on button to manage selection and unselection.
Selection:
sender.backgroundColor = UIColor.black.withAlphaComponent(0.35)
Unselection:
sender.backgroundColor = UIColor.black.withAlphaComponent(0.0)
Happy Coding
If you want to slightly darken the cell and highlight it check the property in UITaleView that's called, isUserInteractionEnabled.
This behavior is already implemented by default in the UITableViewCell, however if that's not what you're looking for you can implement didSelectRowAt delegate function and do whatever you want on that cell, or you can use didHighlightRowAt.
You can read a lot about those functions online here is an example about implementing the didSelectRowAt.
UPDATE: some work around to manually shows the user what he clicked, inside the didSelectRowAt method add implement this.
let cell = (tableView.cellForItem(at: indexPath) as! MyCustomCell)
UIView.animate(withDuration: 0.4) {
cell.imageView.highlightedImage = cell.imageView.image?.withRenderingMode(.alwaysTemplate)
cell.imageView.tintColor = UIColor(displayP3Red: 0, green: 0, blue: 0, alpha: 0.3)
UIView.animate(withDuration: 0.4, animations: {
talbeView.deselectItem(at: indexPath, animated: true)
})
}
This will manually cover the image inside the image view with the tint color you set in this case is black with opacity of 0.3.
And then deselect the cell, all of this wrapped in a 0.4 animation time.
I'm trying to create a tableview from which i will use the selected cells. The tableview only contains 3 cells in view. If i tap the first/last cell, it will get selected, but if i'm trying to select the cell in the middle it will not select unless pressed in a certain area which is about half a cm of the whole cell in the bottom or top, depending on how scrolled the content is.
Note that allowsMultipleSelection is true and i have overridden the setSelected method in the cell with this one:
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
if self.isSelected {
checkImage.isHidden = true
subContentView.backgroundColor = #colorLiteral(red: 0.8979414105, green: 0.8980956078, blue: 0.8979316354, alpha: 1)
} else {
checkImage.isHidden = false
subContentView.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
}
}
Does anyone have any idea why this might happen?
Nevermind, i solved it. There was a separate view that was covering the tableview exactly in the middle, having the height almost as the height of a cell.
I've build an app which contains an UITableView with a bunch of cells. Inside the cells I've got a view, which fill the whole cell. I've configured the tableview like this:
tableView.separatorStyle = .none
tableView.backgroundColor = UIColor(red: 24/255.0, green: 34/255.0, blue: 41/255.0, alpha: 100)
tableView.separatorColor = UIColor(red: 26/255.0, green: 34/255.0, blue: 40/255.0, alpha: 100)
Whenever the app enters the foreground, I got those little lines flickering for 0.5 seconds or so. To be clear, I don't want those.
And this is how it looks like when the app fully entered the foreground, and how it is supposed to look like:
Any ideas how to get rid of them?
EDIT 1:
I'm starting to doubt that the flickering is related to the separators, because it is only happening between cells in a section, not between the section-cell and the first cell in a section. I've grabbed some screenshots of the view hierarchy and the constraints related to the view (Foreground view) I show in the cell.
EDIT 2:
If I set the top and bottom constraint to -2 instead of 0, there's no flickering at all, however it's not as I want it visually. So the flickering is not related to the separators at all.
Trick for removing the cell separators.
Objective-C
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.tableFooterView = [UIView new];
}
Swift
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableFooterView = UIView()
}
Usually flickering happens when you're returning a wrong heightForRowAtIndexPath.
In your case, you're returning a little smaller than your cell's actual height I guess.
So try to set "clipToBounds" of your cell to "true" and check if it works.
Try setting "Renders with edge antialiasing" to YES in your info.plist.
I think here your issue with UITableViewStyle. Right now you are using UITableViewStyle Grouped. So, line between cell isn't UITableViewCellSeparator it's Group Table 1 pixel header and footer space. So,
I have two solutions:
Either use UITableView background color same as cell background color.
Change UITableView style to Plain
GroupTable SS
or
PlainTable SS
I hope it'll help you. And solve your issue :)
I think it's not related to the separator, because the separator doesn't cover the whole screen, it must be related to your constraints, try changing the background color of the BackgroundContainerView, the DepartureCell and the TableView, one of these 3 views should have the dark grey color as a background color.
Would it be possible that the tableview is inherited from another one and seperatorStyle could be set different in the super class? Then, you need override it.
Set this in viewDidLoad()
tableView.separatorStyle = .none
You can do it as per follows, from your storyboard to avoid that separator from UITableView.
If you set
tableView.separatorStyle = .none
on viewDidLoad(), it will flicker
you need to it before like in viewWillAppear() or in the storyboard
Try setting the tableview separator color with full transparency it might help
tableView.separatorColor = UIColor(red: 26/255.0, green: 34/255.0, blue: 40/255.0, alpha: 0)
Do this in viewWillAppear
If that will not help check the view hierarchy maybe there is an issue with the cell rendering in
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
Check this post and its swift 4 update
or try adding this extension to your ViewController
extension UITableViewCell {
func removeCellSeparators() {
for subview in subviews {
if subview != contentView && subview.frame.width == frame.width {
subview.removeFromSuperview()
}
}
}
}
then try calling it in just before you return the cell
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "YourCellIdentifier", for: indexPath)
cell.removeSeparators()
return cell
}
if this doesn't help then please post more information about your setup, code or maybe host a minimal version of your app with the tableView having the issue on gitHub so that I can help.
EDIT 1:
Try setting the rowHeight / cellHeight to 15 pixels more than what it currently is if that will solve your problem than the cellHeight is what needs tweaking could be that it only needs to be 2-4 pixels higher. Probably as the app is entering the foreground autolayout is trying to do what it can do show everything as you want however some constraints are ambiguous therefore whilst entering from the background there is the view appearing animation from the system for about half a second and there is your flickering as well.
Can you use Xcode "Debug View Hierarchy" to find question View , and use "KVC" remove that view.
ps. my english is poor , i hope i can help you
From storyboard select table view separator to None.
In Separator Inset select custom and remove left value make it from 15 to 0.
Build and run it again now check.
Make tableView's backgroundColor and separatorColor exactly the same as in:
tableView.backgroundColor = UIColor(red: 24/255.0, green: 34/255.0, blue: 41/255.0, alpha: 100)
tableView.separatorColor = UIColor(red: 24/255.0, green: 34/255.0, blue: 41/255.0, alpha: 100)
I'm trying to add a 50% black alpha view on every collection view cell. The collection view cells have a background photograph and text on top. Would like the overlay view to be in between the two.
In my cellForItemAt method, I use the following:
let overlayView = UIView()
overlayView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5)
overlayView.frame = cell.bounds
cell.addSubview(overlayView)
The problem is as i scroll down, then up, the overlay keeps adding, making the alpha much darker than 50%. Additionally, the overlayView is being added on top of my text (I need it below the text.)
How can I prevent the overlay from adding multiple times, and adding it in between the correct layers of the cell?
UITableView has a method of reusing cells to make it more efficient (keeping only the required cells in memory). Because of this the reused cell may already have this subview, so calling addSubview again causes another view to be added on top of it.
Here is how to solve this:
Move addSubview(overlayView) to the layoutSubviews() method inside your cell subclass.
override func layoutSubviews() {
super.layoutSubviews()
addSubview(overlayView)
}
Remove the overlay view in the prepareForReuse() method inside your cell subclass.
override func prepareForReuse() {
super.prepareForReuse()
overlayView.removeFromSuperview()
}
Note that this requires you to define the overlay view in the cell's subclass (which you should probably do since the cell itself should be responsible for its own subviews).
This happens because your cells are dequeued and reused multiple times, therefore, you are adding multiple layers.
Put this code inside your cell's class
override func awakeFromNib() {
super.awakeFromNib()
let overlayView = UIView()
overlayView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5)
overlayView.frame = self.bounds
self.addSubview(overlayView)
}
Or if you want to achieve the same result you can set black backgroundColor and set imageView's alpha to 50%
cell.backgroundColor = .black
cell.imageView.alpha = 0.5
Avoid adding this in cellForItem. The cells are reused, hence if you keep adding the view it would add one top of another. On reusing the cell the previously added view is not removed. Instead you can add the view in Prototype cell or XIB and set its alpha to whatever you want. Or if you are creating the cell programatically you can it in awakeFromNib()
I am trying to implement UINavigationBar that changes its transparency when scrolling UITableView. At the beginning, the navigation bar should have transparent background, so the content below it should be visible (there will be an image displayed, for the example I am using solid color):
When user scrolls table view, transparency should be replaced with solid color:
Table view will contain section headers, that should act like when using non-translucent navigation bar. The header views should "stick" to navigation bar once they "touch" it from the bottom:
I have no luck with trying to implement this flow in iOS app.
For the initial state, I am setting UINavigationBar translucent property to YES, and both backgroundColor and barTintColor to clear color, which gives me what I want.
Then, when user scrolls table view, I am updating the backgroundColor and barTintColor to a color with given alpha component, computed basing on current scroll offset. I am using scrollViewDidScroll: from UIScrollViewDelegate protocol to do so. However, it changes only the background of navigation bar, leaving status bar background transparent, which is not what I want.
I can't find another way of making UINavigationBar transparent without setting translucent property to YES. Unfortunately, this changes how the section headers acts when scrolling. As navigation bar is translucent, section header views hides below it when they should "stick" to the bar like on third screenshot above.
I would appreciate any help and hints how to achieve navigation bar that acts like described or similar in Objective-C or Swift.
Assuming that you have a reference to the view above the tableView and that you don't want to interact anything in it:
var overlayView:UIView!
var offsetDenominator:CGFloat!
let TARGER_COLOR = UIColor.blackColor()
override func viewDidLoad() {
super.viewDidLoad()
if let navCtrl = self.navigationController {
self.offsetDenominator = headerView.frame.size.height - navCtrl.navigationBar.frame.height
let targetCIColor = CIColor(CGColor: self.TARGER_COLOR.CGColor)
let overlayColor = UIColor(red: targetCIColor.red, green: targetCIColor.green, blue: targetCIColor.blue, alpha: 0.0)
self.overlayView = UIView(frame: self.headerView.frame)
self.overlayView.backgroundColor = overlayColor
self.view.addSubview(self.overlayView)
}
...
override func scrollViewDidScroll(scrollView: UIScrollView) {
if let navCtrl = self.navigationController, let breakpoint = offsetDenominator {
let alpha = scrollView.contentOffset.y / breakpoint
if alpha >= 1.0 {
navCtrl.navigationBar.backgroundColor = self.TARGER_COLOR
} else {
let targetCIColor = CIColor(CGColor: self.TARGER_COLOR.CGColor)
let overlayColor = UIColor(red: targetCIColor.red, green: targetCIColor.green, blue: targetCIColor.blue, alpha: alpha)
self.overlayView.backgroundColor = overlayColor
navCtrl.navigationBar.backgroundColor = UIColor.clearColor()
}
}
}
My approach is:
override func viewDidLoad() {
super.viewDidLoad()
...
self.setNavbarTransculent()
}
private func setNavbarTransculent() {
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.isTranslucent = true
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let denominator: CGFloat = 50 //your offset treshold
let alpha = min(1, scrollView.contentOffset.y / denominator)
self.setNavbar(backgroundColorAlpha: alpha)
}
private func setNavbar(backgroundColorAlpha alpha: CGFloat) {
let newColor = UIColor(red: 1, green: 1, blue: 1, alpha: alpha) //your color
self.navigationController?.navigationBar.backgroundColor = newColor
UIApplication.shared.statusView?.backgroundColor = newColor
}
extension UIApplication {
var statusView: UIView? {
return value(forKey: "statusBar") as? UIView
}
}
Swift3
var navAlpha = // Your appropriate calculation
self.navigationController!.navigationBar.backgroundColor = UIColor.red.withAlphaComponent(navAlpha)