在SwiftUI中显示分隔线/分割视图

73

我想在我的SwiftUI应用程序中展示一个分隔线。为了达到这个目的,我尝试创建一个带有固定框架和背景颜色/边框的空视图:

EmptyView()
    .frame(width: 200, height: 2)
    .background(Color.black) // or:
    .border(Color.black, width: 2)

很遗憾,我看不到任何暗模式的显示。
有办法显示分隔符/线条视图吗?

6个回答

130
使用分隔线视图

一种可用于分隔其他内容的视觉元素。

示例:

struct ContentView : View {
    var body: some View {
        VStack {
            Text("Hello World")
            Divider()
            Text("Hello Another World")
        }
    }
}

输出: {{link1:输入图像描述}}

3
啊!我尝试了“Separator”、“Line”,但没想到“Divider”。谢谢! - LinusGeffarth
2
你如何消除这条线下面和上面的神秘填充? - coolcool1994
3
将 VStack 的 spacing 设为零。即 VStack(spacing: 0) {…} - 1-877-547-7272

89

如果有人对这样看起来像这样的分隔符、文本、分隔符感兴趣:

输入图像描述

LabelledDivider 代码

struct LabelledDivider: View {

    let label: String
    let horizontalPadding: CGFloat
    let color: Color

    init(label: String, horizontalPadding: CGFloat = 20, color: Color = .gray) {
        self.label = label
        self.horizontalPadding = horizontalPadding
        self.color = color
    }

    var body: some View {
        HStack {
            line
            Text(label).foregroundColor(color)
            line
        }
    }

    var line: some View {
        VStack { Divider().background(color) }.padding(horizontalPadding)
    }
}

这看起来有些丑,但我不得不将Divider放到VStack中以使它们水平排列,否则,由于HStack,它们将是垂直排列的。如果您能简化此操作,请告诉我 :)

另外,也许对于LabelledDivider使用和存储属性可能不是最符合SwiftUI的解决方案,因此我可以接受改进。

示例用法

这是导致上面屏幕截图的代码:

struct GetStartedView: View {
    var body: some View {
        NavigationView {
            VStack {

                NavigationLink(destination: SignInView()) {
                    Text("Sign In").buttonStyleEmerald()
                }

                LabelledDivider(label: "or")

                NavigationLink(destination: SignUpView()) {
                    Text("Sign up").buttonStyleSaphire()
                }

            }.padding(20)
        }
    }
}

按钮样式

为了完整起见,我还包括buttonStyle视图修饰符:

struct ButtonStyle: ViewModifier {

    private let color: Color
    private let enabled: () -> Bool
    init(color: Color, enabled: @escaping () -> Bool = { true }) {
        self.color = color
        self.enabled = enabled
    }

    dynamic func body(content: Content) -> some View {
        content
            .padding()
            .frame(minWidth: 0, maxWidth: .infinity, alignment: .center)
            .foregroundColor(Color.white)
            .background(enabled() ? color : Color.black)
            .cornerRadius(5)
    }
}

extension View {
    dynamic func buttonStyleEmerald(enabled: @escaping () -> Bool = { true }) -> some View {
        ModifiedContent(content: self, modifier: ButtonStyle(color: Color.emerald, enabled: enabled))
    }

    dynamic func buttonStyleSaphire(enabled: @escaping () -> Bool = { true }) -> some View {
        ModifiedContent(content: self, modifier: ButtonStyle(color: Color.saphire, enabled: enabled))
    }

}

编辑:请注意,Color.saphireColor.emerald 是自定义声明的颜色:

extension Color {
    static var emerald:     Color { .rgb(036, 180, 126) }
    static var forest:      Color { .rgb(062, 207, 142) }
}

extension Color {
    static func rgb(_ red: UInt8, _ green: UInt8, _ blue: UInt8) -> Color {
        func value(_ raw: UInt8) -> Double {
            return Double(raw)/Double(255)
        }
        return Color(
            red: value(red),
            green: value(green),
            blue: value(blue)
        )
    }
}

Color.Radix.emerald 是什么? - fulvio
我只是声明了一些颜色...随意用你自己的替换 :) - Sajjon
@Sajjon 我知道有点晚了,但你可以删除init并且只需在视图构造函数中以类似的方式定义标签。这样可以减少一层复杂度。 - Harry J
我使用非常类似的代码,并且不得不添加 .lineLimit(1).fixedSize() 以防止长翻译出现换行和省略号。 - Jannik Arndt
继承颜色分隔器的浅色和深色主题,颜色为:Color = Color(UIColor.separator) - Codelaby
继承颜色分隔器的浅色和深色主题,颜色为:Color = Color(UIColor.separator) - undefined

37

您可以使用Color绘制一条线。如果您想要更改线宽或填充,可以像其他SwiftUI组件一样使用framepadding

//Horizontal Line in VStack
VStack{
    Color.gray.frame(height: 1 / UIScreen.main.scale)
}
//Vertical Line in HStack
HStack{
    Color.gray.frame(width: 1 / UIScreen.main.scale)
}

1
虽然这段代码可能回答了问题,但是提供关于为什么或者如何回答问题的额外上下文可以提高其长期价值。 - β.εηοιτ.βε
好的提示。我以前不知道可以根据颜色创建框架。谢谢。 - Mahmud Ahsan
1
智能而简洁。 - Ismet Sahin
非常优雅,谢谢。 - Dmytro Titov

3
如果你想要自定义分隔符,那么系统本身没有提供此功能。你需要提供自己的自定义实现:
struct CustomDivider: View {
    let height: CGFloat = 1
    let color: Color = .white
    let opacity: Double = 0.2
    
    var body: some View {
        Group {
            Rectangle()
        }
        .frame(height: height)
        .foregroundColor(color)
        .opacity(opacity)
    }
}

解决方案很好,但是为什么你在这里使用 Group?似乎没有它也可以工作。 - Denis

1

回复变体 @Sajjon

修复:

  • 默认界面颜色分隔符为除数
  • 截断文本
  • 修正间距
  • 将行调整到文本中心
struct LabelledDivider: View {

    let label: String
    let horizontalPadding: CGFloat
    let color: Color

    init(label: String, horizontalPadding: CGFloat = 8, color: Color = Color(UIColor.separator)) {
        self.label = label
        self.horizontalPadding = horizontalPadding
        self.color = color
    }

    var body: some View {
        HStack(alignment: .center, spacing: 0) {
            line
            Text(label)
                .font(.callout)
                .foregroundColor(color)
                .lineLimit(1)
                .fixedSize()
                .offset(y: -1)
            line
        }
    }

    var line: some View {
        VStack() { Divider().frame(height: 1).background(color) }.padding(horizontalPadding)
    }
}

struct PositionSampleView: View {
    var body: some View {

        LabelledDivider(label: "or")

        
    }
    
}

enter image description here


-1
HStack {
    VStack {
        Divider()
    }
    Text("or")
        .font(.caption)
        .foregroundColor(Color(UIColor.systemGray))
    VStack {
        Divider()
    }
}

为什么要回答一个已经三年前完成的主题?! - Iskandir
请记住,Stack Overflow 不仅旨在解决当前的问题,还要帮助未来的读者找到类似问题的解决方案,这需要理解底层代码。对于我们社区中的初学者和不熟悉语法的成员来说,这尤其重要。鉴于此,您能否编辑您的答案,包括您正在做什么以及为什么您认为这是最好的方法的解释 - Jeremy Caney

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接