How give gradient on text in TextView iOS? - ios

I would like to give gradient effect on text in UITextView, when I try using gradient layer its applied on complete textview background. I just want it tp be applied on text and background coloraturas should separate.
I want output like this :
And its coming like this:
Can someone suggest how to achieve output like first image on UITextView
I am specifically looking solution for UITextView, instead UILabel or UIView

You can create a patterned color for your text. So, you can apply this color to any text component(like a label,textView, button, etc).
Please check the below example. where you can customize your color pattern in the getGradientLayer() method.
func gradientColor(bounds: CGRect, gradientLayer :CAGradientLayer) -> UIColor? {
//We are creating UIImage to get gradient color.
UIGraphicsBeginImageContext(gradientLayer.bounds.size)
gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return UIColor(patternImage: image!)
}
func getGradientLayer(bounds : CGRect) -> CAGradientLayer{
let gradient = CAGradientLayer()
gradient.frame = bounds
gradient.colors = [UIColor.red.cgColor, UIColor.blue.cgColor]
gradient.startPoint = CGPoint(x: 0.0, y: 0.5)
gradient.endPoint = CGPoint(x: 1.0, y: 0.5)
return gradient
}
let textView = UITextView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
textView.font = UIFont.boldSystemFont(ofSize:50)
textView.textAlignment = .center
textView.text = "Hello World!"
let gradient = getGradientLayer(bounds: textView.bounds)
textView.textColor = gradientColor(bounds: textView.bounds, gradientLayer: gradient)
Output:-

Easiest way to achieve this is to create a UIView with the desired gradient, over your UILabel or UITextView and then mask the gradient UIView over the textView.
There is a good tutorial here.

Related

Create multicolor single letter (character) with Swift 5

I have a requirement to create colourful string where each letter should have multicolors / rainbow colors. Refer the attached image for better understanding. This need to create using Swift 5+ (UIKit) coding for an iOS app's dashboard.
In web, there are multiple solutions for multicolored string, but each letter of the string contain single color only, therefore they won't served my purpose. Any suggestions must be appreciated.
multicolored letter/character prototype
class LoginViewController: UIViewController {
lazy var gradientBG:GradientBg = {
let bg = GradientBg()
return bg
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
gradientBG.frame = view.frame
view.addSubview(gradientBG)
let label = UILabel(frame: view.bounds)
label.text = "Hello World"
label.font = UIFont.boldSystemFont(ofSize: 30)
label.textAlignment = .center
gradientBG.addSubview(label)
gradientBG.mask = label
}
}
class GradientBg:UIView {
override func layoutSubviews() {
super.layoutSubviews()
// Create a gradient layer
let gradient = CAGradientLayer()
// gradient colors in order which they will visually appear
gradient.colors = [UIColor.red.cgColor, UIColor.blue.cgColor]
// Gradient from left to right
gradient.startPoint = CGPoint(x: 0.0, y: 0.5)
gradient.endPoint = CGPoint(x: 1.0, y: 0.5)
// set the gradient layer to the same size as the view
gradient.frame = bounds
// add the gradient layer to the views layer for rendering
self.layer.addSublayer(gradient)
// Create a label and add it as a subview
}
}
The steps are: make a CAGradientLayer, then:
view.layer.addSublayer(gradient)
view.addSubview(label)
view.mask = label
With the help of Zeeshan Ahmed and Shadowrun, I able to solve my problem. My final solution is,
override func viewDidLoad() {
super.viewDidLoad()
let gradient = CAGradientLayer()
gradient.colors = [UIColor.red.cgColor, UIColor.green.cgColor, UIColor.blue.cgColor]
gradient.startPoint = CGPoint(x: 0, y: 0)
gradient.endPoint = CGPoint(x: 0, y: 1)
// bgView is a custom view with 100X100 sized
gradient.frame = bgView.bounds
bgView.layer.addSublayer(gradient)
let label = UILabel(frame: bgView.bounds)
label.text = "8"
label.font = UIFont.boldSystemFont(ofSize: 90)
label.textAlignment = .center
bgView.addSubview(label)
bgView.mask = label
}
And the expected output should be,
Gradient single letter
Kudos to all.

UIView to UIImage using UIGraphicsImageRenderer wrongly renderer image with alpha

