How to add red dot badge in table view cell? - swift

Try to add red dot badge for every unread data in inbox tableviewcell.
I try using cell.accessoryview to add badge
let size: CGFloat = 9
let width = max(size, 0.7 * size * 1) // perfect circle is smallest allowed
let badge = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: size))
badge.layer.cornerRadius = size / 2
badge.layer.masksToBounds = true
badge.textAlignment = .center
badge.textColor = UIColor.white
badge.backgroundColor = UIColor.red
if viewModel.sortedInboxItems[indexPath.section].isRead {
cell.accessoryView = badge
}
But if using cell.accessoryview it will change the display like image below (TIME in the right corner of the cell is moving forward). How to make it not change the display?
EDIT
Try to create dot as uilabel in custom uitableview cell like image below
But the result show like this image below. The red dot shape is not good enough? Can someone help with this issue ?

The accessoryView is not part of the contentView of the cell. If you set the accessoryView it will push the contentView over to make room for itself. More information on that can be found here; this diagram is helpful:
If you don't want it to do this, put your red dot into the cell itself instead of using the accessoryView. It's unclear how you've built your cells, but it looks like you've created a custom UITableViewCell, so you should be able to do this without trouble.
Or as commented above, you could include your time label in your accessory view alongside the red dot if applicable.

Consider using a UIView with corner radius just like you did with the label. To make sure that the shape is right (sizes have initialised properly) change its corner radius in an overriden layoutSubviews.
override func layoutSubviews() {
super.layoutSubviews()
badgeInboxView.layer.cornerRadius = badgeInboxView.frame.height/2
}

Related

Set NSButton size in NSStackView

I programmatically create buttons using this code
let button: NSButton = NSButton()
button.action = #selector(ViewController.eject)
button.bezelStyle = .texturedSquare
buttons.append(button)
stackView.addView(buttons[i], in: .leading)
The problem is that those buttons appear like that
I would like to set the (x , y) position and the size of those buttons. For example, I would like to set their width to fill the whole space.
I tried multiple solutions:
button.frame = CGRect(x: 0.0,y: 0.0,width: 100.0,height: 100.0)
and play with the arguments, but still their size don't change.
I then tried to add them as SubViews to stackView, but obviously they overlap with each other.
Any suggestion?
To fix those buttons you first have to modify the StackView element in the storyboard.
Go to the menu of the storyboard and modify it like that
With the "fill" distribution you let the buttons to fill the entire width of the stackview.
With "spacing" you define how much space there has to be between each button.
Then you go there
To give some space to the buttons just play with the Edge Insets values.
Then set the horizontal Hugging Propriety to 250.
The last thing you have to do is to add this code in your ViewController file.
button.setContentHuggingPriority(NSLayoutConstraint.Priority.init(1), for: .horizontal)
button.translatesAutoresizingMaskIntoConstraints = false
In this way you'll the the horizontal Hugging Propriety of the button to 1.
Here's the buttons I created

UIButton action is not triggered after constraint layouts changed

