What am I doing wrong in this really basic UIScrollView - ios

I am trying to get this really basic UIScrollView to scroll horizontally and not vertically at all. I am following this example here on the Xamarin developer site: https://developer.xamarin.com/recipes/ios/content_controls/scroll_view/create_a_horizontal_scrolling_button_list/ But I cannot get the buttons to take up the entire scroll view and only scroll horizontally. I keep getting weird padding on the top and bottom of the list of buttons. Here is my entire class:
public partial class StackViewController : UIViewController
{
public StackViewController()
{
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
this.View.BackgroundColor = UIColor.White;
nfloat h = 50.0f;
nfloat w = 50.0f;
nint n = 25;
UIScrollView scrollView = new UIScrollView
{
Frame = new CGRect(0, 100, View.Frame.Width, 100),
ContentSize = new CGSize((w) * n, h),
BackgroundColor = UIColor.Green
};
for (int i = 0; i < n; i++)
{
var button = new UIButton();
button.SetTitle(i.ToString(), UIControlState.Normal);
button.Frame = new CGRect((i * w), 0, w, h);
button.BackgroundColor = UIColor.Blue;
scrollView.AddSubview(button);
}
View.AddSubview(scrollView);
}
}
Somehow I am missing some padding or layout property that I don't know about. I am semi-new to Xamarin ios development and I know that there is something simple that I am missing.

UIScrollviews can often add indicator insets as well as content insets. What I'd suggest doing is to override the 'ViewDidLayoutSubviews' method and put in the following code:
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
scrollView.ContentInset = UIEdgeInsets.Zero;
scrollView.ScrollIndicatorInsets = UIEdgeInsets.Zero;
}

Related

Setting the font on navigation bar buttons in a Xamarin Forms iOS 13+ app

