UILabel text duplicates in PDF when containing a certain character - ios

I'm generating a PDF something like:
UIGraphicsBeginPDFContextToFile
layer.render(in: context)
UIGraphicsEndPDFContext
Yesterday, I found a fix to make all text vector-based (basically this answer https://stackoverflow.com/a/9056861/897465).
That worked really well, text is vectors and searchable, etc.
Except for one irritating thing.
Everytime a UILabel contains the character "Å", the text is kind of duplicated in the PDF, like the image below. Probably there are other characters as well the would cause this.
I've got a small example that demonstrates it below. If you run this in the simulator you'll get a pdf in /tmp/test.pdf where you can see the issue yourself.
I guess I should file a rdar, but I would really like some good workaround (good meaning not checking if label.text contains "Å"). Since I don't think this is something Apple would fix, considering the whole workaround to begin with (PDFLabel).
import UIKit
class PDFLabel: UILabel {
override func draw(_ layer: CALayer, in ctx: CGContext) {
let isPDF = !UIGraphicsGetPDFContextBounds().isEmpty
if !layer.shouldRasterize && isPDF {
draw(bounds)
} else {
super.draw(layer, in: ctx)
}
}
}
func generatePDFWith(_ texts: [String]) {
let paper = CGRect(origin: .zero, size: CGSize(width: 876, height: 1239))
UIGraphicsBeginPDFContextToFile("/tmp/test.pdf", paper, [
kCGPDFContextCreator as String: "SampleApp"
])
texts.forEach { text in
UIGraphicsBeginPDFPage()
let v = UIView()
let label = PDFLabel()
label.text = text
label.textColor = .black
v.translatesAutoresizingMaskIntoConstraints = false
label.translatesAutoresizingMaskIntoConstraints = false
v.addSubview(label)
v.widthAnchor.constraint(equalToConstant: 500).isActive = true
v.heightAnchor.constraint(equalToConstant: 500).isActive = true
label.centerXAnchor.constraint(equalTo: v.centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: v.centerYAnchor).isActive = true
v.setNeedsLayout()
v.layoutIfNeeded()
v.layer.render(in: UIGraphicsGetCurrentContext()!)
}
UIGraphicsEndPDFContext();
print("Done!")
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
generatePDFWith([
"Ångavallen",
"Hey Whatsapp?",
"Änglavallen",
"Örebro",
"Råå",
"RÅÅ",
"Å",
"Ål",
])
}
}
EDIT: Little progress in debugging, it seems that the draw function gets called two times, and the first time it is drawn a little "off" if it has an "Å" (probably any character larger than the box).
So this fixed it for me (however ugly it may be):
class PDFLabel: UILabel {
var count = 0
override func draw(_ layer: CALayer, in ctx: CGContext) {
let isPDF = !UIGraphicsGetPDFContextBounds().isEmpty
if isPDF {
if count > 0 { draw(bounds) }
count += 1
} else if !layer.shouldRasterize {
draw(bounds)
} else {
super.draw(layer, in: ctx)
}
}
}

Related

Adding textfeilds on top of drawing veiw image XCode SwiftUI