I have got an UIButton on a storyboard ViewController. When I load data into the form and the layout is significantly changing the button does not recognise the touch action.
I have figured out that when button is visible on the scrollview right after it if filled with data, the touch action works.
If the data too long and the button is not visible at first, just when it is scrolled into the display, the touch action does not work.
I was checking if something is above the button, but nothing. I have tried to change the zPosition of the button, not solved the problem.
What can be the issue?
I have made custom classes from the UIScrollView and the UIButton to check how the touches event triggered. It is showing the same behaviour, which is obvious. If the button is visible right at the beginning, the UIButton's touchesBegan event is triggered. If the button moves down and not visible at the beginning, it is never triggered, but the scrollview's touchesBegan is called instead.
Depending on the size of the data I load into the page sometimes the button is visible at the beginning, but the form can be still scrolled a bit. In this case the button still work, so it seems that this behaviour is not depending on if the scrollview is scrolled before or not, just on the initial visibility of the button.
Is there any layout or display refresh function which should be called to set back the behaviour to the button?
The code portion which ensures that the contentview is resized for the scroll if the filled data requires bigger space.
func fillFormWithData() {
dispDescription.text = jSonData[0]["advdescription"]
dispLongDescription.text = jSonData[0]["advlongdesc"]
priceandcurrency.text = jSonData[0]["advprice"]! + " " + jSonData[0]["advpricecur"]!
validitydate.text = jSonData[0]["advdate"]!
contentview.layoutIfNeeded()
let contentRect = CGRect(x: 0, y: 0, width: scrollview.frame.width, height: uzenetbutton.frame.origin.y+uzenetbutton.frame.height+50)
contentview.frame.size.height = contentRect.size.height
scrollview.contentSize = contentview.bounds.size
}
Ok, so another update. I have coloured the contentview background to blue and the scrollview background to white. When I load the data and resize the layout constraints, the contentview is resizing as expected, however now the scrollview is going to the bottom. After I scroll the view it is resizing to the original size which fits the screen. Now the button is only recognised when I touch the are which is blue behind. With the white background it is not recognised anymore, so it seems that the scrollview is hiding the button.
Let me get this clear the button is added in storyboard and it is a spritekit project?? If you are using zPosition?? Why don’t u connect the UIButton via the assistant editor as an IBAction then the action is always tied to the button.
You can also do it differently
Create an SKLabelNode and put it on the screen where you want to have the button and then set a name to it as myButton
override func touchesBegan(_ touches: Set<UITouch>, with event:
UIEvent?) {
if let touch = touches.first {
let location = touch.location(in: self)
let tappedNodes = nodes(at: location)
for node in tappedNodes {
if node.name == "myButton" {
// call your action here
}
}
}
}
EDIT 1:
You could also try auto resizing your scrollView.content this works also if you are adding any views via the app or programmatically
private func resizeScrollView(){
print("RESIZING THE SCROLLVIEW from \(scrollView.contentSize)")
for view in scrollView.subviews {
contentRect = contentRect.union(view.frame)
}
scrollView.contentSize = CGSize(width: contentRect.size.width, height: contentRect.size.height + 150)
print("THE CONTENT SIZE AFTER RESIZING IS: \(scrollView.contentSize)")
}
EDIT 2: I think I found the issue with your project. You need to move the MessageButton(UzenetButton) above DispDescription label in the object inspector in that way it will always be above your message textView.
At the moment the UzeneButton is at the very far back in your view hierarchy so if your textView is resizing whilst editing it covers the button that is why you cannot click on it.
See #Endre Olah,
To make situation more clear do one more thing, set clipToBound property of contentview to true.
you will notice that after loading of data your button not fully visible, it means it is shifting out of bound of its parentView (ContentView)
And that's why button is not taking your touch. However, if you carefully touch upper part of button it still do its job. Because upper part is still in bound of ContentView
Solution :
After loading of data you have to make sure that you increase height of ContentView such that button should never go out of bound of its parentView(ContentView).
FOR EXAMPLE
#IBOutlet var heightConstraintOfContentView : NSLayoutConstraint!
After loading of data
let contentRect = CGRect(x: 0, y: 0, width: scrollview.frame.width, height: uzenetbutton.frame.origin.y+uzenetbutton.frame.height+50)
heightConstraintOfContentView.constant = contentRect.size.height
contentView.layoutIfNeeded()
I use following steps when I need to use scrollview with dynamic content:
1) Firstly add a scrollView with top, bottom, trailing and leading is 0 to super view.
2) Add a view to scrollView and view's trailing, leading bottom and top space to scrollView can be set to 0 (or you can add margin optionally).
3) Now, you should add UI elements like buttons, labels with appropriate top, bottom, trailing and leading margins to each other.
4) Lastly, add equal height and equal width constraint to view with Safe Area:
and change equal height priority of view to 250:
It should solve your problem with UIScrollView.
Finally, I have found the solution in another chain, once it became clear that the scrollview's contentview is resizing on scroll event to the original size. (Not clear why this is like this, but that is the fact.)
So I had to add a height constraint to the contentview in the storyboard and create an outlet to it and adjust this constraint when the content size is changing, like this:
#IBOutlet weak var ContentViewHeight: NSLayoutConstraint!
func fillFormWithData() {
dispDescription.text = jSonData[0]["advdescription"]
dispLongDescription.text = jSonData[0]["advlongdesc"]
priceandcurrency.text = jSonData[0]["advprice"]! + " " + jSonData[0]["advpricecur"]!
validitydate.text = jSonData[0]["advdate"]!
contentview.layoutIfNeeded()
let contentRect = CGRect(x: 0, y: 0, width: scrollview.frame.width, height: uzenetbutton.frame.origin.y+uzenetbutton.frame.height+50)
contentview.bounds = contentRect
scrollview.contentSize = contentRect.size
----------- This is the key line to the success ----------
ContentViewHeight.constant = contentRect.size.height
----------------------------------------------------------
}
After this is added, it works perfectly.