I'm trying to set the font for navigation buttons (specifically the Back button) in Xamarin iOS (13+) apps. I found this this solution which claims to work but didn't, for me at least:
var style = new UINavigationBarAppearance();
var a = new UIStringAttributes();
a.Font = UIFont.SystemFontOfSize(35);
a.ForegroundColor = UIColor.Yellow;
style.TitleTextAttributes = a;
var dic = new NSDictionary<NSString, NSObject>(
new NSString[] {a.Dictionary.Keys[0] as NSString, a.Dictionary.Keys[1] as NSString }, a.Dictionary.Values
);
var button = new UIBarButtonItemAppearance(UIBarButtonItemStyle.Plain);
button.Normal.TitleTextAttributes = dic;
button.Highlighted.TitleTextAttributes = dic;
style.ButtonAppearance = button;
UINavigationBar.Appearance.StandardAppearance = style;
I then simplified it a little (seeing if I could simply recolour the nav bar title) but this again did nothing:
var style = new UINavigationBarAppearance();
var a = new UIStringAttributes()
{
ForegroundColor = UIColor.Yellow
};
style.TitleTextAttributes = a;
UINavigationBar.Appearance.StandardAppearance = style;
Playing around further I found, curiously, the following DOES recolour the navigation bar title:
var a = new UIStringAttributes()
{
ForegroundColor = UIColor.Yellow
};
UINavigationBar.Appearance.TitleTextAttributes = a;
...but using the same thought process, this does NOT recolour the navigation bar buttons:
var a = new UITextAttributes()
{
TextColor = UIColor.Yellow
};
UIBarButtonItem.Appearance.SetTitleTextAttributes(a, UIControlState.Normal);
Can anyone see why none of these approaches work for modifying the navigation bar button styling? Or might this be an issue with Xamarin?
UPDATE: I realised the first sample does work, but only in Xamarin iOS. It does not work in Xamarin Forms however. It looks like Xamarin Forms might be enforcing its own standard appearance which overrides what I put in my code.
In your case we could set a custom NavigationBar .
In your ViewController
If you want to let it works on all Controllers , you could define a base ViewController
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
var page = Element as ContentPage;
NavigationController.NavigationBar.Hidden = true;
double height = IsiphoneX();
UIView backView = new UIView()
{
BackgroundColor = UIColor.White,
Frame = new CGRect(0,20,UIScreen.MainScreen.Bounds.Width, height),
};
UIButton backBtn = new UIButton() {
Frame = new CGRect(20, height-44, 40, 44),
Font = UIFont.SystemFontOfSize(18), // set style here
} ;
backBtn.SetTitle("Back", UIControlState.Normal);
backBtn.SetTitleColor(UIColor.Blue, UIControlState.Normal);
backBtn.AddTarget(this,new Selector("GoBack"),UIControlEvent.TouchUpInside);
UILabel titleLabel = new UILabel() {
Frame=new CGRect(UIScreen.MainScreen.Bounds.Width/2-75, 0,150, height),
Font = UIFont.SystemFontOfSize(20),
Text = page.Title,
TextColor = UIColor.Black,
Lines = 0,
};
UILabel line = new UILabel() {
Frame = new CGRect(0, height, UIScreen.MainScreen.Bounds.Width, 0.5),
BackgroundColor = UIColor.Black,
};
backView.AddSubview(backBtn);
backView.AddSubview(titleLabel);
backView.AddSubview(line);
View.AddSubview(backView);
}
double IsiphoneX()
{
double height = 44; //set height as you want here !!!
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
if (UIApplication.SharedApplication.Delegate.GetWindow().SafeAreaInsets.Bottom > 0.0)
{
height = 64; //set height as you want here !!!
}
}
return height;
}
[Export("GoBack")]
void GoBack()
{
NavigationController.PopViewController(true);
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
NavigationController.NavigationBar.Hidden = false;
}
In this way you could set all style as you want like BackgroundColor , TextColor or even set the back button as an image .
I finally figured out an approach that works by overriding Xamarin Forms' constant enforcement of its own navigation bar styling:
public class MyNavigationRenderer : NavigationRenderer
{
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
UpdateStyle();
Element.PropertyChanged += HandlePropertyChanged;
}
void UpdateStyle()
{
var navigationBarAppearance = NavigationBar.StandardAppearance;
var titleTextAttributes = new UIStringAttributes
{
ForegroundColor = UIColor.Yellow,
Font = UIFont.SystemFontOfSize(35)
};
var dic = new NSDictionary<NSString, NSObject>(
new NSString[] { titleTextAttributes.Dictionary.Keys[0] as NSString, titleTextAttributes.Dictionary.Keys[1] as NSString }, titleTextAttributes.Dictionary.Values
);
var button = new UIBarButtonItemAppearance(UIBarButtonItemStyle.Plain);
button.Normal.TitleTextAttributes = dic;
button.Highlighted.TitleTextAttributes = dic;
navigationBarAppearance.ButtonAppearance = button;
NavigationBar.StandardAppearance = navigationBarAppearance;
NavigationBar.CompactAppearance = navigationBarAppearance;
NavigationBar.ScrollEdgeAppearance = navigationBarAppearance;
}
void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
{
UpdateStyle();
}
}

Overriding Back button navigation in Xamarin.IOS