Essentially I would like to add text fields on top of my image.
Currently, my viewDidLoad() is currently set up as such.
-Image Background (UIImage)
--Drawing Canvas
I would like it to be set up as such so that it is not possible to draw over the text fields, as I realize it is possible to add text over the image itself
-Image Background (UIImage)
---Drawing Canvas
-----TextFeild Struct
I would assume I need to use UITextField but I keep on getting this error in my simulation.
(Fatal error: Unexpectedly found nil while implicitly unwrapping an
Optional value)
In addition to this error, I'm unable to edit the scaling of my image background. I tried everything turning the imageView to content mode, and modifying the image before adding the view (scaleAspectFit/scaleAspectFill), resizing the view the only thing that seemed to work was changing the resolution of the source image.
I would like to add text fields up top right
class DrawingCanvasViewController: UIViewController {
#IBOutlet weak var nameTextField: UITextField!
lazy var canvas: PKCanvasView = {
let view = PKCanvasView()
view.drawingPolicy = .anyInput
view.minimumZoomScale = 1
view.maximumZoomScale = 1
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
lazy var toolPicker: PKToolPicker = {
let toolPicker = PKToolPicker()
toolPicker.addObserver(self)
return toolPicker
}()
var drawingData = Data()
var drawingChanged: (Data) -> Void = {_ in}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(canvas)
canvas.backgroundColor = .clear
let iTest=UIImage(named: "Test2")
let imageView=UIImageView(image: iTest)
//This is what I have used for trying to resize my background image, although none of it seems to ever work
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFit
view.addSubview(imageView)
view.sendSubviewToBack(imageView)
//The fatal error it gives me is from these two lines below
// view.addSubview(nameTextField)
// view.bringSubviewToFront(nameTextField)
NSLayoutConstraint.activate([
canvas.leadingAnchor.constraint(equalTo: view.leadingAnchor),
canvas.trailingAnchor.constraint(equalTo: view.trailingAnchor),
canvas.topAnchor.constraint(equalTo: view.topAnchor),
canvas.bottomAnchor.constraint(equalTo: view.bottomAnchor)])
toolPicker.setVisible(true, forFirstResponder: canvas)
toolPicker.addObserver(canvas)
canvas.delegate = self
canvas.becomeFirstResponder()
if let drawing = try? PKDrawing(data: drawingData){
canvas.drawing = drawing
}
}
}
I'm new to Xcode, I did follow a tutorial to add the pencil kit UI although am currently unable to refind it, and I figured out how to add the background image from looking at apple documentation, Hence I may have simply missed an easier/better way to code my app.
what I'm seeing from your code is: that you added UITextField in your Xib/Storyboard file. Therefore you can remove the reference of UITextField in the Xib/Storyboard file with the controller and introduce UITextField programmatically. My solution below will only address the fatal error from the 2 lines:
view.addSubview(nameTextField)
view.bringSubviewToFront(nameTextField)
Then let me know other issues when you get this one working first. Please adjust the contrainst of nameTextField to have it visible.
class DrawingCanvasViewController: UIViewController {
// initialise text field
lazy var nameTextField: UITextField = {
let textField = UITextField()
textField.translatesAutoresizingMaskIntoConstraints = false
// Please setup delegate by yourself
return textField
}()
lazy var canvas: PKCanvasView = {
let view = PKCanvasView()
view.drawingPolicy = .anyInput
view.minimumZoomScale = 1
view.maximumZoomScale = 1
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
lazy var toolPicker: PKToolPicker = {
let toolPicker = PKToolPicker()
toolPicker.addObserver(self)
return toolPicker
}()
var drawingData = Data()
var drawingChanged: (Data) -> Void = {_ in}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(canvas)
canvas.backgroundColor = .clear
let iTest=UIImage(named: "Test2")
let imageView=UIImageView(image: iTest)
//This is what I have used for trying to resize my background image,
// although none of it seems to ever work
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFit
view.addSubview(imageView)
view.sendSubviewToBack(imageView)
// since you already created the nameTextField as a lazy variable
// then you can add it here
view.addSubview(nameTextField)
view.bringSubviewToFront(nameTextField)
NSLayoutConstraint.activate([
canvas.leadingAnchor.constraint(equalTo: view.leadingAnchor),
canvas.trailingAnchor.constraint(equalTo: view.trailingAnchor),
canvas.topAnchor.constraint(equalTo: view.topAnchor),
canvas.bottomAnchor.constraint(equalTo: view.bottomAnchor)])
toolPicker.setVisible(true, forFirstResponder: canvas)
toolPicker.addObserver(canvas)
canvas.delegate = self
canvas.becomeFirstResponder()
if let drawing = try? PKDrawing(data: drawingData){
canvas.drawing = drawing
}
}
}

iOS - Create a huge amount of UIImageViews without freezing the UI