Make a UITableViewCell Coloured to specific percentage

I have an app quiz app split up into different categories. The categories can be seen in a UITableView e.g. Category A, Category B, Category C...etc. I am trying to show the percentage of questions that have been answered as a visual representation in the UITableView by colouring the background of a category UITableView cell.
For example if the person has completed 75% of the questions in category A, I want the background of category A in the UITableView to be coloured in a green colour 75% of the background of the Cell from left to right.
The only way would know how to do it is to make background images of a green background and depending on the percentage of questions answered place the relating background image as the background for the cell background.
Is there an easier way? that I could possibly use something like
Cell.backgroundcolor = UIColor.greencolor().75%ofCell.
I know this code isn't correct but it Kind of gets the idea across of what I am trying to do.
I think you can do it without adding a view to you cell by using a layer:
In your cell class you could add the following function:
func addGradientLayer(percentage: Double) {
let color1 = UIColor.green
let color2 = UIColor.clear
let gradientLayer = CAGradientLayer()
// sets the gradient frame as the bounds of your cell
gradientLayer.frame = bounds
gradientLayer.colors = [color1.cgColor, color2.cgColor]
// tells the gradient to go from left to right
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
//this line is the important one: as
//long the second Double is smaller than
//your percentage, you will not get a gradient
//but a clear separation between your two colors.
gradientLayer.locations = [percentage, 0.0]
layer.addSublayer(gradientLayer)
}
you can then call this method within your awakeFromNib() method or in cellForRowAt (tableView delegate):
tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
cell.addGradientLayer(percentage: 0.8)
}
Assuming you're using storyboards, add a UIView with backgroundColor = .greenColor() to the cell
Add top, left and bottom constrains for the view equal to the superview, then add a width constraint for the view and create an outlet for it.
Then in the cell you can say:
var pctScore: CGFloat {
didSet {
let viewWidth = cell.contentView.frame.width * pctScore
widthConstraint.constant = viewWidth
}
}
You could add a UIView as subview to the cell and make the background color of the UIView the color that you want.
Before adding the view you set the views width to 0.75 * cellWidth.

tvOS: UIScrollView doesn't scroll

I am trying to reproduce natively the TVML template that provides a grid of clickable images that extends beyond the screen's bounds. I am using a scroll view for this attempt, but I am unable to select elements that are added to the scroll view, but outside its visible area.
The sketch code using buttons for simplicity is as follows:
let dim = 50
for i in 0..<10 {
for j in 0..<10 {
let frame = CGRect(x: i * (dim + 10), y: j * (dim + 10), width: dim, height: dim)
let button = UIButton(type: .System)
button.frame = frame
myScrollView.panGestureRecognizer.allowedTouchTypes = [UITouchType.Indirect.rawValue]
myScrollView.addSubview(button)
}
}
The scroll view is sized such that only half of these buttons are visible. Why is the scroll view not scrolling to the buttons outside this area (using Siri remote)?
I thought the panGesture touchType might help, but it didn't.
Am I missing something obvious?
Set contentSize property to your scrollview. Make sure all components comes under given content size.
myScrollView.contentSize = CGSizeMake(1880, 2000)
It would actually be way easier to just use a UICollectionView. If you add an image to each cell, you'll get exactly the behavior you want after adjusting the collection view to what you want.
This tutorial kind of explains how it works. http://www.brianjcoleman.com/tutorial-collection-views-using-flow-layout/

ContentView background colour Swift

When I select a cell on a table view it by default changes it's ContentView background colour to a light grey and I am trying to override this.
And I am using the following code to remove this grey colour from the selection. But it is removing the background colour of everything (UIViews, UIImageViews) inside that cell.
Is there a way to eliminate the background colour of the ContentView only?
let changeselectionColor = UIView()
changeselectionColor.backgroundColor = UIColor.clearColor()
cell.selectedBackgroundView = changeselectionColor
I have the following table view cell.
This is how it should look like when selected
This is how it end up looking with all BGs transparent
You don't need to override anything to achieve the effect, actually UITableViewCell provides the API to remove the highlight gray:
cell.selectionStyle = UITableViewCellSelectionStyle.None