I am trying to override the default back button behaviour of IOS, using Xamarin.IOS framework.
I have a stack of objects inside my ViewController, my requirement is that when the user presses back to navigate to previous ViewController, i will navigate only when my stack is empty otherwise i will stay in that screen(ViewController).
For this i tried several thing, like overriding the ViewWillDisappear and setting the PopViewController to false but i am unable to do this. Please guide.
public override void ViewWillDisappear(bool animated)
{
Stack<Object> st = vPage.uContentStack;
if (st.Count != 0)
{
Object pop_obj = st.Pop();
if (st.Count != 0)
{
NavigationController.PopViewController(false);// Here trying to stop navigating back
Object peek_obj = st.Peek();
vPage.ContentUpdateOnBackPress(pop_obj, peek_obj);
}
else
{
NavigationController.PopViewController(true);
}
}
else
{
NavigationController.PopViewController(true);
}
base.ViewWillDisappear(animated);
}
You could customize the Navigation Bar in the specific ViewController
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
NavigationController.NavigationBar.Hidden = true;
double height = IsiphoneX();
UIView backView = new UIView()
{
BackgroundColor = UIColor.White,
Frame = new CGRect(0, 20, UIScreen.MainScreen.Bounds.Width, height),
};
UIButton backBtn = new UIButton()
{
Frame = new CGRect(20, height - 44, 40, 44),
Font = UIFont.SystemFontOfSize(18),
};
backBtn.SetTitle("<", UIControlState.Normal);
// backBtn.SetBackgroundImage(UIImage.FromBundle("xx.png"),UIControlState.Normal); or you can set image here
backBtn.SetTitleColor(UIColor.FromRGB(60,140,250), UIControlState.Normal);
backBtn.AddTarget(this, new Selector("GoBack"), UIControlEvent.TouchUpInside);
UILabel titleLabel = new UILabel()
{
Frame = new CGRect(UIScreen.MainScreen.Bounds.Width / 2 - 75, 0, 150, height),
Font = UIFont.SystemFontOfSize(20),
Text = "xxx",
TextAlignment = UITextAlignment.Center,
TextColor = UIColor.Black,
Lines = 0,
};
UILabel line = new UILabel()
{
Frame = new CGRect(0, height, UIScreen.MainScreen.Bounds.Width, 0.5),
BackgroundColor = UIColor.Black,
};
backView.AddSubview(backBtn);
backView.AddSubview(titleLabel);
backView.AddSubview(line);
View.AddSubview(backView);
}
double IsiphoneX()
{
double height = 44;
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
if (UIApplication.SharedApplication.Delegate.GetWindow().SafeAreaInsets.Bottom > 0.0)
{
height = 64;
}
}
return height;
}
[Export("GoBack")]
void GoBack()
{
//handle logic here
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
NavigationController.NavigationBar.Hidden = false;
}
In this solution you could set the style of the navigation bar , like text color of title or icon of back button .

Xamarin iOS UINavigationBar weird overlay

I am working in Xamarin 4.5 with iOS 13. I am using Simulator to run the code. Here's how it looks.
I have added the following code to apply red color but its not hiding this white/grey overlay.
UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.LightContent;
UINavigationBar.Appearance.BarTintColor = UIColor.Red;
UINavigationBar.Appearance.TintColor = UIColor.Red;
UINavigationBar.Appearance.TitleTextAttributes = new UIStringAttributes
{
ForegroundColor = UIColor.Red
};
UINavigationBar.Appearance.BackgroundColor = UIColor.FromRGBA(255, 0, 0, 255);
Last line added the Red color.
It will be an expected effect because UINavigationBar has a default CALayer after iOS 11.0. As a workaround , we could create a custom NavigationBar by using custom renderer
in your iOS project
using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using xxx;
using xxx.iOS;
using CoreGraphics;
using ObjCRuntime;
[assembly:ExportRenderer(typeof(ContentPage),typeof(MyPageRenderer))]
namespace xxx.iOS
{
public class MyPageRenderer:PageRenderer
{
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
NavigationController.NavigationBar.Hidden = true;
double height = IsiphoneX();
UIView backView = new UIView()
{
BackgroundColor = UIColor.Red,
Frame = new CGRect(0, 20, UIScreen.MainScreen.Bounds.Width, height),
};
// set
UIButton backBtn = new UIButton()
{
Frame = new CGRect(20, height - 44, 40, 44),
Font = UIFont.SystemFontOfSize(18),
};
backBtn.SetTitle("<",UIControlState.Normal);
backBtn.SetTitleColor(UIColor.White,UIControlState.Normal);
backBtn.AddTarget(this, new Selector("GoBack"), UIControlEvent.TouchUpInside);
UILabel titleLabel = new UILabel()
{
Frame = new CGRect(UIScreen.MainScreen.Bounds.Width / 2 - 75, 0, 150, height),
Font = UIFont.SystemFontOfSize(20),
Text = "xxx",
TextColor = UIColor.White,
Lines = 0,
};
UILabel line = new UILabel()
{
Frame = new CGRect(0, height, UIScreen.MainScreen.Bounds.Width, 0.5),
BackgroundColor = UIColor.Black,
};
if (NavigationController.ViewControllers.Length > 1)
{
backView.AddSubview(backBtn);
}
backView.AddSubview(titleLabel);
backView.AddSubview(line);
View.AddSubview(backView);
}
double IsiphoneX()
{
double height = 44;
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
if (UIApplication.SharedApplication.Delegate.GetWindow().SafeAreaInsets.Bottom > 0.0)
{
height = 64;
}
}
return height;
}
[Export("GoBack")]
void GoBack()
{
NavigationController.PopViewController(true);
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
NavigationController.NavigationBar.Hidden = false;
}
}
}
You can set the property of title , backButton and navigationBar as you need (such as text , color ,BackgroundColor ,font e.g.)

