Gradient as foreground color of Text in SwiftUI
New in SwiftUI: modifier .foregroundStyle()
(iOS15+)
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)
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.
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
Show Nsmenu Only on Nsstatusbarbutton Right Click
Why Does Swiftui Uihostingcontroller Have Extra Spacing
Using Compiler Variables in Swift
Split Uint32 into [Uint8] in Swift
How to Cast a Uint64 to an Int64
Modal View Closes When Selecting an Image in Uiwebview iOS
Ui Testing Failure - Neither Element Nor Any Descendant Has Keyboard Focus on Textview
How to Implement iOS 11's Mkusertrackingbutton
Why Does Swift Not Allow Stored Properties in Extensions
Why Does Realitykit Memory Does Not Clear After Deinit Called
What's the Best Way to Iterate Over Results from an API, and Know When It's Finished
Label Disappear When Changing Font Size to 25 in Swift
Uibarbuttonitem Doesn't Work When Created as a Property, But Does When Created in a Function
Why Property Observer Doesn't Work with Classes
Having Tab Bar and Navigationbar in the Same View in Swiftui
Swift: Set Insertion Point in Nstextfield
Swift: Programmatically Enumerate Outgoing Segues from a Uiviewcontroller