I have to render create a huge amount(~10000) of UIImage objects, which are later added to a map using MapBox. The image are created by rendering a UILabel to an UIImage (sadly, the label can not directly be rendered on the map in the right font).
I imagined that, because I am not adding the views to the hierarchy until they are rendered on the map, I could create the views on a background thread in order to not have the UI freeze. However, this seems not to be possible.
My question is, is there a way to create a huge amount of UIImage objects by rendering a UILabel to an image without freezing the UI? Thanks for any help!
My code to render a UIView to an image is as follows:
private func render(_ view: UIView) -> UIImage? {
UIGraphicsBeginImageContext(view.frame.size)
guard let currentContext = UIGraphicsGetCurrentContext() else {return nil}
view.layer.render(in: currentContext)
return UIGraphicsGetImageFromCurrentImageContext()
}
And an example of a label I render to an image:
bigItemList.forEach { item in
// work to process the item..
// I have to call the rendering om the main thread, which causes the UI to freeze
DispatchQueue.main.async {
addImage(createLabel(text: label))
}
}
func createLabel(text: String?) -> UIImage? {
let label = UILabel()
label.textAlignment = .center
label.font = .boldSystemFont(ofSize: 14)
label.textColor = .mainBlue
label.text = text
label.sizeToFit()
label render(depthLabel)
}
UILabel is not safe to access on any non-main thread. The tool you want here is CATextLayer which will do all the same things (with a slightly clunkier syntax) while being thread-safe. For example:
func createLabel(text: String) -> UIImage? {
let label = CATextLayer()
let uiFont = UIFont.boldSystemFont(ofSize: 14)
label.font = CGFont(uiFont.fontName as CFString)
label.fontSize = 14
label.foregroundColor = UIColor.blue.cgColor
label.string = text
label.bounds = CGRect(origin: .zero, size: label.preferredFrameSize())
let renderer = UIGraphicsImageRenderer(size: label.bounds.size)
return renderer.image { context in
label.render(in: context.cgContext)
}
}
This is safe to run on any queue.
You most probably are already in main queue. Try execuring the loop in another one:
DispatchQueue.init(label: "Other queue").async {
bigItemList.forEach { item in
// work to process the item..
// I have to call the rendering om the main thread, which causes the UI to freeze
DispatchQueue.main.async {
addImage(createLabel(text: label))
}
}
}
EDIT: If it is already in another queue, you are also missing the UIGraphicsEndImageContext() call into render:
private func render(_ view: UIView) -> UIImage? {
UIGraphicsBeginImageContext(view.frame.size)
guard let currentContext = UIGraphicsGetCurrentContext() else {return nil}
view.layer.render(in: currentContext)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return img
}
EDIT: Another thing I see is that label allocation is the most time consuming in your loop. Try allocating it once since it's reusable:
let label = UILabel()
func createLabel(text: String?) -> UIImage? {
label.textAlignment = .center
...
...
}

Can't change UINavigationBar prompt color

