使用SwiftUI的新态。第2部分:可访问性可以做什么?

大家好!预期将推出高级课程“ IOS Developer”,我们将发布有关使用SwiftUI的新态的文章第二部分的翻译(请阅读第一部分)。





黑暗主题


在开始了解如何改善新态的可用性之前,让我们先看看如何使用效果来创建其他有趣的样式。

首先为扩展名再添加两种颜色,Color以便手边有几个常数值:

static let darkStart = Color(red: 50 / 255, green: 60 / 255, blue: 65 / 255)
static let darkEnd = Color(red: 25 / 255, green: 25 / 255, blue: 30 / 255)

我们可以将它们用作的背景ContentView,代替现有的背景Color.white,如下所示:

var body: some View {
    ZStack {
        LinearGradient(Color.darkStart, Color.darkEnd)

我们的SimpleButtonStyle现在看起来不合适,因为它在深色背景上施加了明亮的样式。因此,我们将创建一个在这里效果更好的新深色样式,但是这次我们将其分为两个部分:一个可以在任何地方使用的背景视图,以及一个用padding和contentShape修饰符包裹起来的按钮样式。如您稍后所见,这将为我们提供更大的灵活性。

我们将要添加的新背景视图将使我们能够为视觉效果指定任何形状,因此我们不再附加到圆上。它还将跟踪是否使我们的凸效果(向内或向外)凹入,具体取决于isHighlighted我们可以从外部更改的属性

我们将从最简单的开始,使用修改后的阴影翻转方法来获得凹面效果。添加此结构:

struct DarkBackground<S: Shape>: View {
    var isHighlighted: Bool
    var shape: S

    var body: some View {
        ZStack {
            if isHighlighted {
                shape
                    .fill(Color.darkEnd)
                    .shadow(color: Color.darkStart, radius: 10, x: 5, y: 5)
                    .shadow(color: Color.darkEnd, radius: 10, x: -5, y: -5)

            } else {
                shape
                    .fill(Color.darkEnd)
                    .shadow(color: Color.darkStart, radius: 10, x: -10, y: -10)
                    .shadow(color: Color.darkEnd, radius: 10, x: 10, y: 10)
            }
        }
    }
}

修改是,当按下按钮时,阴影的大小减小-我们使用5点而不是10点的距离。

然后,可以在DarkButtonStylepadding和contentShape 的帮助下将其包装,如下所示:

struct DarkButtonStyle: ButtonStyle {
    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
            .padding(30)
            .contentShape(Circle())
            .background(
                DarkBackground(isHighlighted: configuration.isPressed, shape: Circle())
            )
    }
}

最后,我们可以ContentView通过更改将其应用于按钮ButtonStyle()

.buttonStyle(DarkButtonStyle())

让我们看看发生了什么-尽管我们没有太多代码,但我认为结果看起来足够好。



一些实验


现在是尝试效果的时候了,因为它将帮助您更好地了解SwiftUI的特定功能。

例如,我们可以通过向其添加线性渐变并在按下时将其翻转来创建平滑的凸形按钮:

if isHighlighted {
    shape
        .fill(LinearGradient(Color.darkEnd, Color.darkStart))
        .shadow(color: Color.darkStart, radius: 10, x: 5, y: 5)
        .shadow(color: Color.darkEnd, radius: 10, x: -5, y: -5)

} else {
    shape
        .fill(LinearGradient(Color.darkStart, Color.darkEnd))
        .shadow(color: Color.darkStart, radius: 10, x: -10, y: -10)
        .shadow(color: Color.darkEnd, radius: 10, x: 10, y: 10)
}

如果运行此按钮,则在按下和释放按钮时,将看到该按钮平滑地上下动画。我认为动画有点让人分心,所以我建议通过在此存在的修改器之后,将此修改器添加到makeBody()from中的方法禁用它DarkButtonStylebackground()

.animation(nil)



缓冲按钮的这种效果很迷人,但是如果您打算使用它,我建议您尝试以下三个更改以使按钮更加突出。

首先,尽管这与新变形设计的低对比度原理相矛盾,但我还是将灰色图标替换为白色图标以使其脱颖而出。因此,ContentView您将需要以下内容:

Image(systemName: "heart.fill")
    .foregroundColor(.white)

其次,如果为处于按下状态的按钮添加叠加,这不仅使它看起来更像是均匀按下的实际物理按钮,而且还有助于区分其按下状态和未按下状态。

要实现这一点,你需要插入修改overlay()fill(),当isHighlighted它是真实的,如下:

if isHighlighted {
    shape
        .fill(LinearGradient(Color.darkEnd, Color.darkStart))
        .overlay(shape.stroke(LinearGradient(Color.darkStart, Color.darkEnd), lineWidth: 4))
        .shadow(color: Color.darkStart, radius: 10, x: 5, y: 5)
        .shadow(color: Color.darkEnd, radius: 10, x: -5, y: -5)



要获得更清晰的外观,您可以删除两个shadow()按下状态的修改器,否则它们将专注于叠加。

第三,您也可以将叠加层添加到未按下状态,仅用于标记它是一个按钮。紧接着放在fill(),就像这样:

} else {
    shape
        .fill(LinearGradient(Color.darkStart, Color.darkEnd))
        .overlay(shape.stroke(Color.darkEnd, lineWidth: 4))
        .shadow(color: Color.darkStart, radius: 10, x: -10, y: -10)
        .shadow(color: Color.darkEnd, radius: 10, x: 10, y: 10)
}



添加开关样式


将按钮样式与非变形背景样式分开的优点之一是,我们现在可以使用相同的效果添加开关样式。这意味着创建ToggleStyle与相似的新协议兼容结构ButtonStyle,除了:

  1. 我们需要阅读configuration.isOn以确定开关是否打开。
  2. 我们需要提供一个按钮来处理切换动作,或者至少是类似的东西onTapGesture()

将此结构添加到您的项目中:

struct DarkToggleStyle: ToggleStyle {
    func makeBody(configuration: Self.Configuration) -> some View {
        Button(action: {
            configuration.isOn.toggle()
        }) {
            configuration.label
                .padding(30)
                .contentShape(Circle())
        }
        .background(
            DarkBackground(isHighlighted: configuration.isOn, shape: Circle())
        )
    }
}

我们想要放入其中一个,ContentView以便您可以自己对其进行测试,因此首先添加以下属性:

@State private var isToggled = false

然后VStack以等于40的间距包装现有按钮并将其放在下面:

Toggle(isOn: $isToggled) {
    Image(systemName: "heart.fill")
        .foregroundColor(.white)
}
.toggleStyle(DarkToggleStyle())

您的结构ContentView应如下所示:

struct ContentView: View {
    @State private var isToggled = false

    var body: some View {
        ZStack {
            LinearGradient(Color.darkStart, Color.darkEnd)

            VStack(spacing: 40) {
                Button(action: {
                    print("Button tapped")
                }) {
                    Image(systemName: "heart.fill")
                        .foregroundColor(.white)
                }
                .buttonStyle(DarkButtonStyle())

                Toggle(isOn: $isToggled) {
                    Image(systemName: "heart.fill")
                        .foregroundColor(.white)
                }
                .toggleStyle(DarkToggleStyle())
            }
        }
        .edgesIgnoringSafeArea(.all)
    }
}

就是这样-我们在两个地方应用了常见的新变形设计!

无障碍改善


我们有足够的时间来处理各种新变形样式,但现在我想着重于此设计的问题:极度缺乏对比度,意味着按钮和其他重要控件不足以使其周围环境脱颖而出,这使得难以为有残障人士使用我们的应用程序视力不全。

这是我发现一些误解的时刻,因此我想提前说几件事:

  1. 是的,我知道标准的Apple按钮看上去就像蓝色的文本,因此至少乍一看并不像熟悉的按钮,但是它们具有很高的对比度。
  2. « , , » — — « », , , - .
  3. - SwiftUI, , VoiceOver Apple.

您已经了解了我们如何将灰色图标更改为白色以立即增强对比度,但是如果要使按钮和开关更易于访问,它们仍然需要更多的对比度。

因此,我们将考虑可以进行哪些更改,以使这些元素真正脱颖而出。

首先,我希望您在我们的扩展程序中添加两种新颜色:

static let lightStart = Color(red: 60 / 255, green: 160 / 255, blue: 240 / 255)
static let lightEnd = Color(red: 30 / 255, green: 80 / 255, blue: 120 / 255)

其次,复制现有DarkBackground副本并命名副本ColorfulBackground我们将在稍后处理它,但是再次,首先,我们需要做一些准备。

第三,复制按钮的深色样式并进行切换,将它们重命名为ColorfulButtonStyleColorfulToggleStyle,然后使它们使用新的ColorfulBackground作为背景。

因此,它们应如下所示:

struct ColorfulButtonStyle: ButtonStyle {
    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
            .padding(30)
            .contentShape(Circle())
            .background(
                ColorfulBackground(isHighlighted: configuration.isPressed, shape: Circle())
            )
            .animation(nil)
    }
}

