How to make separator (Single Line) transparent in Tableview? - uitableview

I have used table view in my application, and within that I have used the single line separator given by tableview.
How can I make a transparent separator in a tableview?
If anybody has any ideas/code snippets/useful links, I would greatly appreciate it.

it's very simple
in your viewdidload use this
[yourTableView setSeparatorColor:[UIColor clearColor]];

Just in case someone is still looking for solution with 'transparent' separator of any height:
Inside custom UITableViewCell:
override func layoutSubviews() {
super.layoutSubviews()
let mutablePath = CGMutablePath()
mutablePath.addRect(self.bounds)
// frame for your separator
let frame = CGRect(x: 0, y: 55, width: self.bounds.size.width, height: 5)
mutablePath.addRect(frame)
let mask = CAShapeLayer()
mask.path = mutablePath
mask.fillRule = CAShapeLayerFillRule.evenOdd
self.layer.mask = mask
if !(self.superview?.isKind(of: UITableView.self) ?? false) {
self.superview?.layer.mask = mask
}
}

Just use
tableView.separatorColor = .clear

Related

UIScrollView Subviews being misplaced when scaled down and Subviews not showing up when rounded

so I'm making my first Swift iOS app. I have two problems that I would like some help with.
First problem: I'm running into some issues with subviews that I created programmatically not being aligned properly when displayed on a small screen.
This first picture shows how I intend the scrollview to look. (iPhone 11 Pro Max)
However, this is what it looks like when it's on a smaller screen. (iPhone 8)
I think the issue is with me creating the subviews programmatically as the scrollview's size is what I want it to be.
Here's the swift code that I used inside viewDidLoad():
var districtNewsSize = 10;
var districtNewsFrame = CGRect(x:0,y:0,width:0,height:0);
// District News -----
districtNewsPageControl.numberOfPages = districtNewsSize;
for aIndex in 0..<districtNewsSize{
districtNewsFrame.origin.x = districtNewsScrollView.frame.size.width * CGFloat(aIndex);
districtNewsFrame.size = districtNewsScrollView.frame.size;
// create content in scrollview
let contentView = UIButton(frame: districtNewsFrame);
contentView.backgroundColor = makeColor(r: 147, g: 66, b: 78);
contentView.setTitle("titletext", for: .normal);
contentView.layer.cornerRadius = 20; // just to show how displaced the views are
// add contentview to scrollview
self.districtNewsScrollView.addSubview(contentView);
}
// change horizontal size of scrollview
districtNewsScrollView.contentSize = CGSize(width: districtNewsScrollView.frame.size.width * CGFloat(districtNewsSize), height: districtNewsScrollView.frame.size.height);
districtNewsScrollView.delegate = self;
Second Problem: When attempting to round the top two corners of the scrollview, the content inside the scrollview seems to disappear.
This is a picture of the first subview.
This is a picture of the second subview.
I also have a suspicion that this is caused by my function that I am using to round the top edges.
Here's the extension function I made for UIScrollView:
extension UIScrollView{
func setRoundedEdge(corners:UIRectCorner, radius: CGFloat){ // label.setRoundedEdge([.TopLeft, . TopRight], radius: 10)
let maskPath1 = UIBezierPath(roundedRect: bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
let maskLayer1 = CAShapeLayer()
maskLayer1.frame = bounds
maskLayer1.path = maskPath1.cgPath
layer.mask = maskLayer1
}
}
This is how I'm calling the function in viewDidLoad():
districtNewsScrollView.setRoundedEdge(corners: [.topRight,.topLeft], radius: 30);
Any help will greatly be appreciated. I've been stuck on these two problems and can't find anything online (probably because I'm not wording it right but I don't know how to describe these issues). Thank you!
I assume you are using storyboard for scrollview and programmatically adding subviews in viewDidLoad,
districtNewsFrame.origin.x = districtNewsScrollView.frame.size.width * CGFloat(aIndex);
districtNewsFrame.size = districtNewsScrollView.frame.size;
Should be changed to
districtNewsFrame.origin.x = UIScreen.main.bounds.size.width * CGFloat(aIndex);
districtNewsFrame.size = UIScreen.main.bounds.frame.size;
Use screen's size on viewDidLoad since the views in storyboards are loaded but constraints in auto layout is not yet applied.
For second question,
change extension to
extension UIScrollView{
func setRoundedEdge(corners:UIRectCorner, radius: CGFloat){ // label.setRoundedEdge([.TopLeft, . TopRight], radius: 10)
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
layer.mask = mask
}
}
and view controller to
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews();
districtNewsScrollView.setRoundedEdge(corners: [.topRight,.topLeft], radius: 30);
}
Here's what I did to fix both issues:
// District News -----
districtNewsFrame.size = districtNewsScrollView.frame.size;
districtNewsFrame.size.width = UIScreen.main.bounds.size.width - 34;
for aIndex in 0..<districtNewsSize{
//districtNewsFrame.origin.x = (UIScreen.main.bounds.size.width-52) * CGFloat(aIndex);
//districtNewsFrame.size = UIScreen.main.bounds.size;
districtNewsFrame.origin.x = (districtNewsFrame.size.width * CGFloat(aIndex));
// create content in scrollview
let contentView = UIButton(frame: districtNewsFrame); // wrapper for article
//testButton.setImage(UIImage(named: "ahsldpi.png"), for: .normal);
contentView.backgroundColor = makeColor(r: 147, g: 66, b: 78);
// content inside contentView -------
let articleContentFrame = CGRect(x:0,y:0,width:districtNewsFrame.width,height:districtNewsFrame.height-60);
let articleContent = UIView(frame: articleContentFrame); // may be image?
articleContent.backgroundColor = makeColor(r: 138, g: 138, b: 138);
let articleLabelFrame = CGRect(x:0,y:districtNewsFrame.height-60,width:districtNewsFrame.width,height:60);
let articleLabel = UILabel(frame: articleLabelFrame);
articleLabel.text = " " + "Title";
articleLabel.backgroundColor = UIColor.white;
articleLabel.font = UIFont(name: "DINCondensed-Bold", size: 30);
// add content inside contentView to contentview
contentView.addSubview(articleContent);
contentView.addSubview(articleLabel);
// add contentview to scrollview
contentView.setRoundedEdge(corners: [.topRight,.topLeft,.bottomLeft,.bottomRight], radius: 30);
self.districtNewsScrollView.addSubview(contentView);
}
// change horizontal size of scrollview
districtNewsScrollView.contentSize = CGSize(width: (districtNewsFrame.size.width * CGFloat(districtNewsSize)), height: districtNewsScrollView.frame.size.height);
districtNewsScrollView.delegate = self;
```

How to change Accessory type -> Disclosure Indicator color in my cell?

I can't change the default Accessory Type->Disclosure Indicator view's color in my UItableviewCell.
When I change tableviewcell tint color, it changes the following Accessory Type view color.
Detail Disclosure
Detail
CheckMark
But I can't change the "Disclosure Indicator" color.
Do you have any other option to change 'Disclosure Indicator' color other than to set image in accessory view?
Screenshots:
Cell:
Xcode menu:
You can put your image in accessoryView and your problem solved.
Sample Code
Put this code in cellForRowAtIndexPath
UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 11, 22, 22)];
imgView.contentMode = UIViewContentModeScaleAspectFit;
imgView.image = [UIImage imageNamed:#"IconMore"];
cell.accessoryView = imgView;
Apple does not provide any option for this, you can do by creating custom UIView. Please find below custom View for the same,
import UIKit
class CustomDisclosureIndicator: UIView {
#IBInspectable
public var color: UIColor = UIColor.darkGray {
didSet {
setNeedsDisplay()
}
}
override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
let x = self.bounds.maxX - 3
let y = self.bounds.midY
let R = CGFloat(4.5)
context?.move(to: CGPoint(x: x-R, y: y-R))
context?.addLine(to: CGPoint(x: x, y: y))
context?.addLine(to: CGPoint(x: x-R, y: y+R))
context?.setLineCap(.square)
context?.setLineJoin(.miter)
context?.setLineWidth(2)
color.setStroke()
context?.strokePath()
}
}
You can do following way,
Above code produces following output.
Try it once and let me know if any other queries are there.

Why is my table view shadow scrolling with my table view?

I added shadow to my table view but unfortunately when I scroll through the table view the shadow also moves with the table. The code for adding shadow is as follows:
func addShadow(to myView: UIView){
let shadowPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: uiView.frame.width, height: uiView.frame.height * 1.1))
uiView.layer.shadowColor = UIColor.black.cgColor
uiView.layer.shadowOffset = CGSize(width: 0.2, height: 0)
uiView.layer.shadowOpacity = 0.5
uiView.layer.shadowRadius = 5.0
uiView.layer.masksToBounds = false
uiView.layer.shadowPath = shadowPath.cgPath
}
Can you please explain to me why is this happening and how to make the shadow stick to its designated location?
Thank you in advance.
If you are adding shadow on tableView, it will scroll along with tableview data. To prevent that you have to add UIView first. Add tableview on that view. Add shadow for the UIView you have taken. It will stick to designated location.
This is my solution in Swift 3 with an UIView and a CAGradientLayer inside.
override func viewWillAppear(_ animated: Bool) {
addShadow(myView: myTab)
}
func addShadow(myView: UIView){
let shadowView = UIView()
shadowView.center = CGPoint(x: myView.frame.minX,y:myView.frame.minY - 15)
shadowView.frame.size = CGSize(width: myView.frame.width, height: 15)
let gradient = CAGradientLayer()
gradient.frame.size = shadowView.frame.size
let stopColor = UIColor.clear.cgColor
let startColor = UIColor.black.withAlphaComponent(0.8).cgColor
gradient.colors = [stopColor,startColor]
gradient.locations = [0.0,1.0]
shadowView.layer.addSublayer(gradient)
view.addSubview(shadowView)
}

Drawing underline for UIButton is hidden behind views

I have a viewcontroller with 3 UIButtons that have the same Y position but 20px apart from each other horizontally. When a button is selected, I'd like to draw a line beneath the button. I tried just adding the underline attribute, but the line isn't really customizable. I have the buttons on top of a UIImageView that is contained within a subclass of UIView I named SectionView.
In my view controller i have the following function that is called when a button is pressed:
#IBOutlet weak var sectionView: SectionView!
func sectionButtonPressed(sender: UIButton) {
self.sectionView.selectedButton = sender
self.sectionView.setNeedsDisplay()
}
In my UIView subclass, I have the following:
class SectionView: UIView {
var selectedButton: UIButton?
override func drawRect(rect: CGRect) {
let linePath = UIBezierPath()
linePath.moveToPoint(CGPoint(x:(self.selectedButton?.frame.origin.x)! - 3, y: (self.selectedButton?.frame.origin.y)! + 35))
linePath.addLineToPoint(CGPoint(x: (self.selectedButton?.frame.origin.x)! + (self.selectedButton?.frame.width)! + 3, y: (self.selectedButton?.frame.origin.y)! + 35))
linePath.closePath()
UIColor.purpleColor().set()
linePath.stroke()
linePath.fill()
}
}
I can get the line to draw at the position and length I desire, but its beneath the UIButton and UIImageView. How can I get it to appear above?
func addLine(button:UIButton)// pass button object as a argument
{
let length = button.bounds.width
let x = button.bounds.origin.x
let y = button.bounds.origin.y + button.bounds.height - 5
let path = UIBezierPath()
path.move(to: CGPoint(x: x, y: y))
path.addLine(to: CGPoint(x: x + length , y:y))
//design path in layer
let lineLayer = CAShapeLayer()
lineLayer.path = path.cgPath
lineLayer.strokeColor = UIColor.red.cgColor
lineLayer.lineWidth = 1.0
lineLayer.fillColor = UIColor.clear.cgColor
button.layer.insertSublayer(lineLayer, at: 0)
}`
// This code will create one line below your button(using UIBezierPath and Layers )
I had to change it up. Instead of using a bezier path, I ended up creating a UIView and placing it above the other views.
func sectionButtonPressed(sender: UIButton) {
let lineView = createView(sender)
self.sectionView.addSubview(lineView)
}
func createView(sender:UIButton) -> UIView {
let customView = UIView(frame: CGRect(x: sender.frame.origin.x, y: sender.frame.origin.y + 12, width: sender.frame.width, height: 2.0))
customView.backgroundColor = UIColor.purpleColor()
return customView
}
Remember, my buttons are on top of a UIImageView that is contained within a UIView. When I tried to add the line view as a subview to the imageview, the line wouldn't line up with the x origin of the button. So instead I added the line view as a subview to the UIView and it came out looking correct.
We can use CALayer to draw lines. Add the following code in your button action, this may help.
#IBAction func sectionButtonPressed(sender: AnyObject) {
let border = CALayer()
border.borderColor = UIColor.purpleColor().CGColor
border.frame = CGRect(x: 0, y: sender.frame.size.height - 2,
width: sender.frame.size.width, height: 2)
border.borderWidth = 2.0
sender.layer.addSublayer(border)
sender.layer.masksToBounds = true
}
RESULT:

