I want a rounded image inside a UIImageView. I subclassed UITableViewCell and added the cornerRadious in awakeFromNib like this:
class FriendsCell: UITableViewCell {
#IBOutlet weak var friendImageView: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
self.friendImageView.layer.cornerRadius = self.friendImageView.frame.size.width / 2
self.friendImageView.clipsToBounds = true
}
And this is what i get:
And this is what i expected:
The code for filling the tableView:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as FriendsCell
let user = fetchedResultsController.objectAtIndexPath(indexPath) as Friend
cell.friendImageView.image = UIImage(data: user.photo)
return cell
}
I tried also setting the cornerRadius when filling the tableView here, but i get the same result. I also tried with all the modes of contentMode (AspecFill, ScaleToFill..)
The weird thing is that in another VC i have the same layout and this is not happening.
I have the exact problem like you and I try setting this in the function of viewWillLayoutSubviews(). And then everything is ok! below is my code
override func viewWillLayoutSubviews() {
detailPortImageView.image = detailImage
detailPortImageView.layer.cornerRadius = detailPortImageView.frame.width / 2
detailPortImageView.clipsToBounds = true
detailPortImageView.layer.borderWidth = 2
detailPortImageView.layer.borderColor = UIColor.whiteColor().CGColor
}
Related
The cell is initially created from a xib file. Ive registered a reuse identifier in viewDidLoad().
Whenever I scroll down, one specific label is redrawn partially. Cant seem to figure out whats going on with the cell, but I know that the cell is not nil. Looking for insight on why this label isn't being drawn correctly.
before dragging
after dragging
More Info:
I can't tell, but it seems as if new cells are being drawn directly on top of the old cells. I figured this out due to the custom line divider: (let lineView = self.createLineDivider(cell: cell)) I added to context view of the cell. To stop the line from drawing over itself, I change the tag of every new cell.
override func viewDidLoad()
{
super.viewDidLoad()
let nib = UINib(nibName: "customContactDetailTableViewCell", bundle: nil)
self.contactDetailsTableView.register(nib, forCellReuseIdentifier: "customDetailCell")
}
func configureCell(cell: customContactDetailTableViewCell, indexPath: IndexPath) -> customContactDetailTableViewCell
{
let sectionName = self.props[indexPath.section].keys.first!
let contactPropLabel = self.props[indexPath.section][sectionName]![indexPath.row].keys.first!
let contactProp = self.props[indexPath.section][sectionName]![indexPath.row][contactPropLabel]
cell.contactDetailInfo?.layer.borderWidth = 1
cell.contactDetailInfo?.layer.borderColor = UIColor.white.cgColor
cell.contactDetailInfoTitle?.layer.borderWidth = 1
cell.contactDetailInfoTitle?.layer.borderColor = UIColor.white.cgColor
cell.contactDetailInfo?.numberOfLines = 0
cell.contactDetailInfoTitle?.text = contactPropLabel
cell.contactDetailInfo?.text = contactProp
cell.contactDetailInfo?.lineBreakMode = .byWordWrapping
self.rowHeight = cell.bounds.height
return cell
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{ var cell = tableView.dequeueReusableCell(withIdentifier: "customDetailCell") as? customContactDetailTableViewCell
if cell?.tag != 212
{
cell?.tag = 212
cell?.backgroundColor = UIColor.clear
let lineView = self.createLineDivider(cell: cell)
cell?.contentView.addSubview(lineView)
}
return self.configureCell(cell: cell!, indexPath: indexPath)
}
Update
Figured it out. Looks like the sporadic behavior came from the table view not updating the row height quick enough. Used this instead:
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
This is my requirement:
I want my tableView's cell to be like the last cell, its border is margin the tableView some pix, not contradict the tableview's edge.(I want this is because when I click down the cell, there is gray effect on the cell)
How to do with that?
u can't resize the cell's, instead u can set the views's layer properties to achieve the similar effect, for example, (u are not mentioning which language u are using, i assume u are using swift).
i will assume your custom cell contains a UIView and some other view components, like below,
and also add outlet for imageHolderView in the above image,
out let name will be holderView as shown in below image,
in the custom cell class, define two methods for selection management, and your custom cell class would look like below,
class CustomCell: UITableViewCell {
#IBOutlet weak var circleNameTextField: UILabel!
#IBOutlet weak var holderView: UIView!
var cellindexPath:IndexPath?
var selectedIndexPath:IndexPath?
func selectTheCell() {
if self.selectedIndexPath?.row == self.cellindexPath?.row {
self.holderView.layer.cornerRadius = 6.0
self.holderView.layer.masksToBounds = true
self.holderView.layer.borderWidth = 4.0
self.holderView.layer.borderColor = UIColor.red.cgColor
self.backgroundColor = UIColor.gray
} else {
self.resetCellWith(animate: false)
}
}
func resetCellWith(animate:Bool) {
self.holderView.layer.cornerRadius = 0.0
self.holderView.layer.masksToBounds = false
self.holderView.layer.borderWidth = 0.0
self.holderView.layer.borderColor = UIColor.clear.cgColor
self.backgroundColor = UIColor.orange
}
}
now all u have to do is call the above methods, from controller and update the cell behaviour, for example,
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.selIndexPath = indexPath
self.aTableView.reloadSections(IndexSet(integer: 0), with: .none)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : CustomCell? = tableView.dequeueReusableCell(withIdentifier: "CUSTOM_CELL", for: indexPath) as? CustomCell//tableView.dequeueReusableCell(withIdentifier: "CUSTOM_CELL") as? CustomCell
cell?.cellindexPath = indexPath
if let selectedIndexPath = self.selIndexPath {
cell?.selectedIndexPath = selectedIndexPath
cell?.selectTheCell()
} else {
cell?.resetCellWith(animate:false)
}
cell?.selectionStyle = .none
return cell!
}
with the above arrangement, u can get the table cell and selection like below,
NOTE: well, above is one way achieve this effect. and method names i simply used the sample project that i created for different purpose. :)
I'm trying to apply a radius to the corner of the images showed in a table to make them look like a circle. The problem is that the images are located via autolayout, so the final size is not calculated till the view has layout all its subviews, and I need to code the circle mask after that.
The solution that came to me was to write the code inside the method tableView(... willDisplayCell ...), or inside the methods didMoveToSuperview() and layoutSubviews() on the custom UITableViewCell subclass. I have seen this solutions on some questions of this forum, but no one of them are working.
Here is the code with one of those methods commented:
import UIKit
struct Contact {
var name: String
var image: UIImage
}
class ActiveChatsController: UITableViewController {
let contacts = [
Contact(name: "Alex", image: UIImage(named: "Alex")!),
Contact(name: "Puto Albert", image: UIImage(named: "Albert")!),
Contact(name: "Golfo-man", image: UIImage(named: "Pablo")!)
]
override func viewDidLoad() {
self.navigationController!.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: AppDesign.color(withIntensity: 6)]
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contacts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = Bundle.main.loadNibNamed("OpenedChatCell", owner: self, options: nil)?.first as! OpenedChatCell
cell.contactImage.image = contacts[indexPath.row].image
cell.contactName.text = contacts[indexPath.row].name
return cell
}
}
And the custom cell subclass is got from a XIB file:
import UIKit
class OpenedChatCell: UITableViewCell {
#IBOutlet weak var contactImage: UIImageView!
#IBOutlet weak var contactName: UILabel!
/*
override func didMoveToSuperview() {
self.contactImage.layer.cornerRadius = self.contactImage.frame.width / 2
self.contactImage.clipsToBounds = true
}
*/
}
If I run these codes on the simulator, I get this:
But if I delete the comments on the didMoveToSuperview() method and let it change the radius I get this:
After this, I wrote inside didMoveToSuperview():
print(self.contactImage.frame.height)
And it shows a height of 177.0, so I don't know where the error may be.
The problem might be that the table view itself is being created early, before the final setting of the frame of the image view. Thus, all your attempts to set the rounded corners are also happening too early, because they all depend on the initial formation of the table view.
The solution, in that case, would be as follows:
var didLayout = false
override func viewDidLayoutSubviews() {
if !self.didLayout {
self.didLayout = true // only need to do this once
self.tableView.reloadData()
}
}
If you have moved your code into this delegate method:
func tableView(UITableView, willDisplay cell: UITableViewCell,
forRowAt indexPath: IndexPath)
...that method will now run again for all the cells of the table, and the image view frame will be correct and the rounded corners will come out correctly.
Try to ovveride layoutSubviews instead of didMoveToSuperview:
override func layoutSubviews() {
super.layoutSubviews()
self.contactImage.layer.cornerRadius = self.contactImage.frame.width / 2
self.contactImage.clipsToBounds = true
}
Try this out. It may work
import UIKit
class OpenedChatCell: UITableViewCell {
#IBOutlet weak var contactImage: UIImageView!
#IBOutlet weak var contactName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
setRoundedView(roundedView: customImageView)
}
func setRoundedView (roundedView:UIView) {
let saveCenter = roundedView.center
let newFrame:CGRect = CGRect(origin: CGPoint(x: roundedView.frame.origin.x,y :roundedView.frame.origin.y), size: CGSize(width: roundedView.frame.size.width, height: roundedView.frame.size.height))
roundedView.layer.cornerRadius = roundedView.frame.height/2
roundedView.frame = newFrame;
roundedView.center = saveCenter
roundedView.clipsToBounds = true
}
}
If you already know the size of your image and don't need to determine it on the fly (oftentimes this is the case with images in a table view), you can just try it like this:
let imageHeight = CGFloat(100)
imageView.layer.masksToBounds = true
imageView.layer.cornerRadious = imageHeight / 2
I'm having a problem with my TableViewCell
I have two type of cell in my storyboard.
when i scroll, the text overlaps in some cells. I Try everything but I do not know how else to do. thank you very much for the help
public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
var storeNew = systemsBlog.getStore(listNews[indexPath.row].getIdStore())
var newNotice = listNews[indexPath.row]
let cell = tableView.dequeueReusableCellWithIdentifier("TimelineCell", forIndexPath: indexPath) as? TimelineCell
cell!.nameLabel.text = storeNew.getName()
cell!.postLabel?.text = newNotice.getText()
cell!.postLabel?.numberOfLines = 0
cell!.dateLabel.text = newNotice.getDate()
cell!.typeImageView?.tag = indexPath.row;
return cell!
}
class TimelineCell : UITableViewCell {
#IBOutlet var nameLabel : UILabel!
#IBOutlet var postLabel : UILabel?
#IBOutlet var dateLabel : UILabel!
override func awakeFromNib() {
postLabel?.font = UIFont(name: "Roboto-Thin", size: 14)
}
override func layoutSubviews() {
super.layoutSubviews()
}
I can fix the problem. In the storyboard, the label have unchacked "Clears Graphics Context". I checked and for now it solved! Thanks for the help!
I had a similar issue with one of my UITableViews in the past. There are a bunch of things that could cause this, but maybe it is the same thing that happened to me.
I see that you are using a custom tableViewCell. What could be happening is when you set the text of the cell, it adds a label view with that text. Now say you scroll through the tableview and that cell disappears. If you were to reuse that cell and you did not remove the label from the subview, or set the text of that label again to the desired text, you will be reusing the tableviewcell with a previous label on it and adding a new label with new text to it, overlapping the text.
My suggestion would be to make sure you do not keep adding UIlabels as subviews in the TimelineCell class unless no label exists. if a label exists edit the text of that label not of the cell.
As per apple documentation:
The table view’s data source implementation of
tableView:cellForRowAtIndexPath: should always reset all content when
reusing a cell.
It seems that your problem is that you not always setting postLabel, causing it to write on top of the other cells, try this:
//reuse postLabel and set to blank it no value is returned by the function
let cell = tableView.dequeueReusableCellWithIdentifier("TimelineCell", forIndexPath: indexPath) as? TimelineCell
cell!.nameLabel.text = storeNew.getName()
if newNotice.getText() != nil{
cell!.postLabel.text = newNotice.getText()
} else {cell!.postLabel.text = ''}
cell!.postLabel.numberOfLines = 0
cell!.dateLabel.text = newNotice.getDate()
cell!.typeImageView?.tag = indexPath.row;
return cell!
}
//Make postLabel mandatory and set the font details in the xcode
class TimelineCell : UITableViewCell {
#IBOutlet var nameLabel : UILabel!
#IBOutlet var postLabel : UILabel!
#IBOutlet var dateLabel : UILabel!
override func awakeFromNib() {
//set this in xcode
}
override func layoutSubviews() {
super.layoutSubviews()
}
Also be sure that you are not creating any UI element and appending to the cell, as if you are you need to dispose it before you recycle the cell.
You can try setting:
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 44.0 // Set this value as a good estimation according to your cells
}
In the View Controller containing your tableView.
Make sure the layout constraints in your TimelineCell define a clear line of height constraints
Another option is responding to:
tableView(_ tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 44.0 // Your height depending on the indexPath
}
Always in the ViewController that contains your tableView and, I assume, is the tableView's UITableViewDelegate
Hope this helps
Set cell to nil that will fix some error.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
var cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as? ImageCellTableViewCell
cell = nil
if cell == nil {
cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for:indexPath) as? ImageCellTableViewCell
}
cell.yourcoustomtextTextLabel.text = "this is text"
cell.yourcoustomtextImageView.image = image
return cell
}
If I know which cell I need to load (from an indexPath), how do I perform an action for only that cell?
I have a class for my UITableViewCell where I set up a few things, most importantly I position an MPMoviePlayer with an empty URL.
class TableViewCell: UITableViewCell {
#IBOutlet weak var titleLabel:UILabel!
#IBOutlet weak var movieView:UIView! //Set up in storyboard
var moviePlayer:MPMoviePlayerController!
var videoURL:NSURL!
override func awakeFromNib() {
super.awakeFromNib()
//initialize movie player
moviePlayer = MPMoviePlayerController(contentURL: videoURL)
}
override func layoutSubviews() {
//layout movieplayer
moviePlayer.view.frame = movieView.bounds
moviePlayer.view.center = CGPointMake(CGRectGetMidX(movieView.bounds), CGRectGetMidY(movieView.bounds))
movieView.addSubview(moviePlayer.view)
}
//Action to load video
func displayVideo() {
println("Should display Video at specified indexPath")
moviePlayer = MPMoviePlayerController(contentURL: videoURL)
moviePlayer.movieSourceType = MPMovieSourceType.File
moviePlayer.repeatMode = MPMovieRepeatMode.One
moviePlayer.controlStyle = MPMovieControlStyle.None
moviePlayer.prepareToPlay()
moviePlayer.play()
}
}
displayVideo is the vital function here. It needs to load ONLY when the tableViewCell is taking up a majority of the view. Therefore, I can't call it in cellForRowAtIndexPath.
All I do in cellForRowAtIndexPath is load a label into each cell and set a height variable for adjusting the heightForRowAtIndexPath:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell:TableViewCell = tableView.dequeueReusableCellWithIdentifier("tableViewCell", forIndexPath: indexPath) as TableViewCell
//Get height of movieView so we can adjust height of row
if didSetRowHeight == false {
movieViewHeight = myCell.movieView.frame.height
didSetRowHeight = true
}
//Set label in each cell to the right college
myCell.titleLabel.text = titleLabels[indexPath.row]
//This does NOT WORK; loads movies that are not taking majority of view
//myCell.videoURL = NSURL(string: videoFiles[indexPath.row].url)
return myCell
}
Next, I determine the indexPath for the cell that is in the majority of the view when scrolling stops. This value is held in indexPathToLoad
override func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
//Array to hold distance of visible cells to top of screen
var distancesToTop = [CGFloat]()
//Clean out array from previous scroll
distancesToTop.removeAll(keepCapacity: true)
//Array of visible cell indexPaths
var indexPaths = tableView.indexPathsForVisibleRows()!
for visibleCell in tableView.visibleCells() { //for each visible cell...
//Append the distance to top of screen
distancesToTop.append(abs((visibleCell.frame.minY - tableView.contentOffset.y) - 64))
}
//Find the lowest distance to top
let numMin = distancesToTop.reduce(CGFloat.max, { min($0, $1) })
//Determine the objectForIndexPath that the minimum number was in
let num = find(distancesToTop, numMin)!
//Use that to determine the indexPathToLoad from the array of indexPaths
indexPathToLoad = indexPaths[num]
//This successfully prints the indexPath that I need to load a movie
println("indexPath to load: \(indexPathToLoad.row)")
//Here's where it gets funky:
//Attempt to access cell from this function so we can load the video at the proper indexPath
var cell:TableViewCell = tableView.dequeueReusableCellWithIdentifier("tableViewCell", forIndexPath: indexPathToLoad as NSIndexPath) as TableViewCell
//Load the proper video...
cell.videoURL = NSURL(string: videoFiles[indexPathToLoad.row].url)
cell.displayVideo()
}
So I know precisely which tableViewCell that displayVideo() needs to be applied to, but it seems to choose a totally random indexPath, rather than the one specified in indexPathToLoad.
Any help is GREATLY APPRECIATED. I have been struggling with this for days.
The line
var cell:TableViewCell = tableView.dequeueReusableCellWithIdentifier("tableViewCell", forIndexPath: indexPathToLoad as NSIndexPath) as TableViewCell
should look something like
if let cell = tableView.cellForRowAtIndexPath(indexPathToLoad) as? TableViewCell {
cell.displayVideo()
}
There is a UITableViewDelegate protocol method
optional func tableView(_ tableView: UITableView,
willDisplayCell cell: UITableViewCell,
forRowAtIndexPath indexPath: NSIndexPath)
Implement this method and inside it check if the indexPath is the one that you want and if it is do the work that needs to be done.