Gradient as Foreground Color of Text in Swiftui

Gradient as foreground color of Text in SwiftUI


New in SwiftUI: modifier .foregroundStyle() (iOS15+)

Text with a gradient

Text(“Gradient”)
.foregroundStyle(
.linearGradient(
colors: [.red, .blue],
startPoint: .top,
endPoint: .bottom
)
)

How to move the gradient-foreground-color text to the center of the view in SwiftUI?

The problem is that the LinearGradient is filling all of the space it is given. If you remove the mask, you will see how big it is. You'd like it to be just the size of the text.

I'm sure there's a better way to handle this, but this is what I came up with. By starting with the text, we are able to use the LinearGradient as an overlay which will exactly match the size of the text.

struct GradientText: View {
let text = Text("Hello World")
.font(.system(size: 40, weight: .bold, design: .rounded))

var body: some View {
text
.foregroundColor(.clear)
.overlay(
LinearGradient(gradient: Gradient(colors: [.blue, .red, .orange]),
startPoint: .leading, endPoint: .trailing)
.mask(text))
}
}

Extending this idea further, you could make GradientText take text and gradient as inputs so that you could easily do this repeatedly:

struct GradientText: View {
let text: Text
let gradient: LinearGradient

init(text: Text, gradient: LinearGradient? = nil) {
self.text = text
self.gradient = gradient ?? LinearGradient(gradient: Gradient(colors: [.blue, .red, .orange]), startPoint: .leading, endPoint: .trailing)
}

var body: some View {
text
.foregroundColor(.clear)
.overlay(
gradient
.mask(text))
}
}

struct ContentView: View {
var body: some View {
VStack {
GradientText(text: Text("Hello World")
.font(.system(size: 40, weight: .bold, design: .rounded)))
GradientText(text: Text("Goodnight World"), gradient: LinearGradient(gradient: Gradient(colors: [.green, .yellow, .orange]), startPoint: .leading, endPoint: .trailing))
}
}
}

SwiftUI - How to add foreground linear gradient on image

The task here is to display gradient over an image. To display one view over another SwiftUI provides ZStack view, so, the code can have the next structure:

ZStack {
<Image>
<Rectangle with gradient>
}

Additionally, to make sure the image we use is resized correctly to the specified frame resizable modifier should be applied with correct contentMode:

Image("IconLoseWeight")
.resizable() // Make it resizable
.aspectRatio(contentMode: .fit) // Specifying the resizing mode so that image scaled correctly

After all, we need to apply frame and padding parameter to ZStack so that gradient has the same size as the image.

The result would look like that:

ZStack {
Image("IconLoseWeight")
.resizable() // Making the image resizable to the container size
.aspectRatio(contentMode: .fit) // Setting up resizing mode so that the image scaled correctly

Rectangle() // Shapes are resizable by default
.foregroundColor(.clear) // Making rectangle transparent
.background(LinearGradient(gradient: Gradient(colors: [.clear, .black]), startPoint: .top, endPoint: .bottom), cornerRadius: 0)
// Specifying gradient (note that one color is .clear)
}
.frame(width: 30, height: 30) // Applying frame
.padding(.leading, 17) // Applying padding

Note, that we use a gradient from .clear to .black as we need a transparent gradient to make the image visible.

How to add a gradient above button in SwiftUI that is overlapping the content? iOS 13

If it helps someone, I managed to do it with overlay.

   Button(action: {
state.isExpanded.toggle()
}, label: {
Text(state.isExpanded ? "Collapse" : "Expand")
.frame(maxWidth: .infinity,
minHeight: 60,
maxHeight: 60,
alignment: .center)
.foregroundColor(Color(.red))
.background(Color(.white))
}).overlay(Rectangle()
.foregroundColor(.clear)
.background(LinearGradient(
gradient: Gradient(colors: [.white.opacity(0), .white.opacity(1)]),
startPoint: .top,
endPoint: .bottom))
.frame(height: 30)
.alignmentGuide(.top) { $0[.top] + 30 },
alignment: .top)

How do I get a Color from a gradient in SwiftUI

Here is a way to get a single color from a gradient by applying a percentage to RVB components.

Here is your code modified by adding the grandientColor() function that calculates the Red and Green components of the color based on the value of your Slider.

import SwiftUI