Adding Bottom Line Border To A TextView - iOS

What is the best way to add a bottom line border to a TextView with a dynamic height?
I tried this:
func addBottomBorderWithColor(color: UIColor, width: CGFloat) {
let border = CALayer()
border.backgroundColor = color.CGColor
border.frame = CGRectMake(0, self.frame.size.height - width,
self.frame.size.width, width)
self.layer.addSublayer(border)
self.layer.masksToBounds = true
}
Swift 4 Version
func addBottomBorderWithColor() {
let border = CALayer()
border.backgroundColor = UIColor.black.cgColor
border.frame = CGRect(x: 0, y: yourTextArea.frame.height - 1, width: yourTextArea.frame.width, height: 1)
yourTextArea.layer.addSublayer(border)
self.view.layer.masksToBounds = true
}
Update:
I thought a lot about my original solution.
If you are subclassing UITextView to add a bottom line, then the bottom line had better be a subview of the text view itself, rather than its super view's.
And finally, I figure out one solution that can add bottom line as a subview of TextView itself and the bottom line will not move when the user scrolls the text of TextView. In your view controller, you can also change the frame of TextView dynamically, and the bottom line will also stick to the the bottom.
Here is the reference code:
import UIKit
class TextView: UITextView {
var border: UIView
var originalBorderFrame: CGRect
var originalInsetBottom: CGFloat
deinit {
removeObserver(self, forKeyPath: "contentOffset")
}
override var frame: CGRect {
didSet {
border.frame = CGRectMake(0, frame.height+contentOffset.y-border.frame.height, frame.width, border.frame.height)
originalBorderFrame = CGRectMake(0, frame.height-border.frame.height, frame.width, border.frame.height);
}
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if keyPath == "contentOffset" {
border.frame = CGRectOffset(originalBorderFrame, 0, contentOffset.y)
}
}
func addBottomBorderWithColor(color: UIColor, width: CGFloat) {
border.backgroundColor = color
border.frame = CGRectMake(0, frame.height+contentOffset.y-width, self.frame.width, width)
originalBorderFrame = CGRectMake(0, frame.height-width, self.frame.width, width)
textContainerInset.bottom = originalInsetBottom+width
}
}
Note: Since I used to write code in Objective-C, I am not familiar with Swift. The code above is only for your reference (though I have tested the corresponding Objective-C code, and it works as expected):
As you can see, there is no initialisation code. I have tried to write such code, but it always shows an error and I still have no idea about that. Just make sure to add the below code to your TextView initialisation code:
border = UIView()
addSubview(border)
originalInsetBottom = textContainerInset.bottom
addObserver(self, forKeyPath: "contentOffset", options: .New, context: nil)
I am not familiar with the concept of optional value, wrap, unwrap... So you should add ?, ! to the code if needed.
Original answer:
Does self in your code mean TextView?
If so, when you add border as a sublayer of the TextView, the border will move up and down when the user scrolls the text of TextView.
Try to add border as a sublayer of TextView's super view rather than TextView itself.
Here is the code (Note that I change border from CALayer to UIView):
func addBottomBorderWithColor(color: UIColor, width: CGFloat) {
let border = UIView()
border.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y+self.frame.height-width, textView.frame.width, width)
border.backgroundColor = color
self.superview!.insertSubview(border, aboveSubview: textView)
}
Here is the capture:
PS. I suggest you to change the second paramter name from width to height since width is ambiguous in this context.
It works better with following line:
border.autoresizingMask = [.flexibleWidth, .flexibleHeight]
extension UITextView {
func addBottomBorderWithColor(color: UIColor, height: CGFloat) {
let border = UIView()
border.autoresizingMask = [.flexibleWidth, .flexibleHeight]
border.frame = CGRect(self.frame.origin.x,
self.frame.origin.y+self.frame.height-height, self.frame.width, height)
border.backgroundColor = color
self.superview!.insertSubview(border, aboveSubview: self)
}
}
I've tried other answers, they are either hard to implement, or come with bugs, however, I've found a simple and perhaps the best way to achieve this:
Just add a UIView next to your UITextView, with a height of 1 (or maybe 2 of your choice), set up the constraints, make sure the UIView is above the UITextView.
All of this can be achieved in storyboard so I'm not giving code here, since this UIView can be replaced with an UIImageView, you can add mustache to your UITextView if you wish
:)
Set the mask to bounds to be false then only it show the bounds of the line that you want to show..
Try following code it may helps you
func addBottomBorderWithColor(color: UIColor, width: CGFloat) {
let border = CALayer()
border.backgroundColor = color.CGColor
border.frame = CGRectMake(0, yourTextview.frame.origin.y+yourTextview.frame.size.height+1 , width, 1)
self.view.layer.addSublayer(border)
self.view.layer.masksToBounds = true
}
Sometimes it's easier to just keep things a little more independent of one another.
UIImageView * border = [UIImageView new];
border.frame = CGRectMake(0,y,100,0.5f);
border.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.3f];
[self.view addSubview:border];

Resources