Scrolling UITableView mess with gradient - ios

I have a custom TableViewCell on my TableViewController.
The cell has a UIView that is turned into a gradient that displays black at the bottom and clear (transparent) color on the top of the UIView.
It looks fine when the app loads, but as I scroll, the gradient turns more and more black and the 'fading' itself becomes smaller and gets closer to the top of the UIView.
I do not know how to make it stay as it is when the app loads at first.
Here's my code:
let gradient = CAGradientLayer()
gradient.frame = cell.gradientView.bounds
let colour:UIColor = .black
gradient.colors = [colour.withAlphaComponent(0.0).cgColor,colour.cgColor]
cell.gradientView.layer.insertSublayer(gradient, at: 0)

Add this code in awakeFromNib not in cellForRow , as because of dequeuing the gradient is being added multiple times to the cell
let gradient = CAGradientLayer()
gradient.frame = cell.gradientView.bounds
let colour:UIColor = .black
gradient.colors = [colour.withAlphaComponent(0.0).cgColor,colour.cgColor]
self.gradientView.layer.insertSublayer(gradient, at: 0)

Related

Adding a gradient to UIImageView

I'm trying to add a gradient to UIImageView.
viewDidLoad() {
self.bookImageBig.sd_setImage(with: URL(string: self.book.image), placeholderImage: nil)
self.bookImage.sd_setImage(with: URL(string: self.book.image), placeholderImage: nil)
let view = UIView(frame: bookImageBig.frame)
let gradient = CAGradientLayer()
gradient.frame = view.frame
gradient.colors = [UIColor.clear.cgColor, UIColor.black.cgColor]
gradient.locations = [0.0, 1.0]
view.layer.insertSublayer(gradient, at: 0)
bookImageBig.addSubview(view)
bookImageBig.bringSubviewToFront(view)
I'm trying to add a gradient to bookImageBig UIImageView.
However, the gradient only partially covers the image. 30px of the image is not covered by the gradient. The image was added to the story board and is being referenced in the view controller.
Can someone please help?
Instead of frame use bounds
gradient.frame = self.bookImageBig.bounds
For frame and bounds difference look at this post

CAGradientLayer not filling width

I am relatively new to Swift. I'm just messing around trying to design a taxi app.
I discovered CGGradientLayer and thought it would add a nice effect to the top bar on the app.
I've added it and for some reason, it's not fully stretching to the views width.
This is my subclass:
import UIKit
class GradientView: UIView {
let gradient = CAGradientLayer()
override func awakeFromNib() {
setupGradientView()
}
func setupGradientView() {
gradient.frame = self.frame
gradient.colors = [UIColor.white.cgColor, UIColor.init(white: 1.0, alpha: 0.0).cgColor]
gradient.startPoint = CGPoint.zero
gradient.endPoint = CGPoint(x: 0, y: 1)
gradient.locations = [0.9, 1.0]
self.layer.addSublayer(gradient)
}
}
And this is the result.
The green background is actually the width of the UIView which the sub class is applied too.
You are setting the frame of the gradient too early. You should set it up in an override of layoutSubviews:
override func layoutSubviews() {
super.layoutSubviews()
gradient.frame = self.bounds
}
Notes:
You should be setting the gradient frame to self.bounds. That is the coordinate system used inside of the view. The gradient is placed relative to the GradientView and doesn't change if the GradientView is placed in another location on the screen (because the bounds do not change in that case, but the frame does).
At the time your view is first created, Auto Layout has not established the size of your view for your current device (or orientation). By setting the frame in layoutSubviews you always get the latest value for the size of the view.

CAGradientLayer isn't spanning the whole width of my button - xcode

I'm new to xcode and I am placing a gradient layer over a button and it is not filling the whole width. I'm not sure what I'm doing wrong. My code is here and screenshot of how it is rendering.
let gradientLayer = CAGradientLayer()
gradientLayer.frame = self.btnSavePhoto.bounds
let color1 = UIColor(red:0.05, green:0.29, blue:0.49, alpha:1.0).CGColor as CGColorRef
let color2 = UIColor(red:0.08, green:0.23, blue:0.39, alpha:1.0).CGColor as CGColorRef
gradientLayer.colors = [color1, color2]
gradientLayer.locations = [0.0, 1.0]
self.btnSavePhoto.layer.addSublayer(gradientLayer)
It seems like your button changes it's size later on (due to autoresizing masks or constraints), but the gradientLayer stays of the original (smaller) size. It is caused by the fact that layers don't resize automatically.
You can create a custom UIButton subclass that would update the sizing of a custom layer in layoutSubviews method.
Or you can create a custom layer subclass, although it would also require to create a UIButton subclass, as described in this question: CALayers didn't get resized on its UIView's bounds change. Why?

How to set UICollectionView layer not moving/static while scrolling Swift

I added a gradient layer to UICollectionView, but the layer is set to the width of the screen. I am trying to keep the layer static while scrolling but can't find a solution. Tried setting to both the frame of the collectionView and to the currentVC, when I scroll the layer is also scrolling. This is my code so far, thank you for your help.
let gradinatLayer = CAGradientLayer()
gradinatLayer.frame = self.collectionView.frame //self.currentViewController.view.frame
let cgColors:[CGColorRef] = [UIColor.blackColor().colorWithAlphaComponent(0.7).CGColor, UIColor.clearColor().CGColor, UIColor.blackColor().colorWithAlphaComponent(0.7).CGColor]
gradinatLayer.colors = cgColors
gradinatLayer.startPoint = CGPointMake(0, 0.5)
gradinatLayer.endPoint = CGPointMake(1.0, 0.5)
gradinatLayer.locations = [0.15, 0.50, 0.85]
self.collectionView.layer.insertSublayer(gradinatLayer, atIndex: 0)
//This doesn't work
self.collectionView.layer.shouldRasterize = true
self.collectionView.layer.rasterizationScale = UIScreen.mainScreen().scale
Thank you for all your comments. This was my solution after digging into UIView. Unfortunately, adding super views and subviews to UICollectionView still keeps the view scrollable. Thanks to John Stephen, who showed how to create a transparent UIView with userIntaractions with its child views, this was possible.
I have declared a #IBOutlet weak var passThroughView: PassThroughView! on top of collectionView.
This is the code that works now:
let gradinatLayer = CAGradientLayer()
gradinatLayer.frame = self.currentViewController.view.frame
let cgColors:[CGColorRef] = [UIColor.blackColor().colorWithAlphaComponent(0.7).CGColor, UIColor.clearColor().CGColor, UIColor.blackColor().colorWithAlphaComponent(0.7).CGColor]
gradinatLayer.colors = cgColors
gradinatLayer.startPoint = CGPointMake(0, 0.5)
gradinatLayer.endPoint = CGPointMake(1.0, 0.5)
gradinatLayer.locations = [0.15, 0.50, 0.85]
passThroughView.layer.insertSublayer(gradinatLayer, atIndex: 0)
Try adding your layer to the collectionView's backgroundview instead:
self.collectionView.backgroundView.layer.addSublayer(gradinatLayer)

How can you add a CAGradientLayer to a cell in a tableview from within the cells' awakeFromNib() method?

I have been adding CAGradient layers to cells using this code:
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as myCell
cell.mImageView.image = UIImage(named: scripts[indexPath.row].thumbnailImage)
let gradientLayer = CAGradientLayer()
if(cell.layer.sublayers.count == 2){ //This is to stop stacking gradient layers
gradientLayer.colors = [UIColor.clearColor().CGColor, UIColor.blackColor().CGColor]
gradientLayer.locations = [0.6, 1.0]
gradientLayer.frame = cell.bounds
cell.layer.insertSublayer(gradientLayer, below: cell.mImageView.layer)
}
This is from within the tableView(_:cellForRowAtIndexPath) method of my CustomTableViewController class.
I have a myCell class that I would much rather use to perform the gradient layout, but I cannot use this code or the cell object from within the awakeFromNib() method.
How can I insert this CAGradientLayer from within the awakeFromNib (or init()) method of the myCell class? The cell also contains a label and I would like to insert it beneath the label as well.
I don't know why you would get that error. I tried a slight modification of your code (in the cell class), and it worked ok. Here it is,
class RDTableViewCell: UITableViewCell {
#IBOutlet var mImageView: UIImageView!
override func didMoveToSuperview() {
let gradientLayer = CAGradientLayer()
gradientLayer.colors = [UIColor.clearColor().CGColor, UIColor.blackColor().CGColor]
gradientLayer.locations = [0.6, 1.0]
gradientLayer.frame = self.bounds
self.layer.insertSublayer(gradientLayer, below: self.mImageView.layer)
}
}
I assumed that you want the gradient at the bottom of the cell, and that did not happen with my cells (which had a height of 70) if I put the code in awakeFromNib.

Resources