Adding a gradient to UIImageView - ios

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

Related

Custom UINavigationBar gradient background and image in logo

I have some problems with inheriting UINavigationBar.
First of all, I have to use the same class in multiple UINavigationBar, since everything is embedded in UITabBar. So I have a UITabBar connected to 5 different UINavigationBar.
All these UINavigationBars should have a gradient background and an image as title. I tried inheriting and setting this class to each of them, but it does not work.
class NavBar: UINavigationBar {
func setupNavBar(){
self.topItem?.titleView = UIImageView(image: UIImage(named: "image"))
self.topItem?.titleView?.contentMode = .scaleAspectFit
let gradient = CAGradientLayer()
gradient.frame = self.bounds
gradient.colors = [UIColor.blue.cgColor, UIColor.blue.cgColor]
gradient.locations = [0.0, 1.0]
self.layer.insertSublayer(gradient, at: 0)
self.setNeedsLayout()
}
override func didMoveToSuperview() {
self.setupNavBar()
}
}
I have tried different combinations, but in most of them I cannot see the image. Also it happened to have a different behavior by calling the same class in different UINavigationBar, for instance in the first tab I can see the gradient, but if I change it then it is not there.
Please help me to solve this by using the subclass, I do not want to put the code in controllers.
Extra: I would also like to fill the status bar with gradient, but I can only fill static color
Solved by inheriting UITabBarController instead and putting gradient as backgroundImage
class NavBarController: UINavigationController {
override func viewDidLayoutSubviews() {
self.navigationBar.topItem?.titleView = UIImageView(image: UIImage(named: "image"))
self.navigationBar.topItem?.titleView?.contentMode = .scaleAspectFit
let gradient = CAGradientLayer()
var bounds = self.navigationBar.bounds
bounds.size.height += self.view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
bounds.origin.y -= self.view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
gradient.frame = bounds
gradient.colors = [UIColor.black, UIColor.white]
gradient.locations = [0.0, 1.0]
self.navigationBar.setBackgroundImage(image(fromLayer: gradient), for: .default)
}
func image(fromLayer layer: CALayer) -> UIImage {
UIGraphicsBeginImageContext(layer.frame.size)
layer.render(in: UIGraphicsGetCurrentContext()!)
let outputImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return outputImage!
}
}

Scrolling UITableView mess with gradient

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)

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?

Button stretch when gradient applied

First I set constraints to a button in storyboard. Then, I edited it in code to make it look good.
When I apply my gradient function to a button it becomes bigger than before. How do you fix that?
extension UIView {
func applyGradient(colours: [UIColor]) -> Void {
self.applyGradient(colours, locations: nil)
}
func applyGradient(colours: [UIColor], locations: [NSNumber]?) -> Void {
let gradient: CAGradientLayer = CAGradientLayer()
gradient.frame = self.bounds
gradient.colors = colours.map { $0.CGColor }
gradient.locations = locations
self.layer.insertSublayer(gradient, atIndex: 0)
}
}
I just applied it on one button and..
Here is the pic...
Now after that it looks like this...The gradient bound did nothing It goes way outside frame PLZPLZPLZ try to help me :) I appreciate ur help so far
Add self.layer.masksToBounds = true to the function. This will mean that the sublayer you added won't draw outside of the original frame of the button
EDIT:
If you want the shadow as well you'll need to set self.layer.masksToBounds to false, since it will clip the shadow too.
Try gradient.frame = self.layer.bounds instead maybe?

How can UIVisualEffectView be used inside of a circle?

I'm making a custom control circle. Part of the circle may be transparent. It would make more visual sense and look better if it was translucent instead of transparent.
Because views are rectangular, and I only want the circle to be translucent, not the rest of the rectangle, this is a problem.
The UIVisualEffectView is behind the custom control.
(Without anything rendered inside of the circle for debugging purposes)
As you can see, the view is blurring things outside of the circle.
I don't know how to blur inside only the view, and the prerelease documentation is practically empty. My only thought is to create many 1x1 views to cover the circle, but this seems like it would not really work, and even if it did it would be a slow and ugly solution. How can I blur the content inside the view, without blurring anything outside it?
Set the circle view's layer mask to a filled circle:
CircleControlView *circleView = yourCircleView();
CAShapeLayer *mask = [CAShapeLayer layer];
mask.path = [UIBezierPath bezierPathWithOvalInRect:circleView.bounds].CGPath;
circleView.layer.mask = mask;
UPDATE
Swift playground example:
import UIKit
import XCPlayground
import QuartzCore
UIGraphicsBeginImageContext(CGSize(width: 100, height: 100))
let viewPath = UIBezierPath(ovalInRect:CGRect(x:1,y:1,width:98,height:98))
viewPath.lineWidth = 2
viewPath.stroke()
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
let view = UIView(frame:CGRect(x:0,y:0,width:100,height:100))
XCPShowView("view", view)
let label = UILabel(frame:view.bounds)
label.text = "This is the text in the background behind the circle."
label.numberOfLines = 0
view.addSubview(label)
let effectView = UIVisualEffectView(effect:UIBlurEffect(style:.ExtraLight))
effectView.frame = view.bounds
view.addSubview(effectView)
let circleView = UIImageView(image:image)
effectView.addSubview(circleView)
let maskPath = UIBezierPath(ovalInRect:circleView.bounds)
let mask = CAShapeLayer()
mask.path = maskPath.CGPath
effectView.layer.mask = mask
Result:

Resources