I am unable to change the prompt color on my navigation bar. I've tried the code below in viewDidLoad, but nothing happens.
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
Am I missing something? Is the code above wrong?
I was able to make the prompt color white on iOS 11 was setting the barStyle to black. I set the other color attributes (like the desired background color) using the appearance proxy:
myNavbar.barStyle = UIBarStyleBlack; // Objective-C
myNavbar.barStyle = .black // Swift
It seems like you're right about this one. You need to use UIAppearance to style the prompt text on iOS 11.
I've filed radar #34758558 that the titleTextAttributes property just stopped working for prompt in iOS 11.
The good news is that there are a couple of workarounds, which we can uncover by using Xcode's view hierarchy debugger:
// 1. This works, but potentially changes *all* labels in the navigation bar.
// If you want this, it works.
UILabel.appearance(whenContainedInInstancesOf: [UINavigationBar.self]).textColor = UIColor.white
The prompt is just a UILabel. If we use UIAppearance's whenContainedInInstancesOf:, we can pretty easily update the color the way we want.
If you look closely, you'll notice that there's also a wrapper view on the UILabel. It has its own class that might respond to UIAppearance...
// 2. This is a more precise workaround but it requires using a private class.
if let promptClass = NSClassFromString("_UINavigationBarModernPromptView") as? UIAppearanceContainer.Type
{
UILabel.appearance(whenContainedInInstancesOf: [promptClass]).textColor = UIColor.white
}
I'd advise sticking to the more general solution, since it doesn't use private API. (App review, etc.) Check out what you get with either of these two solutions:
You may use
for view in self.navigationController?.navigationBar.subviews ?? [] {
let subviews = view.subviews
if subviews.count > 0, let label = subviews[0] as? UILabel {
label.textColor = UIColor.white
label.backgroundColor = UIColor.red
}
}
It will be a temporary workaround until they'll fix it
More complicated version to support old and new iOS
func updatePromptUI(for state: State) {
if (state != .Online) {
//workaround for SOFT-7019 (iOS 11 bug - Offline message has transparent background)
if #available(iOS 11.0, *) {
showPromptView()
} else {
showOldPromptView()
}
}
else {
self.navigationItem.prompt = nil
if #available(iOS 11.0, *) {
self.removePromptView()
} else {
self.navigationController?.navigationBar.titleTextAttributes = nil
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor:UIColor.lightGray]
}
}
}
private func showOldPromptView() {
self.navigationItem.prompt = "Network Offline. Some actions may be unavailable."
let navbarFont = UIFont.systemFont(ofSize: 16)
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.font: navbarFont, NSAttributedStringKey.foregroundColor:UIColor.white]
}
private func showPromptView() {
self.navigationItem.prompt = String()
self.removePromptView()
let promptView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 18))
promptView.backgroundColor = .red
let promptLabel = UILabel(frame: CGRect(x: 0, y: 2, width: promptView.frame.width, height: 14))
promptLabel.text = "Network Offline. Some actions may be unavailable."
promptLabel.textColor = .white
promptLabel.textAlignment = .center
promptLabel.font = promptLabel.font.withSize(13)
promptView.addSubview(promptLabel)
self.navigationController?.navigationBar.addSubview(promptView)
}
private func removePromptView() {
for view in self.navigationController?.navigationBar.subviews ?? [] {
view.removeFromSuperview()
}
}
I suggest using a custom UINavigationBar subclass and overriding layoutSubviews:
- (void)layoutSubviews {
[super layoutSubviews];
if (self.topItem.prompt) {
UILabel *promptLabel = [[self recursiveSubviewsOfKind:UILabel.class] selectFirstObjectUsingBlock:^BOOL(UILabel *label) {
return [label.text isEqualToString:self.topItem.prompt];
}];
promptLabel.textColor = self.tintColor;
}
}
Basically I'm enumerating all UILabels in the subview hierarchy and check if their text matches the prompt text. Then we set the textColor to the tintColor (feel free to use a custom color). That way, we don't have to hardcode the private _UINavigationBarModernPromptView class as the prompt label's superview. So the code is be a bit more future-proof.
Converting the code to Swift and implementing the helper methods recursiveSubviewsOfKind: and selectFirstObjectUsingBlock: are left as an exercise to the reader 😉.
You can try this:
import UIKit
class ViewController: UITableViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
updatePrompt()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
updatePrompt()
}
func updatePrompt() {
navigationItem.prompt = " "
for view in navigationController?.navigationBar.subviews ?? [] where NSStringFromClass(view.classForCoder) == "_UINavigationBarModernPromptView" {
if let prompt = view.subviews.first as? UILabel {
prompt.text = "Hello Red Prompt"
prompt.textColor = .red
}
}
navigationItem.title = "This is the title (Another color)"
}
}
Moshe's first answer didn't work for me because it changed the labels inside of system VCs like mail and text compose VCs. I could change the background of those nav bars but that opens up a whole other can of worms. I didn't want to go the private class route so I only changed UILabels contained inside of my custom navigation bar subclass.
UILabel.appearance(whenContainedInInstancesOf: [NavigationBar.self]).textColor = UIColor.white
Try this out:->
navController.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor.rawValue: UIColor.red]
I've found next work around for iOS 11.
You need set at viewDidLoad
navigationItem.prompt = UINavigationController.fakeUniqueText
and after that put next thing
navigationController?.promptLabel(completion: { label in
label?.textColor = .white
label?.font = Font.regularFont(size: .p12)
})
extension UINavigationController {
public static let fakeUniqueText = "\n\n\n\n\n"
func promptLabel(completion: #escaping (UILabel?) -> Void) {
gloabalThread(after: 0.5) { [weak self] in
guard let `self` = self else {
return
}
let label = self.findPromptLabel(at: self.navigationBar)
mainThread {
completion(label)
}
}
}
func findPromptLabel(at view: UIView) -> UILabel? {
if let label = view as? UILabel {
if label.text == UINavigationController.fakeUniqueText {
return label
}
}
var label: UILabel?
view.subviews.forEach { subview in
if let promptLabel = findPromptLabel(at: subview) {
label = promptLabel
}
}
return label
}
}
public func mainThread(_ completion: #escaping SimpleCompletion) {
DispatchQueue.main.async(execute: completion)
}
public func gloabalThread(after: Double, completion: #escaping SimpleCompletion) {
DispatchQueue.global().asyncAfter(deadline: .now() + after) {
completion()
}
}

Can't Get iOS Print Renderer to Draw Properly

OK. There seems to be a dearth of examples on this, and I am fairly stumped.
I'm trying to make a custom print page renderer; the type that completely customizes the output, not one that uses an existing view.
The really weird thing, is that I was able to do this in ObjC a couple of years ago, and I can't seem to do the same thing in Swift.
I should mention that I am using the prerelease (Beta 5) of Xcode, and Swift 4 (Which has almost no difference at all from Swift 3, in my project).
The project is here.
It's a completely open-source project, so nothing's hidden; however, it's still very much under development, and is a moving target.
This is the page renderer class.
BTW: Ignore the delegate class. I was just thrashing around, trying to figure stuff up. I'm not [yet] planning on doing any delegate stuff.
In particular, my question concerns what's happening here:
override func drawContentForPage(at pageIndex: Int, in contentRect: CGRect) {
let perMeetingHeight: CGFloat = self.printableRect.size.height / CGFloat(self.actualNumberOfMeetingsPerPage)
let startingPoint = max(self.maxMeetingsPerPage * pageIndex, 0)
let endingPointPlusOne = min(self.maxMeetingsPerPage, self.actualNumberOfMeetingsPerPage)
for index in startingPoint..<endingPointPlusOne {
let top = self.printableRect.origin.y + (CGFloat(index) * perMeetingHeight)
let meetingRect = CGRect(x: self.printableRect.origin.x, y: top, width: self.printableRect.size.width, height: perMeetingHeight)
self.drawMeeting(at: index, in: meetingRect)
}
}
and here:
func drawMeeting(at meetingIndex: Int, in contentRect: CGRect) {
let myMeetingObject = self.meetings[meetingIndex]
var top: CGFloat = contentRect.origin.y
let topLabelRect = CGRect(x: contentRect.origin.x, y: 0, width: contentRect.size.width, height: self.meetingNameHeight)
top += self.meetingNameHeight
let meetingNameLabel = UILabel(frame: topLabelRect)
meetingNameLabel.backgroundColor = UIColor.clear
meetingNameLabel.font = UIFont.boldSystemFont(ofSize: 30)
meetingNameLabel.textAlignment = .center
meetingNameLabel.textColor = UIColor.black
meetingNameLabel.text = myMeetingObject.name
meetingNameLabel.draw(topLabelRect)
}
Which is all called from here:
#IBAction override func actionButtonHit(_ sender: Any) {
let sharedPrintController = UIPrintInteractionController.shared
let printInfo = UIPrintInfo(dictionary:nil)
printInfo.outputType = UIPrintInfoOutputType.general
printInfo.jobName = "print Job"
sharedPrintController.printPageRenderer = BMLT_MeetingSearch_PageRenderer(meetings: self.searchResults)
sharedPrintController.present(from: self.view.frame, in: self.view, animated: false, completionHandler: nil)
}
What's going on, is that everything on a page is being piled at the top. I am trying to print a sequential list of meetings down a page, but they are all getting drawn at the y=0 spot, like so:
This should be a list of meeting names, running down the page.
The way to get here, is to start the app, wait until it's done connecting to the server, then bang the big button. You'll get a list, and press the "Action" button at the top of the screen.
I haven't bothered to go beyond the preview, as that isn't even working. The list is the only one I have wired up right now, and I'm just at the stage of simply printing the meeting names to make sure I have the basic layout right.
Which I obviously don't.
Any ideas?
All right. I figured out what the issue was.
I was trying to do this using UIKit routines, which assume a fairly high-level drawing context. The drawText(in: CGRect) thing was my lightbulb.
I need to do everything using lower-level, context-based drawing, and leave UIKit out of it.
Here's how I implement the drawMeeting routine now (I have changed what I draw to display more relevant information). I'm still working on it, and it will get larger:
func drawMeeting(at meetingIndex: Int, in contentRect: CGRect) {
let myMeetingObject = self.meetings[meetingIndex]
var remainingRect = contentRect
if (1 < self.meetings.count) && (0 == meetingIndex % 2) {
if let drawingContext = UIGraphicsGetCurrentContext() {
drawingContext.setFillColor(UIColor.black.withAlphaComponent(0.075).cgColor)
drawingContext.fill(contentRect)
}
}
var attributes: [NSAttributedStringKey : Any] = [:]
attributes[NSAttributedStringKey.font] = UIFont.italicSystemFont(ofSize: 12)
attributes[NSAttributedStringKey.backgroundColor] = UIColor.clear
attributes[NSAttributedStringKey.foregroundColor] = UIColor.black
let descriptionString = NSAttributedString(string: myMeetingObject.description, attributes: attributes)
let descriptionSize = contentRect.size
var stringRect = descriptionString.boundingRect(with: descriptionSize, options: [NSStringDrawingOptions.usesLineFragmentOrigin,NSStringDrawingOptions.usesFontLeading], context: nil)
stringRect.origin = contentRect.origin
descriptionString.draw(at: stringRect.origin)
remainingRect.origin.y -= stringRect.size.height
}

