swiftuigraphicsrectanglesbaseline

How to draw SwiftUI Rectangles on a static baseline?


I am trying to create a balance control using 2 rectangles that represent the left and right pan value of a sound. As a start, I'm using a slider to input the values. No matter what I've done with Geometry and baseline and alignment, I cannot get the rectangles to sit on a floor. They insist on floating in space. I want to change the height, but not from the middle out!

import Foundation
import SwiftUI

struct PanView: View {
  @Binding var value: Double
    
    var body: some View {
        HStack(spacing: 10) {
          leftBar
          rightBar
        }
    }
    
    private var leftBar: some View {
      Rectangle()
        .fill(Color(.green))
        .frame(width: barWidth,
               height: abs(value - 50),
               alignment: .bottom)
    }
    
    private var rightBar: some View {
      Rectangle()
        .fill(Color(.red))
        .frame(width: barWidth,
               height: abs(value + 50),
               alignment: .bottom)
    }
    
    private var barWidth: CGFloat {
      return 50 // Adjust the width as per your preference
    }
  }

struct PanView_Used: View {
  @State private var barValue:Double = 0.0
  
  var body: some View {
    VStack {
      Text("Bar Graph at \(Int(barValue))")
        .font(.title)
      
      PanView(value: $barValue)
      
      Slider(value: $barValue, in: -50...50, step:Double.Stride(1), onEditingChanged: {e in})
    }
  }
}

struct  PV_Previews: PreviewProvider {
  static var previews: some View {
    PanView_Used()
  }
}

The horrid results are shown below. How can I get these things to sit still??

    

Solution

  • You didn't give it any alignments, so it defaulted. For HStacks, that means centered vertically. VStacks default to center horizontally. Adding appropriate alignments tames the views. Comments in code:

    struct PanView: View {
        @Binding var value: Double
        
        var body: some View {
            // bottom align this HStack
            HStack(alignment: .bottom, spacing: 10) {
                leftBar
                rightBar
            }
        }
        
        ...
    
    }
    
    struct PanView_Used: View {
        @State private var barValue:Double = 0.0
        
        var body: some View {
            VStack {
                Text("Bar Graph at \(Int(barValue))")
                    .font(.title)
                
                PanView(value: $barValue)
                    // Frame this since you know the max height already, and bottom align it.
                    .frame(height: 100, alignment: .bottom)
                
                Slider(value: $barValue, in: -50...50, step:Double.Stride(1), onEditingChanged: {e in})
            }
        }
    }
    

    Edit:

    On the HStack in Pan view works as well.

    struct PanView: View {
        @Binding var value: Double
        
        var body: some View {
            // bottom align this HStack
            HStack(alignment: .bottom, spacing: 10) {
                leftBar
                rightBar
            }
                    // Frame this since you know the max height already, and bottom align it.
                    .frame(height: 100, alignment: .bottom)
    
        }
    

    enter image description here