简体   繁体   中英

How can I create this view in SwiftUI?

I am trying to create a view like this in SwiftUI (sorry it's so huge): 屏幕模型

Specifically, I'm trying to build the scrolling row of labels/bar graph bars in the top quarter of the screen. To me, it looks like a ScrollView with horizontal scrolling, containing some number X of barGraphItems, which are each a VStack with a label and a colored rectangle. The VStack is then rotated 270deg.

Here's the code I have so far:

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()
    }
}

And here's what it produces (sorry it's so huge): swiftui预览

How can I get the barGraphItems closer together? How can I add the "Budget" line? How can I make the whole business scrollable WITHOUT scrolling the Budget line?

I think the other elements onscreen I can suss out, but I've been fiddling with this bar graph widget all afternoon and I'm stumped.

The problem with applying rotation effect to complex container having many views is that layout of container does not change, so all other views affected by rotated container

It looks more appropriate different approach. The idea is to have plot bars as rectangles where height or rectangle show values, and label is a transformed overlay for such rectangle, thus rectangles form layout, and overlays do not affect anything (almost).

Tested with Xcode 11.4 / iOS 13.4

Note: the budget line can be added above plot scrollview by wrap both into 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
        }
    }
}

backup

To answer your first question: "How can I get the barGraphItems closer together?"

I replaced your code with this: -These changes fix the problem where your bars begin to be misaligned by adding.fixedSize() to the text.

-You can change the number of bars by increasing or decreasing the range in my for loop. This saves you from copy and pasting the same code.

-You were making several VStacks when you only needed one. This solved the spacing issue and now the bars will come out stuck together with 0 spacing as defined.

Hope this helps!

import SwiftUI

struct ContentView: View {
    var body: some View {
        HStack(alignment: .bottom, spacing: 0) {
            VStack(alignment: .leading, spacing: 0) {
                ForEach(0..<10) {_ in
                    Text("Demo")
                        .font(.caption)
                        .fontWeight(.bold)
                        .fixedSize()

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


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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM