如何在Swift中创建梯度边框

303 阅读7分钟

当涉及到前端开发时,用户界面越清晰越好。这对于移动开发的小屏幕尺寸来说尤其如此。

边框使我们能够在移动应用中突出信息和CTA。然而,有一个边框本身是不够的。为了使边框更有吸引力,并与界面的其他部分保持一致,你可能会发现自己需要一些高级的边框样式。

在这篇文章中,我们将介绍如何为列表和按钮创建一个吸引人的渐变边框。

设置一个待办事项的样本

由于这篇文章的重点是创建和应用梯度边框,我不会深入讨论如何实际创建我们将用作例子的待办事项列表。不过,我按照这个教程创建了一个列表和列表项,供你参考。这篇博文的完整源代码可以在GitHub上找到。

下面是我们构建和应用任何梯度之前的待办事项列表的样子。

To Do List Before Gradients

正如你所看到的,每个列表项都包含一个标题、细节、状态和按钮。具体来说,按钮会执行与相应文本相关的动作。我们将把这些统称为动作。

背景颜色是由待办事项列表项目的状态决定的。如果该项目没有完成,则列表为红色,如果完成则为绿色。很简单,对吗?

使用Swift在列表中应用梯度边框

虽然背景颜色可以帮助我们区分不同的列表项目,但它有点无聊。我个人并不喜欢动作和列表项本身与背景的融合方式。

一个边框不仅可以突出和区分UI元素,而且还可以提供更多的深度和个性。这就是我们的梯度边框可以派上用场的地方

首先,让我们声明我们的梯度边框。我们可以将这些梯度存储在一个名为MyGradients.swift 的文件中。