CALayer appears only for one second, then disappears

I'm adding CALayer to top and bottom of scrollable objects (UIScrollView, TableView, CollectionView) to display them when there is a content behind the visible area.
class TableViewWithCALayers: UITableView {
var topGradientLayer: CAGradientLayer?
var bottomGradientLayer: CAGradientLayer?
override func layoutSubviews() {
super.layoutSubviews()
guard self.topGradientLayer != nil && self.bottomGradientLayer != nil else {
addGradientLayerToTop() // create layer, set frame, etc.
addGradientLayerToBottom()
return
}
// addGradientLayerToTop()// if uncomment it - multiple layers are created and they are visible, but this is not the solution...
handleLayerAppearanceAfterLayoutSubviews() // playing with opacity here
}
How I create layer:
func addGradientLayerToTop() {
if let superview = superview {
self.topGradientLayer = CAGradientLayer()
let colorTop = UIColor.redColor().CGColor
let colorBottom = UIColor.clearColor().CGColor
if let topLayer = self.topGradientLayer {
topLayer.colors = [colorTop, colorBottom]
topLayer.locations = [0.0, 1.0]
topLayer.frame = CGRect(origin: self.frame.origin, size: CGSizeMake(self.frame.width, self.layerHeight))
superview.layer.insertSublayer(topLayer, above: self.layer)
if (self.contentOffset.y == 0) {
// if we are at the top - hide layer
// topLayer.opacity = 0.0 //temporarily disabled, so it is 1.0
}
}
}
}
TableViewWithCALayers works nice everywhere, except using TableView with xib files:
class XibFilesViewController : CustomUIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tableView: TableViewWithCALayers!
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.registerNib(UINib(nibName: "CustomTableViewCell", bundle: NSBundle.mainBundle()), forCellReuseIdentifier: "CustomTableViewCell")
self.tableView.layer.masksToBounds = false // this line doesn't help...
}
CustomUIViewController is used in many other ViewControllers where TableViewWithCALayers works good, so it should not create a problem.
Layers at the top and bottom appear for one second, then disappear. Logs from LayoutSubviews() func say that they are visible and opacity are 1.0, but something covers them. What can it be and how to deal with that?
Any help is appreciated!)
topLayer.zPosition = 10000 //doesn't help
topLayer.masksToBounds = false //doesn't help as well
When using nib files it's good practice, and design to add the UIView that you want to draw the layer on into your prototype cell, or header/footed and then have that view confirm to your class that's actually handling the layer.

Resources