I created a Swift class that inherits from UICollectionViewFlowLayout and i've been able to successfully do some neat stuff like change the spacing between each box that it draws. I'm drawing a calendar so just imagine 28-31 boxes, 7 per row, depending on the month.
..one thing I never figured out was how to do something like make the right border blank vs. not. Or the top border. I recently changed the spacing to 0 between each box, and now the boxes' borders overlap.
I'd love to programmatically make all the right borders blank so the left border of it's next one acts as the mutual border (so it's not a double border). Then, on the last box in the collection for each row, I can make that have a right border. Know what I'm saying? Nice clean thin border around each box.
Do I do this in my override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? Perhaps somewhere else?
Thanks!
BANG! I figured it out. This is so cool, because now I can programmatically decide when to add the borders below (i.e. if x then day.layer.addSublayer(topBorder), otherwise don't add it)
func collectionView(collectionView: UICollectionView!, cellForItemAtIndexPath indexPath: NSIndexPath!) -> UICollectionViewCell!
{
let day = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! CalendarDayCollectionViewCell
/* adds a border to entire grid */
day.layer.borderColor = UIColor.lightGrayColor().CGColor
//day.layer.borderWidth = 1 //can also do .cornerRadius to round out borders
//top border
let topBorder = CALayer()
topBorder.frame = CGRectMake(0.0, 0.0, day.frame.size.width, 1.0);
topBorder.backgroundColor = UIColor(white: 0.8, alpha: 1.0).CGColor
// bottom border
let bottomBorder = CALayer()
bottomBorder.frame = CGRectMake(0.0, day.frame.size.height-1, day.frame.size.width, 1.0);
bottomBorder.backgroundColor = UIColor(white: 0.8, alpha: 1.0).CGColor
let leftBorder = CALayer()
leftBorder.frame = CGRectMake(0.0, 0.0, 1.0, day.frame.size.height);
leftBorder.backgroundColor = UIColor(white: 0.8, alpha: 1.0).CGColor
let rightBorder = CALayer()
rightBorder.frame = CGRectMake(day.frame.size.width - 1, 0.0, 1.0, day.frame.size.height);
rightBorder.backgroundColor = UIColor(white: 0.8, alpha: 1.0).CGColor
day.layer.addSublayer(topBorder)
day.layer.addSublayer(bottomBorder)
day.layer.addSublayer(leftBorder)
day.layer.addSublayer(rightBorder)
return day
}
You cannot really explicitly remove one side or two sides of a border, not support by CALayer.
But based on this answer, you should be able to achieve by overlapping the cells, so you're correct that you should override func layoutAttributesForElementsInRect(rect: CGRect)
BTW, I think you can have a try with
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
let borderWidth = 5
return UIEdgeInsetsMake(-borderWidth,-borderWidth,-borderWidth,-borderWidth);
}
Related
I created CAShapeLayer border for view using the below code:
func addBorderToWebView() {
borderShape = CAShapeLayer()
borderShape.path = UIBezierPath(rect: webView.frame).cgPath
borderShape.lineWidth = CGFloat(2)
borderShape.bounds = borderShape.path!.boundingBox
borderShape.strokeColor = UIColor(red: 68/255, green: 219/255, blue: 94/255, alpha: 1.0).cgColor
borderShape.position = CGPoint(x: borderShape.bounds.width/2, y: borderShape.bounds.height/2)
webView.layer.addSublayer(borderShape)
}
I right and bottom border lines are out of the frame, you can see it on the image below. However, if I define borderWidth property of webView.layer, everything appears to be showed fine. That is why I make a conclusion, that the problem is not in layout constraints. How should I configure UIBezierPath (or CAShapeLayer) to make the border be showed correctly? Thank you for any help!
Try to replace this
borderShape.path = UIBezierPath(rect: webView.frame).cgPath
with this:
borderShape.path = UIBezierPath(rect: webView.bounds).cgPath
Another possible cause of the problem is that webView's frame is not updated yet when you set it to borderShape. You can try to do self.view.updateLayoutIfNeeded() prior to adding border shape. If it doesn't help override the following method:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
updateBorderShape()
}
func updateBorderShape() {
borderShape.bounds = webView.bounds
borderShape.position = CGPoint(x: borderShape.bounds.width/2, y: borderShape.bounds.height/2)
}
This will make sure that every time your frames are updated, border shape is updated as well.
I have a table view and I need to show author_img in section header. In ViewForSectionHeader method, I want to make the image to be circular. But If I did that, the images are not showing at all, no matter in simulator or in real device. If I remove the code, uiimageview will show the images normally. I set up the width and height constraint for uiimageview because I want to get fixed size of showing images. So Any ideas, please?
cell.author_img.layer.cornerRadius = cell.author_img.frame.size.width/2
cell.author_img.layer.masksToBounds = true
// add a boundary for thumb
cell.author_img.layer.borderWidth = 1.5
cell.author_img.layer.borderColor = UIColor.whiteColor().CGColor
It may come from the fact that you are setting the cornerRadius too early, the final size of your author_img is not fixed yet.
Try to set that cornerRadius when you are sure that the layout of your cell has been entirely calculated.
For test purpose, just to make sure it is coming from this behaviour, try to hardcode the cornerRadius.
cell.author_img.layer.cornerRadius = 10
If your image has a slight cornerRadius, it means that the issue is coming from what I explained earlier, if it is still not showing, it is coming from something else.
If it does come from the fact the size of your image is not fixed, try to set your cornerRadius in something like viewDidAppear, I mean the latest you can do.
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView : UIView = UIView.init(frame: CGRectMake(0, 0, tableView.frame.size.width, 40))
headerView.backgroundColor = UIColor(red: 75/255.0, green: 193/255.0, blue: 210/255.0, alpha: 1.0)
let iconimage: UIImageView = UIImageView(frame: CGRectMake(10, 0, 40, 40))
iconimage.image = UIImage(named: "original.jpg")
iconimage.layer.cornerRadius = iconimage.frame.size.height / 2
iconimage.layer.borderColor = UIColor.whiteColor().CGColor
iconimage.layer.borderWidth = 1.0
iconimage.clipsToBounds = true
let subjectNameLabel = UILabel(frame: CGRect(x: 60, y: 4, width: 250, height: 35))
subjectNameLabel.textAlignment = NSTextAlignment.Center
subjectNameLabel.font = UIFont (name: "HelveticaNeue", size: 16)
subjectNameLabel.textColor = UIColor.whiteColor()
headerView.userInteractionEnabled = true
if isFristtime == true {
let subjectNameTxtValue = "Mile Ho Tum Humko"
subjectNameLabel.text = subjectNameTxtValue
}else{
let subjectNameTxtValue = "Saiyaan"
subjectNameLabel.text = subjectNameTxtValue
}
subjectNameLabel.backgroundColor = UIColor(red: 75/255.0, green: 193/255.0, blue: 210/255.0, alpha: 1.0)
headerView.addSubview(iconimage)
headerView.addSubview(subjectNameLabel)
return headerView
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 40
}
i am trying to get a cell to resize to the text/or image inside it. But also the labels have some rounded corners depending on their position. I have tried using snippets like:
let path = UIBezierPath(roundedRect:cell.receivedText!.bounds, byRoundingCorners:[.TopRight, .BottomLeft, .BottomRight], cornerRadii: CGSizeMake(30, 30))
let maskLayer = CAShapeLayer()
maskLayer.path = path.CGPath
cell.receivedText!.layer.mask = maskLayer
and
tableView.estimatedRowHeight = 44
tableView.rowHeight = UITableViewAutomaticDimension
but i cant get the two to work in conjunction.
Here is my current code minus snippets that didnt work:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
createConversation()
let cell: ConversationCell = tableView.dequeueReusableCellWithIdentifier("ConversationCell") as! ConversationCell
if conversation.conversationArray[indexPath.row].isAReceivedMessage == true {
cell.receivedText!.text = conversation.conversationArray[indexPath.row].text
cell.receivedText!.textAlignment = .Left
cell.receivedText!.sizeToFit()
cell.receivedProfileImage!.image = self.conversationProfileImage!.image
cell.receivedText!.backgroundColor = UIColor(red: 44/255, green: 99/255, blue: 105/255, alpha: 5/100)
} else {
cell.sentText!.text = conversation.conversationArray[indexPath.row].text
cell.sentText!.textAlignment = .Right
cell.sentText!.backgroundColor = UIColor(red: 204/255, green: 115/255, blue: 115/255, alpha: 1)
cell.sentText!.sizeToFit()
}
return cell
}
This is what im trying to achieve
Thanks for any help in advance.
but i cant get the two to work in conjunction.
There are two problems:
Timing. When a view is resized, its mask is not resized. Thus, if you attach the mask before you know the final size of the view, you will get the wrong answer.
Resuse. Don't forget that a cell is reused. Thus, in cellForRow, you always need to remove the existing mask if there is one, because you're doing to be making another one to fit the new resized cell.
I have tableView cellForRowAtIndexPath function:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: ProjectCell = tableView.dequeueReusableCellWithIdentifier("Cell") as! ProjectCell
let rightUtilityButtons = NSMutableArray()
rightUtilityButtons.sw_addUtilityButtonWithColor(UIColor(red: 255.0/255.0, green: 200.0/255.0, blue: 122.0/255.0, alpha: 1.0), icon: UIImage(named: "ic_edit"))
rightUtilityButtons.sw_addUtilityButtonWithColor(UIColor(red: 255.0/255.0, green: 120.0/255.0, blue: 122.0/255.0, alpha: 1.0), icon: UIImage(named: "ic_close"))
cell.setRightUtilityButtons(rightUtilityButtons as [AnyObject], withButtonWidth: 70)
cell.delegate = self
let project = projects[indexPath.row] as! Project
cell.projectNameLabel.text = project.name
cell.projectDescriptionLabel.text = project.desc
cell.projectDateLabel.text = project.duedate
cell.customView.backgroundColor = getColor(indexPath.row * 10)
cell.backView.layer.cornerRadius = 6
cell.backView.layer.shadowColor = UIColor.blackColor().CGColor
cell.backView.layer.shadowOffset = CGSize(width: -1, height: 1)
cell.backView.layer.shadowOpacity = 0.5
return cell
}
And Problem is here:
cell.backView.layer.shadowColor = UIColor.blackColor().CGColor
cell.backView.layer.shadowOffset = CGSize(width: -1, height: 1)
cell.backView.layer.shadowOpacity = 0.5
Without this code, my table view works great. How to solve this problem. Maybe better place for my cell view will be willDisplayCell, but how to put this code there?
Move the code you are setting the shadow to cell's initialization. Right now, the shadow is set every time delegate returns cell to the table view. You don't have to do this for cells that are just being reused and already have shadow configured.
Remember to set shadowPath when dealing with shadows. It improves performance.
[view.layer setShadowPath:[[UIBezierPath bezierPathWithRect:view.bounds] CGPath]];
You can try next things to improve shadow performance:
Move shadow initialization to cell's initialization methods.
Rasterize your layer, using shouldRasterize property of CALayer (also you should set rasterizationScale property to UIScreen.mainScreen().scale)
Use shadowPath property of CALayer instead shadowOffset, like this:
_
var shadowBounds = self.bounds
shadowBounds = CGRectOffset(shadowBounds, -1, 1)
let cornerRadius = 6
layer.shadowPath = UIBezierPath(roundedRect: shadowBounds, cornerRadius: cornerRadius).CGPath
As an alternative way you can use resizable transparent image below your cell.
I've a tableView and I'm trying to add black mask on each image in the cell not on the whole cell just on the image. But I have two issues;
-It is masking the half cell from the left to the middle and each I scroll it is becoming darker. So please where would be my issue?
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! PlacesTableViewCell
cell.backgroundImage.sd_setImageWithURL(NSURL(string: place.Image), placeholderImage: nil, options: .HighPriority)
}
class PlacesTableViewCell: UITableViewCell {
override func layoutSubviews() {
super.layoutSubviews()
maskArrangement()
}
func maskArrangement(){
var maskLayer = CALayer()
maskLayer.frame = CGRectMake(0, 0, backgroundImage.frame.size.width, backgroundImage.frame.size.height)
maskLayer.backgroundColor = UIColor(white: 0.0, alpha: 0.5).CGColor
//backgroundImage.layer.mask = maskLayer
backgroundImage.layer.addSublayer(maskLayer)
}
}
Every time cell is dequeued you are adding new sublayer to your backgroundImage. In this way it is getting darker when you scroll (when you dequeued your cells). I think you can add to your PlacesTableViewCell class at awakeFromNib method if it has a .xib file.
Meanwhile your image's frame should be half of the cell. Use autolayout to fix it's frame (for instance, set width and height constraints) in your PLacesTableViewCell class.
In #Shripada 's way:
class PlacesTableViewCell: UITableViewCell {
var maskLayer : CALayer
override func layoutSubviews() {
super.layoutSubviews()
maskArrangement()
}
func maskArrangement(){
if maskLayer == nil {
maskLayer.frame = CGRectMake(0, 0, backgroundImage.frame.size.width, backgroundImage.frame.size.height)
maskLayer.backgroundColor = UIColor(white: 0.0, alpha: 0.5).CGColor
//backgroundImage.layer.mask = maskLayer
backgroundImage.layer.addSublayer(maskLayer)
}
}
}
I haven't tried this code. But your solution can be like that.