struct ContentView: View {

@State private var monthTotalSpent = 100.0
@State private var budgetdef = 1100.0


var body: some View{
ZStack{
RoundedRectangle(cornerRadius: 30)
.foregroundColor(.init(.systemGray4))
VStack(spacing: 5){
HStack{
Text("\(monthTotalSpent)")
Text("/")
Text("\(budgetdef)")
}
.padding(.top)
.padding(.horizontal)
ZStack(alignment: .center){
RoundedRectangle(cornerRadius: 15)
.foregroundColor(Color(uiColor: .systemGray6))
.frame(width: UIScreen.main.bounds.width-50, height: 10, alignment: .center)
HStack{
RoundedRectangle(cornerRadius: 4)
.fill(gradientColor(value: monthTotalSpent))
.frame(width: ((monthTotalSpent*290)/budgetdef) < 290 ? ((monthTotalSpent*290)/budgetdef) : UIScreen.main.bounds.width-54, height: 8, alignment: .center)
.padding(.leading, 27)
Spacer(minLength: 0)
}
}
Slider(
value: $monthTotalSpent,
in: 0...1500,
step: 100
)
}
}
}

func gradientColor(value: Double) -> Color {
let percent = value / budgetdef
let color = UIColor(red: percent, green: 1 - percent, blue: 0, alpha: 1)
return Color(uiColor: color)
}
}

How do I add a gradient to the text of a UILabel, but not the background?

(Skip to bottom for full class source code)

Really useful answers by both Brad Larson and Bach. The second worked for me but it requires an image to be present in advance. I wanted something more dynamic so I combined both solutions into one:

  • draw the desired gradient on a UIImage
  • use the UIImage to set the color pattern

The result works and in the screenshot below you can see some Greek characters rendered fine too. (I have also added a stroke and a shadow on top of the gradient)

iOS stylized UILabel, the big brown fox

Here's the custom init method of my label along with the method that renders a gradient on a UIImage (part of the code for that functionality I got from a blog post I can not find now to reference it):

- (id)initWithFrame:(CGRect)frame text:(NSString *)aText {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
self.text = aText;

self.textColor = [UIColor colorWithPatternImage:[self gradientImage]];

}
return self;
}

- (UIImage *)gradientImage
{
CGSize textSize = [self.text sizeWithFont:self.font];
CGFloat width = textSize.width; // max 1024 due to Core Graphics limitations
CGFloat height = textSize.height; // max 1024 due to Core Graphics limitations

// create a new bitmap image context
UIGraphicsBeginImageContext(CGSizeMake(width, height));

// get context
CGContextRef context = UIGraphicsGetCurrentContext();

// push context to make it current (need to do this manually because we are not drawing in a UIView)
UIGraphicsPushContext(context);

//draw gradient
CGGradientRef glossGradient;
CGColorSpaceRef rgbColorspace;
size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 0.0, 1.0, 1.0, 1.0, // Start color
1.0, 1.0, 0.0, 1.0 }; // End color
rgbColorspace = CGColorSpaceCreateDeviceRGB();
glossGradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);
CGPoint topCenter = CGPointMake(0, 0);
CGPoint bottomCenter = CGPointMake(0, textSize.height);
CGContextDrawLinearGradient(context, glossGradient, topCenter, bottomCenter, 0);

CGGradientRelease(glossGradient);
CGColorSpaceRelease(rgbColorspace);

// pop context
UIGraphicsPopContext();

// get a UIImage from the image context
UIImage *gradientImage = UIGraphicsGetImageFromCurrentImageContext();

// clean up drawing environment
UIGraphicsEndImageContext();

return gradientImage;
}

I'll try to complete that UILabel subclass and post it.

EDIT:

The class is done and it's on my GitHub repository. Read about it here!

Linear Color Gradient to items in HStack?

There is built-in Gradient... how to present it is up to us... Here is possible alternate, but it is just ... one of many other variants.. you know.

demo

struct GradView: View {
var body: some View {
HStack(spacing: 0) {
ForEach((1...7).reversed(), id: \.self) { index in
HStack(spacing: 0) {
Rectangle().fill(Color.clear)
.frame(width: 50, height: 50)
Rectangle().fill(Color(UIColor.systemBackground))
.frame(width: 4, height: 50)
}
}
}.background(LinearGradient(gradient:
Gradient(colors:[.red, .black]),
startPoint: .leading, endPoint: .trailing))
}
}

Gradient Background Color with List

You need to clear the background colors first and then you can see the gradient color on your background. And also, put the List or any view you want inside the '.overlay()' after the LinearGradient, like this:

struct ContentView: View {

init() {
UITableView.appearance().backgroundColor = .clear
UITableViewCell.appearance().backgroundColor = .clear
}

var body: some View {
ZStack {
LinearGradient(gradient: Gradient(colors: [Color.red, Color.blue]), startPoint: .top, endPoint: .bottom)
.edgesIgnoringSafeArea(.vertical)
.overlay(
List {
HStack {
Text("Boulangerie Roussel")
.font(.title3)
.foregroundColor(Color.black)
Spacer()
Text("Ouvert")
.font(.title3)
.foregroundColor(Color.green)
.padding(.horizontal)

}
}
)
}
}
}

If you want the List Item to change the background color, just put the HStack inside the .overlay() and not the whole List ;)



Related Topics



Leave a reply



Submit