struct ColorfulToggleStyle: ToggleStyle {
    func makeBody(configuration: Self.Configuration) -> some View {
        Button(action: {
            configuration.isOn.toggle()
        }) {
            configuration.label
                .padding(30)
                .contentShape(Circle())
        }
        .background(
            ColorfulBackground(isHighlighted: configuration.isOn, shape: Circle())
        )
    }
}

最后,编辑按钮并切换ContentView为使用新样式:

Button(action: {
    print("Button tapped")
}) {
    Image(systemName: "heart.fill")
        .foregroundColor(.white)
}
.buttonStyle(ColorfulButtonStyle())

Toggle(isOn: $isToggled) {
    Image(systemName: "heart.fill")
        .foregroundColor(.white)
}
.toggleStyle(ColorfulToggleStyle())

您可以根据需要运行该应用程序,但这没有任何意义-实际上并没有更改。

为了带来丰富多彩的生活,我们将更改修饰符以及按下状态 fill()overlay()未按下状态。因此,当为isHighlightedtrue时,darkStart更改darkEndlightStartlightEnd

if isHighlighted {
    shape
        .fill(LinearGradient(Color.lightEnd, Color.lightStart))
        .overlay(shape.stroke(LinearGradient(Color.lightStart, Color.lightEnd), lineWidth: 4))
        .shadow(color: Color.darkStart, radius: 10, x: 5, y: 5)
        .shadow(color: Color.darkEnd, radius: 10, x: -5, y: -5)

如果再次运行该应用程序,您会发现它已经得到了显着改善:按下状态现在变为亮蓝色,因此当按下按钮且开关处于活动状态时,该状态将变得清晰。但是,我们可以做其他事情-当未按下按钮时,可以在按钮周围添加相同的颜色,从而有助于引起人们的注意。



为此,将现有的overlay()非压力状态更改为此:

.overlay(shape.stroke(LinearGradient(Color.lightStart, Color.lightEnd), lineWidth: 4))


因此,完成的按钮样式应如下所示:

ZStack {
    if isHighlighted {
        shape
            .fill(LinearGradient(Color.lightEnd, Color.lightStart))
            .overlay(shape.stroke(LinearGradient(Color.lightStart, Color.lightEnd), lineWidth: 4))
            .shadow(color: Color.darkStart, radius: 10, x: 5, y: 5)
            .shadow(color: Color.darkEnd, radius: 10, x: -5, y: -5)
    } else {
        shape
            .fill(LinearGradient(Color.darkStart, Color.darkEnd))
            .overlay(shape.stroke(LinearGradient(Color.lightStart, Color.lightEnd), lineWidth: 4))
            .shadow(color: Color.darkStart, radius: 10, x: -10, y: -10)
            .shadow(color: Color.darkEnd, radius: 10, x: 10, y: 10)
    }
}

现在再次运行该应用程序,您将看到在按钮和开关周围出现了一个蓝色的环,并且当单击它时,它会充满蓝色-更易于访问。



结论


实际上,至少在一个项目中,您不会有几种不同的按钮样式,至少您不想让用户感到头疼。但这是一个有趣的实验空间,我希望您能领会我这篇文章的想法,因为您可以创造出非常漂亮的效果而不会退缩。

我已经反复说过,您应该始终监视应用程序的可用性,这不仅仅意味着确保VoiceOver可以与您的用户界面一起使用。确保按钮看起来具有交互性,确保文本标签和图标与背景具有足够的对比度(至少4.5:1,但倾向于7:1),并确保可单击区域舒适且大(至少44x44像素)。

而且,出于天堂的缘故,请使用新设计进行实验并扩展您对SwiftUI的了解,但是请不要忘记,如果您为新的时装设计趋势牺牲了可用性,那么您将一无所获。

你可以得到关于该项目的完整源代码GitHub上

阅读第一部分。



了解有关该课程的更多信息。



All Articles