Bottom Border Width on Swift TextField in TableView

i builded a static tableview with more Rowes than the screen has, so the user has to scroll to see all cell.
Every cell has a textfield with the following class to add a bottom border:
class TextFieldWithBottomBorder: UITextField {
let border = CALayer()
let width = CGFloat(1.0)
func addBottomBorder(color: UIColor){
self.border.borderColor = color.cgColor
self.border.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height:self.frame.size.height)
self.border.borderWidth = self.width
self.layer.addSublayer(self.border)
self.layer.masksToBounds = true
}
func changeBorderColor(color: UIColor){
self.border.borderColor = color.cgColor
}
}
And i call the method after receiving some data from the server e. g.
self.firstnameTextField.text = firstNameFromDB
self.firstnameTextField.addBottomBorder(color: .blue)
This works fine for every cell is currently displayed. But the cells which are out of the current view the with is shorter than the textfield.
See this screenshot, for "Vorname", means firstName everything looks good, but for email, password etc. the border is to short.
http://share-your-photo.com/34b5e80253
Looks like the size of the UITextField is being resized after you have called addBottomBorder and so the UIView being used at the line is now not wide enough. It's difficult to say why this would be without seeing more code but there are several methods you could use to overcome it.
1) Switch to a UIView instead of a CALayer and use auto layout to keep the view in the correction position.
2) Override layoutSubviews to update the frame of the bottom line.
The simplest for you is probably option 2 (although I would go option 1) and it would look like this:
override func layoutSubviews() {
super.layoutSubviews()
self.border.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height:self.frame.size.height)
}
Now whenever the frame/size of the text field changes the frame/size of the border line CALayer will be updated appropriately.
Use this class for bottom line text field
#IBDesignable class BottomTextField: UITextField {
var lineView = UIView()
#IBInspectable var lineViewBgColor:UIColor = UIColor.gray{
didSet {
if !isFirstResponder {
lineView.backgroundColor = lineViewBgColor
}
}
}
required init?(coder aDecoder:NSCoder) {
super.init(coder:aDecoder)!
setup()
}
override init(frame:CGRect) {
super.init(frame:frame)
setup()
}
// MARK:- Private Methods
private func setup() {
lineView.frame = CGRect(x:CGFloat(0), y:self.frame.size.height-2, width:self.frame.size.width, height:CGFloat(1))
lineView.backgroundColor = lineViewBgColor
self.addSubview(lineView)
}
}

Draw a separator line in conjunction with Auto Layout

