在SwiftUI中是否可以使用渐变作为Text的foregroundColor?
感谢您的提前解答!
答案 0 :(得分:17)
我想这应该有所帮助。适用于文本,图像和任何其他视图。
import SwiftUI
// MARK: - API
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
extension View {
public func foreground<Overlay: View>(_ overlay: Overlay) -> some View {
_CustomForeground(overlay: overlay, for: self)
}
}
// MARK: - Implementation
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
private struct _CustomForeground<Content: View, Overlay: View>: View {
let content: Content
let overlay: Overlay
internal init(overlay: Overlay, for content: Content) {
self.content = content
self.overlay = overlay
}
var body: some View {
content.overlay(overlay).mask(content)
}
}
我个人最喜欢这种方法。但您也可以将其组合为:
import SwiftUI
// MARK: - API
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
extension View {
public func foreground<Overlay: View>(_ overlay: Overlay) -> some View {
self.overlay(overlay).mask(self)
}
}
用法示例?
// MARK: - Example
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
struct GradientTextDemo: View {
var body: some View {
Text("Gradient foreground")
.foreground(makeGradient())
.padding(.horizontal, 32)
.padding(.vertical)
.background(Color.black)
.cornerRadius(12)
}
func makeGradient() -> some View {
LinearGradient(
gradient: .init(colors: [.red, .orange]),
startPoint: .topLeading,
endPoint: .bottomTrailing
)
}
}
答案 1 :(得分:4)
您可以将任意渐变或其他类型的视图分配为自定义尺寸的蒙版,例如:
Text("Gradient is on FIRE !!!")
.selfSizeMask(
LinearGradient(
gradient: Gradient(colors: [.red, .yellow]),
startPoint: .bottom,
endPoint: .top)
)
具有以下简单的小扩展名:
extension View {
func selfSizeMask<T: View>(_ mask: T) -> some View {
ZStack {
self.opacity(0)
mask.mask(self)
}.fixedSize()
}
}
您可以将其应用于任何类型的view
:
此外,您可以在其上应用所有渐变或任何视图:
答案 2 :(得分:2)
无需使用import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
theta = np.linspace(0, 2.*np.pi, 200)
phi = np.linspace(0, 1.*np.pi, 200)
theta, phi = np.meshgrid(theta, phi)
# major and minor radius
R0, a = 3., 1.
lw = 0.05 # Width of line
# Cue the unpleasantness - the circle must also be drawn as a toroid
x_circle = (R0 + lw*np.cos(theta)) * np.cos(phi)
y_circle = (R0 + lw*np.cos(theta)) * np.sin(phi)
z_circle = lw * np.sin(theta)
c_circle = np.full_like(x_circle, (1.0, 1.0, 1.0, 1.0), dtype=(float,4))
# Delay meshgrid until after circle construction
x_torus = (R0 + a*np.cos(theta)) * np.cos(phi)
y_torus = (R0 + a*np.cos(theta)) * np.sin(phi)
z_torus = a * np.sin(theta)
c_torus = np.full_like(x_torus, (0.0, 0.5, 1.0, 1.0), dtype=(float, 4))
# Create the bridge, filled with transparency
x_bridge = np.vstack([x_circle[-1,:],x_torus[0,:]])
y_bridge = np.vstack([y_circle[-1,:],y_torus[0,:]])
z_bridge = np.vstack([z_circle[-1,:],z_torus[0,:]])
c_bridge = np.full_like(z_bridge, (0.0, 0.0, 0.0, 0.0), dtype=(float, 4))
# Join the circle and torus with the transparent bridge
X = np.vstack([x_circle, x_bridge, x_torus])
Y = np.vstack([y_circle, y_bridge, y_torus])
Z = np.vstack([z_circle, z_bridge, z_torus])
C = np.vstack([c_circle, c_bridge, c_torus])
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=C, linewidth=0)
ax.view_init(elev=15, azim=270)
ax.set_xlim( -3, 3)
ax.set_ylim( -3, 3)
ax.set_zlim( -3, 3)
ax.set_axis_off()
plt.show()
,就可以轻松地以纯SwiftUI
完成此操作。您需要用文本遮盖渐变:
UIViewRepresentable
答案 3 :(得分:1)
在csv
中,您可以像下面一样使用feature的概念来实现
GradientView
SwiftUI
GradientLabelWrapper:
struct GradientView: View {
var body: some View {
VStack {
GradientLabelWrapper(width: 150) // you can give as you want
.frame(width: 200, height: 200, alignment: .center) // set frame as you want
}
}
}
UILabel:扩展名
struct GradientLabelWrapper: UIViewRepresentable {
var width: CGFloat
var text: String?
typealias UIViewType = UIView
func makeUIView(context: UIViewRepresentableContext<GradientLabelWrapper>) -> UIView {
let label = UILabel()
label.lineBreakMode = .byWordWrapping
label.numberOfLines = 0
label.preferredMaxLayoutWidth = width
label.text = text ?? ""
label.font = UIFont.systemFont(ofSize: 25) //set as you need
label.applyGradientWith(startColor: .red, endColor: .blue)
return label
}
func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<GradientLabelWrapper>) {
}
}
答案 4 :(得分:0)
您可以使用它来使渐变成为文本的前景色:
Text("Hello World")
.padding()
.foregroundColor(.white)
.background(LinearGradient(gradient: Gradient(colors: [.white, .black]), startPoint: .top, endPoint: .bottom))
希望这会有所帮助:)您也可以使用以下链接作为参考:https://www.hackingwithswift.com/quick-start/swiftui/how-to-render-a-gradient
答案 5 :(得分:0)
我会说在纯SwiftUI中是不可能的。您需要使用经过修改的UILabel
并通过UIViewRepresentable
进行包装,才能在SwiftUI中使用它。
我从先前的答案中抓取了代码,为水平渐变创建了一个基本示例:
class GradientLabel: UILabel {
var gradientColors: [CGColor] = []
override func drawText(in rect: CGRect) {
if let gradientColor = drawGradientColor(in: rect, colors: gradientColors) {
self.textColor = gradientColor
}
super.drawText(in: rect)
}
private func drawGradientColor(in rect: CGRect, colors: [CGColor]) -> UIColor? {
let currentContext = UIGraphicsGetCurrentContext()
currentContext?.saveGState()
defer { currentContext?.restoreGState() }
let size = rect.size
UIGraphicsBeginImageContextWithOptions(size, false, 0)
guard let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(),
colors: colors as CFArray,
locations: nil) else { return nil }
let context = UIGraphicsGetCurrentContext()
context?.drawLinearGradient(gradient,
start: CGPoint.zero,
end: CGPoint(x: size.width, y: 0),
options: [])
let gradientImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
guard let image = gradientImage else { return nil }
return UIColor(patternImage: image)
}
}
struct MyTextView: UIViewRepresentable {
var width: CGFloat
func makeUIView(context: Context) -> GradientLabel {
let label = GradientLabel()
label.gradientColors = [UIColor.blue.cgColor, UIColor.red.cgColor]
label.lineBreakMode = .byWordWrapping
label.numberOfLines = 0
label.preferredMaxLayoutWidth = width
label.text = "Here's a lot of text for you to display. It won't fit on the screen."
return label
}
func updateUIView(_ view: GradientLabel, context: Context) {
}
}
struct ContentView: View {
var body: some View {
GeometryReader { geometry in
MyTextView(width: geometry.size.width)
}
}
}
Reference to the GradientLabel class
Reference to wrapping a UILabel to use in SwiftUI
我希望这会有所帮助!