I'm converting a UIView to UIImage, to set it as navigationBar background.
Thats view has an gradient layer, and when i use setBackgroundImage(_ backgroundImage: UIImage?, for barMetrics: UIBarMetrics) using the converted view, navigation gets a little transparent, something like 0.8 alpha
Here's the code that i'm using:
let navBackground = UIView(frame: CGRect(x: UIApplication.shared.statusBarFrame.origin.x,
y: UIApplication.shared.statusBarFrame.origin.y,
width: UIApplication.shared.statusBarFrame.width,
height: UIApplication.shared.statusBarFrame.height+self.navigationController!.navigationBar.frame.size.height))
let gradient: CAGradientLayer = CAGradientLayer()
gradient.colors = [UIColor(red:0.16, green:0.22, blue:0.49, alpha:1.0).cgColor, UIColor(red:0.31, green:0.53, blue:0.78, alpha:1.0).cgColor]
gradient.locations = [0.0, 1.0]
gradient.startPoint = CGPoint(x: 0, y: 1)
gradient.endPoint = CGPoint(x: 1, y: 0)
gradient.frame = navBackground.bounds
navBackground.layer.insertSublayer(gradient, above: nil)
let imgBackground = navBackground.asImage()
self.navigationController?.navigationBar.setBackgroundImage(imgBackground, for: UIBarMetrics.default)
asImage() it's a UIView extension that convert UIView to UIImage:
extension UIView {
func asImage() -> UIImage {
let renderer = UIGraphicsImageRenderer(bounds: bounds)
return renderer.image { rendererContext in
layer.render(in: rendererContext.cgContext)
}
}!
Result: sample
Turn off the translucent property of navigation bar. Actually the default navigation background has a blur effect but your converted image has none.

Make UINavigationBar have a gradient background using UIAppearance

Following this question, I am able to make a background gradient for a UINavigationBar, however when I try to set it through UIAppearance, the app crashes in the didFinishLaunching because there is no current CGContext. How can I get around this and still have all my UIAppearance code in the app delegate?
The code being called just before return true in the didFinishLaunching:
private func setNavBarAppearance() {
let titleAttributes: [NSAttributedStringKey: Any] = [.foregroundColor: UIColor.white]
UINavigationBar.appearance().titleTextAttributes = titleAttributes
UINavigationBar.appearance().barTintColor = .white
UINavigationBar.appearance().tintColor = .white
UINavigationBar.appearance().makeTransparent()
// Set gradient
let colors = [UIColor.lavender.cgColor, UIColor.mint.cgColor]
let gradientLayer = CAGradientLayer()
gradientLayer.frame = UINavigationBar.appearance().bounds
gradientLayer.colors = colors
gradientLayer.startPoint = CGPoint(x: 0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 0.5, y: 0.5)
let image = UIImage(layer: gradientLayer)
UINavigationBar.appearance().setBackgroundImage(image, for: .default)
}
When calling UIGraphicsBeginImageContext, you must provide a non-zero CGRect. In my case I was setting the frame to UINavigationBar.appearance().bounds which is a zero rect in the app delegate. To get around this I simply set the gradient frame to CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 1)

CAGradientLayer on UILabel can't be rotated

I want a horizontal color gradient as the text color of my UILabel.
So I'm using a CAGradientLayer as described in https://developer.apple.com/reference/quartzcore/cagradientlayer.
The gradient is rendered perfectly on the text, but vertically.
CATransform3DMakeRotation as apple described doesn't rotate the gradient.
In this answer it says that the CAGradientLayer needs to be added to a View or other Layer first to make the rotation work.
So I tried to add it as a sublayer to my UILabel and remove it after the rendering, but it won't transform the gradient on the text, but adds a horizontal gradient rectangle on top of it, in the size of the UILabel but rotated 90°.
Here's my code:
extension UILabel {
func addGradient() {
// Get size of the label
let size = CGSize(width: frame.width, height: frame.width)
let gradientLayer = CAGradientLayer()
gradientLayer.frame = CGRect(x: 0, y: 0, width: size.height, height: size.width)
gradientLayer.colors = [
UIColor.gradientBlue.cgColor,
UIColor.gradientPink.cgColor,
UIColor.gradientOrange.cgColor
]
// layer.addSublayer(gradientLayer)
gradientLayer.transform = CGAffineTransform
// This does not work
gradientLayer.transform = CATransform3DMakeRotation(CGFloat.pi / 2, 0, 0, 1)
UIGraphicsBeginImageContext(size)
gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
// Create UIImage from Gradient
let gradientImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// gradientLayer.removeFromSuperlayer()
textColor = UIColor.init(patternImage: gradientImage!)
}
}
you can use
gradientLayer.startPoint = CGPoint.init(x: 0, y: 0)
gradientLayer.endPoint = CGPoint.init(x: 1, y: 1)
for diagonal gradient. you can play with those points however you want to achieve different results.

How to change background view color partialy in ios swift

New to swift i want my background view 80% height to be red and rest in blue. Currently i'm doing that adding two views. I think there is a direct way to do that. Any guidance or help will be appreciated.
Adding two views is a good way of getting what you want (and the best since you can set the % via constraints.)
An other way would be by adding sublayers to your view via the code:
let gradient: CAGradientLayer = CAGradientLayer()
let topColor = UIColor(red:223.0/255.0, green:142.0/255.0, blue:219.0/255.0, alpha:255.0/255.0).cgColor
let bottomColor = UIColor(red:0, green:201.0/255.0, blue:243.0/255.0, alpha:255.0*0.34).cgColor
gradient.colors = [topColor, UIColor.clear, bottomColor]
gradient.locations = [0.0 , 0.5, 1.0]
gradient.frame = self.view.bounds
self.view.layer.insertSublayer(gradient, at: 1)
I would only use the layer method if you want to do something funky like a gradient.
Thanks for help. I think i found a solution.Adding a sublayer does the trick.
self.view.backgroundColor = UIColor.red
let bottomBorder = CALayer()
let t = CGRect(x: 0.0, y: (self.view.frame.size.height/100.0)*80, width: self.view.frame.size.width, height: (self.view.frame.size.height/100.0)*20)
bottomBorder.frame = t
bottomBorder.backgroundColor = UIColor.blue.cgColor
self.view.layer.addSublayer(bottomBorder)

Resources