I'm reimplementig some kind of UISplitViewController. Now I need to draw a separator line between the master and the detail view. Now I have some questions for this:
Should the separator line be on the view controller itself or should it be a separate view?
What about Auto Layout? Setting a frame is not allowed.
I saw solutions for CALayer/CAShapeLayer, drawRect (CoreGraphics) or using the background color of an UIView/UILabel. The last one should cost too much performance according to the folks there.
On the one side it is comfortable to draw the line in the UITableViewController itself. Or should a separate UIView be created? If I embed a separate UIView there will be much more constraints and it will complicate things (would have to set separate widths) ... Also it should adapt to orientation changes (e.g. the size of the UITableViewController changes -> the separation line should also resize).
How can I add such a dividing rule? Such a dividing rule can be seen here:
If you need to add a true one pixel line, don't fool with an image. It's almost impossible. Just use this:
#interface UILine : UIView
#end
#implementation UILine
- (void)awakeFromNib {
CGFloat sortaPixel = 1 / [UIScreen mainScreen].scale;
// recall, the following...
// CGFloat sortaPixel = 1 / self.contentScaleFactor;
// ...does NOT work when loading from storyboard!
UIView *line = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, sortaPixel)];
line.userInteractionEnabled = NO;
line.backgroundColor = self.backgroundColor;
line.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[self addSubview:line];
self.backgroundColor = [UIColor clearColor];
self.userInteractionEnabled = NO;
}
#end
How to use:
Actually in storyboard, simply make a UIView that is in the exact place, and exact width, you want. (Feel free to use constraints/autolayout as normal.)
Make the view say five pixels high, simply so you can see it clearly, while working.
Make the top of the UIView exactly where you want the single-pixel line. Make the UIView the desired color of the line.
Change the class to UILine. At run time, it will draw a perfect single-pixel line in the exact location on all devices.
(For a vertical line class, simply modify the CGRectMake.)
Hope it helps!
I took #joe-blow's excellent answer a step further and created a view that is not only rendered in IB but also whose line width and line color can be changed via the inspector in IB. Simply add a UIView to your storyboard, size appropriately, and change the class to LineView.
import UIKit
#IBDesignable
class LineView: UIView {
#IBInspectable var lineWidth: CGFloat = 1.0
#IBInspectable var lineColor: UIColor? {
didSet {
lineCGColor = lineColor?.CGColor
}
}
var lineCGColor: CGColorRef?
override func drawRect(rect: CGRect) {
// Draw a line from the left to the right at the midpoint of the view's rect height.
let midpoint = self.bounds.size.height / 2.0
let context = UIGraphicsGetCurrentContext()
CGContextSetLineWidth(context, lineWidth)
if let lineCGColor = self.lineCGColor {
CGContextSetStrokeColorWithColor(context, lineCGColor)
}
else {
CGContextSetStrokeColorWithColor(context, UIColor.blackColor().CGColor)
}
CGContextMoveToPoint(context, 0.0, midpoint)
CGContextAddLineToPoint(context, self.bounds.size.width, midpoint)
CGContextStrokePath(context)
}
}
Updating the #mharper answer to Swift 3.x
import UIKit
#IBDesignable
class LineView: UIView {
#IBInspectable var lineWidth: CGFloat = 1.0
#IBInspectable var lineColor: UIColor? {
didSet {
lineCGColor = lineColor?.cgColor
}
}
var lineCGColor: CGColor?
override func draw(_ rect: CGRect) {
// Draw a line from the left to the right at the midpoint of the view's rect height.
let midpoint = self.bounds.size.height / 2.0
if let context = UIGraphicsGetCurrentContext() {
context.setLineWidth(lineWidth)
if let lineCGColor = self.lineCGColor {
context.setStrokeColor(lineCGColor)
}
else {
context.setStrokeColor(UIColor.black.cgColor)
}
context.move(to: CGPoint(x: 0.0, y: midpoint))
context.addLine(to: CGPoint(x: self.bounds.size.width, y: midpoint))
context.strokePath()
}
}
}
New code
This should work for horizontal and vertical lines:
/// <summary>
/// Used as separator line between UIView elements with a given color.
/// </summary>
public class DividerView : UIView
{
private UIColor color;
public DividerView ()
{
this.color = UIColor.Black;
}
public DividerView (UIColor color)
{
this.color = color;
}
public override void Draw (CGRect rect)
{
base.Draw (rect);
// get graphics context
CGContext context = UIGraphics.GetCurrentContext ();
// set up drawing attributes
color.SetStroke ();
color.SetFill ();
// assumption: we can determine if the line is horizontal/vertical based on it's size
nfloat lineWidth = 0;
nfloat xStartPosition = 0;
nfloat yStartPosition = 0;
nfloat xEndPosition = 0;
nfloat yEndPosition = 0;
if (rect.Width > rect.Height) {
// horizontal line
lineWidth = rect.Height;
xStartPosition = rect.X;
// Move the path down by half of the line width so it doesn't straddle pixels.
yStartPosition = rect.Y + lineWidth * 0.5f;
xEndPosition = rect.X + rect.Width;
yEndPosition = yStartPosition;
} else {
// vertical line
lineWidth = rect.Width;
// Move the path down by half of the line width so it doesn't straddle pixels.
xStartPosition = rect.X + lineWidth * 0.5f;
yStartPosition = rect.Y;
xEndPosition = xStartPosition;
yEndPosition = rect.Y + rect.Height;
}
// start point
context.MoveTo (xStartPosition, yStartPosition);
// end point
context.AddLineToPoint (xEndPosition, yEndPosition);
context.SetLineWidth (lineWidth);
// draw the path
context.DrawPath (CGPathDrawingMode.Stroke);
}
}
Original answer
Using frames in an Auto Layout project seems not suitable for me. Also I'd need the actual frames after auto layout has been applied and than I'd have to draw another view on top of it. In a fixed layout based on frames it is no problem, but not here. That's why I chose the following apporach for now:
I created a subclass of UIView and overwrote drawRect like in Draw line in UIView or how do you draw a line programmatically from a view controller?. Here is another option.
Because I'm using C# I give the code samples in that programming language. In the links I posted you can get the Objective-C version if you want.
DividerView:
using System;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.CoreGraphics;
using System.CodeDom.Compiler;
using System.Drawing;
namespace ContainerProject
{
public class DividerView : UIView
{
public DividerView ()
{
}
public override void Draw (RectangleF rect)
{
base.Draw (rect);
// get graphics context
CGContext context = UIGraphics.GetCurrentContext ();
// set up drawing attributes
UIColor.Black.SetStroke ();
UIColor.Black.SetFill ();
context.SetLineWidth (rect.Width);
// start point
context.MoveTo (rect.X, 0.0f);
// end point
context.AddLineToPoint (rect.X, rect.Y + rect.Height);
// draw the path
context.DrawPath (CGPathDrawingMode.Stroke);
}
}
}
In viewDidLoad of my container class I instantiate the DividerView with DividerView separator = new DividerView ();.
Auto Layout:
Then I'm using Auto Layout to layout it's position (all in viewDidLoad):
separator.TranslatesAutoresizingMaskIntoConstraints = false;
separatorTop = NSLayoutConstraint.Create (separator, NSLayoutAttribute.Top, NSLayoutRelation.Equal, TopLayoutGuide, NSLayoutAttribute.Bottom, 1, 0);
separatorBottom = NSLayoutConstraint.Create (separator, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, BottomLayoutGuide, NSLayoutAttribute.Top, 1, 0);
separatorRight = NSLayoutConstraint.Create (separator, NSLayoutAttribute.Right, NSLayoutRelation.Equal, documentListController.View, NSLayoutAttribute.Left, 1, 0);
separatorWidth = NSLayoutConstraint.Create (separator, NSLayoutAttribute.Width, NSLayoutRelation.Equal, null, NSLayoutAttribute.NoAttribute, 1, 1);
this.View.AddSubview (separator);
Here the constraints are added:
public override void UpdateViewConstraints ()
{
if (!hasLoadedConstraints) {
this.View.AddConstraints (new NSLayoutConstraint[] {
separatorTop,
separatorBottom,
separatorRight,
separatorWidth
});
hasLoadedConstraints = true;
}
base.UpdateViewConstraints ();
}
Result:
This approach seems to work. Now my separator line is overlapping my detail view (only the first point). One could adapt the values or changes the constraints of the master and the detail view so that there is room between those for the separator.
Alternatives:
One could also add a subview to the content view of each UITableViewCell. Examples can be found here or here.
MHarper's code updated for Swift 5:
import UIKit
#IBDesignable
class LineView: UIView {
#IBInspectable var lineWidth: CGFloat = 1.0
#IBInspectable var lineColor: UIColor? {
didSet {
lineCGColor = lineColor?.cgColor
}
}
var lineCGColor: CGColor?
override func draw(_ rect: CGRect) {
// Draw a line from the left to the right at the midpoint of the view's rect height.
let midpoint = self.bounds.size.height / 2.0
let context = UIGraphicsGetCurrentContext()
context!.setLineWidth(lineWidth)
if let lineCGColor = self.lineCGColor {
context!.setStrokeColor(lineCGColor)
}
else {
context!.setStrokeColor(UIColor.black.cgColor)
}
context!.move(to: CGPoint(x: 0.0, y: midpoint))
context!.addLine(to: CGPoint(x: self.bounds.size.width, y: midpoint))
context!.strokePath()
}
}

Resources