With iOS 18, Apple introduced the powerful MeshGradient API in SwiftUI. It allows for the definition of gradients using 2D coordinates.
In essence, you define color stops along both horizontal and vertical axes of a grid, starting at the top-left corner [0, 0]
and ending at the bottom-right [1, 1]
. You can define a different number of stops along each axis and even animate them for visual effects. If you’re new to MeshGradient
, Paul Hudson has a great introduction.
When the gradient was introduced last summer, people focused on the ability on animate this grid which makes it easy to create beautiful view backgrounds.
In this article, I want to focus on using MeshGradient
to style Swift Charts to create a two-dimensional style in a graph.
Defining the structure
First, lets set the baseline for the view that we are about to create. Here is a basic example how with a chart and a few entries.
It uses AreaMark
s to define an area for the given y values.
|
|
Adding a linear gradient
Next, lets add a one-dimensional linear gradient. This is will make the creation of the our mesh gradient easier.
We use this gradient to define the color stops from left to right along the x-axis of the chart, blending colors from .leading
to .trailing
.
|
|
You see a smooth color transition across the chart and can play around with the points to get different results. However, they are limited since we are only defining color stops along one axis. Let’s change that!
Applying a MeshGradient
A MeshGradient
lets you define color stops across both horizontal and vertical axes. For example, we can fade the colors vertically by changing their opacity values from top to bottom.
Let’s take the same colors as before, and define a smooth opacity gradient vertically along the y-axis. This gives a nice fade-out to the bottom of the graph area. We define our points along the x-axis, and repeat for all the stops along the y-axis.
Important: Note how it defines three color stops for its width
and two for its height
. You can pass in values here which do not correspond to the number of items you have in either points
or colors
but rendering will be inconsistent and unexpected. Make sure that the definition of both parameters always matches what the mesh gradient expects.
|
|
Additionally, the order in which you define your colors is important, too. Since the points are connected by the algorithm, you want a smooth transition between each point and no jumps across your graph area.
For example, assume you define your color stops on the y-axis first, so each color and its corresponding more opaque variant, top to bottom, left to right. It will look very weird. The API will allow it, and this might be just what you want, but I would suspect usually not.
|
|
Extra: Hard color stops
If you want to highlight very specific areas of the chart, you can do so using gradients as well. You achieve this by defining color stops that are so close to each other that they are rendered without any color fade between each other.
Taking the example of the linear gradient from the beginning, we change it to define each color right next to the following color so that the beginning and end of each color range is clearly defined.
Note: I originally thought that the stops needed to be 1 / 10000
apart. However, in testing for this, it seems that you can simply move both stops onto the same location, and it will work as expected.
|
|
Of course, this also works with a MeshGradient
. In this example, I put the stops at 0.3
and 0.6
to take advantage of the implicit conversion to Float
so that the code is easier to read. You would want to do the real conversion in production instead.
|
|
Conclusion
Using a MeshGradient
to style a SwiftChart is straight forward. You apply it as a foregroundStyle
to your graph component, and it will work just like any other SwiftUI view. This also holds true for lines using LineMark
, for example.
In conjuction, this can be used to add a nice shaded area below a line, and can be combined with all other standard SwiftUI abilities.