我们将构建 [overlays](https://developer.apple.com/documentation/swiftui/view/overlay(alignment:content:))来在我们的视图上分层边框。叠加允许你在提供的View上叠加一个二级View要使用它们,你可以简单地创建一个单独的View ,然后把它粘到另一个上,像这样。

SomeView().overlay(
SomeOtherView()
)

如果你想对叠加进行更多的处理,而不仅仅是渲染一个二级View ,比如调整对齐方式,你可以这样写你的叠加。

SomeView().overlay(
    alignment: .topLeading
){
    SomeOtherView()
}

对于我们的具体情况,我们的梯度将作为没有指定对齐方式的叠加传递给用于我们待办事项和行动的Views

在我们的MyGradients.swift ,我们要做的第一件事是导入SwiftUI,并创建一个梯度来用于我们的边框。你可以在下面看到这个。

import SwiftUI

var myGradient = Gradient(
    colors: [
        Color(.systemTeal),
        Color(.systemPurple)
    ]
)

在这里,我们利用了 [Gradient class](https://developer.apple.com/documentation/swiftui/gradient)在这里,我们利用了SwiftUI提供的这个类接受一个列表的 [Color](https://developer.apple.com/documentation/swiftui/color)实例作为参数。你可以添加任何你想要的颜色,但我们现在只添加两个。

我们要创建的下一件事是我们的CardGradient 。这将是我们用于待办事项的梯度边框。

我们通过创建一个符合View 协议的struct 来做到这一点。在body ,我们将再次扩展View 协议并使用 [Rectangle](https://developer.apple.com/documentation/swiftui/rectangle)结构。我们将使用这个形状,因为我们的待办事项默认渲染它。

这个过程概述如下。

struct CardGradient: View{
    var body: some View {
        Rectangle()
            .stroke(
                LinearGradient(
                    gradient: myGradient,
                    startPoint: .leading,
                    endPoint: .trailing
                ),
                lineWidth: 5
            )
    }
}

你所看到的粘附在我们的Rectangle 实例上的stroke(...) 会返回一个新的形状,该形状本质上与所提供的形状一样。在这种情况下,Rectangle 是我们的待办事项列表项目的广度,有一个描边的路径(即边界),其线宽由lineWidth 值定义。我们将使用 [LinearGradient](https://developer.apple.com/documentation/swiftui/lineargradient)在描边路径的内容中加入我们的梯度。

我想指出的是,我们使用的是LinearGradient ,而不是 [RadialGradient](https://developer.apple.com/documentation/swiftui/radialgradient)因为两者的区别更明显。使用RadialGradient ,渐变会从中心向外辐射。这对较大的实体形状来说比较好,而对细长的描边路径来说则比较好。

LinearGradient 需要三个参数:一个 (应用于路径的颜色梯度);一个 ;和一个 。我们将在 中提供 。gradient startPoint endPoint gradient myGradient

对于startPoint ,我们将使用.leading ,表示开始应该是列表中的第一种颜色。endPoint 只是简单地与startPoint 相反。我们使用.trailing ,表示梯度应该向列表中的最后一种颜色混合。

通过使用.leading 和 .trailing ,我们告诉线性渐变应该是水平的而不是垂直的。对于垂直渐变,你可以使用.top.bottom

现在,让我们看看我们的新渐变边框的实际效果吧要做到这一点,我们需要到CardView 。我们可以把梯度作为覆盖物粘到我们的View'sVStack 中,如下图所示。

var body: some View {
        VStack(alignment: .leading) {
            Text(todo.title)
                .font(.headline)
            Spacer();
            Text("Details");
            Text("\(todo.content)")
                .padding(.trailing, 20)
                .font(.caption);
            Spacer();
            Text("Status")
                .frame(minWidth: 0, maxWidth: .infinity, alignment: .trailing);
            Text(todo.isDone == true ? "Done" : "Not Done")
                .font(.caption)
                .frame(minWidth: 0, maxWidth: .infinity, alignment: .trailing);
            Spacer();
            ActionsView()
        }
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
        .padding()
        .background(todo.isDone == true
                    ? Color(red: 0.5804, green: 0.9961, blue: 0.6784)
                    : Color(red: 1, green: 0.4471, blue: 0.4353)
        )
        .overlay(
            CardGradient()
        )
    }

在最后几行代码中,我们还将.overlay() 到我们的CardGradient ,以应用梯度。

现在,让我们看看这在用户界面中的效果如何。

To Do List With Gradient Border

很完美!现在我们有一个很酷的渐变边框应用到我们的待办事项中。

使用Swift为按钮应用渐变色边框

既然我们已经知道了如何为我们的列表项制作渐变边框,我们可以简单地将这个过程应用到我们的按钮上,只需做一些调整。让我们回到MyGradients.swift ,创建我们的第二个梯度边框:ButtonGradient

为了创建这个渐变,我们可以重复使用CardGradient 中的很多代码。然而,我们需要考虑到动作的形状。如果我们使用Rectangle ,我们的叠加将渗出按钮的边界,边框将更多地附着在一个方形形状上。这些将与我们的动作按钮相当不一致。

为了解决这个问题,我们将使用 [Capsule](https://developer.apple.com/documentation/swiftui/capsule)而不是Rectangle

struct ButtonGradient: View{
    var body: some View {
        Capsule()
            .stroke(
                LinearGradient(
                    gradient: myGradient,
                    startPoint: .leading,
                    endPoint: .trailing
                ),
                lineWidth: 5
            )
    }
}

正如你所看到的,除了我们的View 的初始形状外,代码几乎是相同的。我们可以在我们的Actions.swift 文件中看到这一点是如何应用于我们的按钮的。

为了给每个Button ,我们使用了一个叫做ButtonStyle 的属性来应用自定义样式。这个属性接受一个符合ButtonStylestruct ,并包含影响我们Button 的样式的各种属性。

struct MyButtonStyle: ButtonStyle {


    func makeBody(configuration: Configuration) -> some View {
        HStack {
          configuration.label.foregroundColor(.black)
        }
        .padding()
        .scaleEffect(configuration.isPressed ? 0.95 : 1)
        .background(Capsule().foregroundColor(Color.white))
    }
}

这是我们动作的初始样式。它可以像这样应用于每个动作按钮。

Button(action: edit) {
                Text("Edit")
                    .font(.caption)
            }
            .buttonStyle(MyButtonStyle())

现在,为了将我们的ButtonGradient 应用到我们的动作按钮上,我们可以像对待我们的CardView 一样,粘上overlay

struct MyButtonStyle: ButtonStyle {


    func makeBody(configuration: Configuration) -> some View {
        HStack {
          configuration.label.foregroundColor(.black)
        }
        .padding()
        .scaleEffect(configuration.isPressed ? 0.95 : 1)
        .background(Capsule().foregroundColor(Color.white))
        .overlay(
           ButtonGradient()
        )
    }
}

让我们看看这看起来如何。下面是我们应用叠加之前的动作。

Actions Before Overlay

下面是我们应用覆盖层后的动作。

Actions After Overlay

现在,让我们来看看这一切。

Final To Do List

这就是你所拥有的!我们的待办事项的渐变边框和我们的动作的渐变边框都附着在各自的元素形状上。太棒了

总结

列表和按钮的渐变边框是区分你的用户界面特征和创建一个有吸引力的界面的好方法。

如果你想更进一步,可以随意尝试更多的颜色、渐变类型和渐变方向。

如果你想参考,这篇文章的所有配套代码都可以在GitHub上找到。

The postCreating gradient borders in Swiftappeared first onLogRocket Blog.