首页 > 解决方案 > 如何在 SwiftUI 中创建此视图?

问题描述

我正在尝试在 SwiftUI 中创建这样的视图(抱歉它太大了): 屏幕模型

具体来说,我正在尝试在屏幕的上四分之一处构建标签/条形图条的滚动行。对我来说,它看起来像一个水平滚动的 ScrollView,包含一些 X 个 barGraphItems,每个都是一个带有标签和彩色矩形的 VStack。然后将 VStack 旋转 270 度。

这是我到目前为止的代码:

import SwiftUI

struct ContentView: View {
    var body: some View {
        HStack(alignment: .bottom, spacing: 0) {
            Spacer()
            VStack(alignment: .leading, spacing: 0) {
                Text("Demo")
                    .font(.caption)
                    .fontWeight(.bold)

                Rectangle().foregroundColor(.orange)
                    .frame(width: 84, height: 10)
            }
            .rotationEffect(Angle(degrees: 270.0))

            VStack(alignment: .leading, spacing: 0) {
                Text("Demo")
                    .font(.caption)
                    .fontWeight(.bold)

                Rectangle().foregroundColor(.orange)
                    .frame(width: 84, height: 10)
            }
            .rotationEffect(Angle(degrees: 270.0))

            VStack(alignment: .leading, spacing: 0) {
                Text("Demo")
                    .font(.caption)
                    .fontWeight(.bold)

                Rectangle().foregroundColor(.orange)
                    .frame(width: 84, height: 10)
            }
            .rotationEffect(Angle(degrees: 270.0))

            VStack(alignment: .leading, spacing: 0) {
                Text("Demo")
                    .font(.caption)
                    .fontWeight(.bold)

                Rectangle().foregroundColor(.orange)
                    .frame(width: 84, height: 10)
            }
            .rotationEffect(Angle(degrees: 270.0))

            VStack(alignment: .leading, spacing: 0) {
                Text("Demo")
                    .font(.caption)
                    .fontWeight(.bold)

                Rectangle().foregroundColor(.orange)
                    .frame(width: 84, height: 10)
            }
            .rotationEffect(Angle(degrees: 270.0))

        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

这就是它产生的结果(抱歉它太大了): swiftui预览

如何让 barGraphItems 靠得更近?如何添加“预算”行?如何在不滚动预算行的情况下使整个业务可滚动?

认为屏幕上的其他元素我可以弄清楚,但我整个下午都在摆弄这个条形图小部件,我被难住了。

标签: iosxcodelayoutswiftui

解决方案


将旋转效果应用于具有许多视图的复杂容器的问题是容器的布局不会改变,因此所有其他视图都会受到旋转容器的影响

它看起来更适合不同的方法。这个想法是将绘图条作为矩形,其中高度或矩形显示值,标签是此类矩形的转换覆盖,因此矩形形成布局,并且覆盖不会影响任何东西(几乎)。

使用 Xcode 11.4 / iOS 13.4 测试

注意:预算线可以添加到绘图滚动视图上方,方法是将两者都包装成ZStack.

演示

演示2

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        VStack(alignment: .leading, spacing: 0) {
            Text("Title above").font(.largeTitle)
            ContentView()
            Text("comment below")
        }
    }
}


struct ContentView: View {
    var plotHeight: CGFloat = 120

    // test with different lenth labels
    let demos = ["Demo", "Demoos", "Demoooos", "Demooooooos"]

    var body: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack(alignment: .bottom, spacing: 24) {
                ForEach(0..<20) {_ in
                    Rectangle().foregroundColor(.orange)
                        .frame(width: 14, height: CGFloat.random(in: 0..<self.plotHeight)) // values for demo
                        .overlay(
                            Text(self.demos.randomElement()!) // values for demo
                                .font(.caption)
                                .fontWeight(.bold)
                                .fixedSize()
                                .rotationEffect(Angle(degrees: 270.0), anchor: .leading)
                                .offset(x: -8, y: 6)  // align as/if needed here
                        , alignment: .bottomLeading)
                }
            }
            .frame(height: plotHeight, alignment: .bottom)
            .padding(.leading) // required offset for first label in scrollview
        }
    }
}

推荐阅读