StackView layout side by side & on Top of each other (like zStack)

你说的曾经没有我的故事 提交于 2021-02-11 12:50:57

问题


I currently have this interface whereby I am putting a MapView and a UIView on top of each other. The UIView is where I put my chart overlay (eg: Heart Rate).

This is fine when the device is in portrait mode. However, I would like to explore a different layout when in landscape mode whereby the UIView(HR Chart) and the MapView is side by side.

Is this doable in Interface Builder? Or only in code? (I would like to only use UIKit to better support lower OSes)

note : I tried in IB but can't seem to figure out how to get the Stack such that the MapView and UIView is on top of each other in Portrait mode.

This is how it looks like now. But I would like to the Chart and the Map side by side in landscape mode.

Edit for clarification on current layout in portrait mode and desired outcome in landscape mode. How the layout looks like. enter image description here


回答1:


This can be done by using Trait Variations on stack views, changing the Axis between Vertical and Horizontal.

Consider this layout - I've given the labels background colors to help visualize:

  • Each "name / Value" label set is in a Vertical Stack View
  • Each "Pair" of "sets" - Power / Slope, Distance / Elapsed Time, Heart Rate / Cadence - is also in their own Vertical Stack View
  • The 3 "pairs" are in a Horizontal Stack View

Select the RedPairStack and, in the Attributes Inspector pane, click the + icon to the left of the Axis:

From that popup, change Width to Any and change Height to Compact and click Add Variation:

For the new hC variation, select Horizontal:

Do the same for the GreenPairStack and the BluePairStack.

Now, when the device is has a Regular Height, those three stack views will use a Vertical Axis... in Compact Height, they'll use a Horizontal Axis.

Here's the result:

Here is the source to the Storyboard so you can inspect everything: https://pastebin.com/dqNp8CcC


Edit - after comments...

To get side-by-side, we need a few changes:

Looks very similar, but:

  • embedded the "label/value" horizontal stack in a UIView - "PairsContainerView" (cantaloupe background)
  • embed that view plus the Map view in a Vertical stack view

I removed the Trait variations from the PairStacks, then constrained the HorizontalStack to all 4 sides of the "PairsContainerView"

The result looks good at first, but when rotating the labels get stretched out. So, we add a couple new Trait Variations.

First, set the Content Hugging Priority on all the labels to Required.

Next, for Compact Height (hC) trait, we add a CenterY constraint to the HorizontalStack, and remove the Top and Bottom constraints.

Here's the new results:

and with colors removed:

Since you didn't provide an image of how you want your layout to look, this may be close enough to get you on your way.

New Storyboard souce: https://pastebin.com/TkVbNUVE


Edit 2

Start with the first example above...

Add a UIView as a sibling of the Map View and assign its Custom Class to HeartRateView:

Here's my quick HeartRateView (red squiggly line):

class HeartRateView: UIView {

    let shapeLayer = CAShapeLayer()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    
    func commonInit() -> Void {
        layer.addSublayer(shapeLayer)
        shapeLayer.strokeColor = UIColor.red.cgColor
        shapeLayer.fillColor = UIColor.clear.cgColor
        shapeLayer.lineWidth = 1.0

        let pth = UIBezierPath()
        let topY: CGFloat = 40.0
        var pt: CGPoint = CGPoint(x: 0.0, y: topY)
        pth.move(to: pt)
        for _ in 1...30 {
            pt.x += 2
            pt.y = topY + CGFloat.random(in: 0...40)
            pth.addLine(to: pt)
        }
        
        shapeLayer.path = pth.cgPath
    }

}

Add these constraints to HeartRateView:

  • Top equal to MapView Top
  • Leading equal to MapView Leading
  • Width equal to MapView Width
  • Height equal to MapView Height

As you would expect, this will "overlay" the HeartRateView on the MapView.

Now, in Storyboard, switch the Orientation to Landscape and click the "Vary for Traits" button. From that popup, select Height

Select the MapView in the Document Outline pane, and over in the Size Inspector pane, select the Trailing to Safe Area and Leading to Heart Rate View constraints:

Tap Delete on your keyboard - it will delete those constraints only for this Trait variation. Should look like this:

and your view should look like this:

Select the Heart Rate View and constrain its Trailing to the Safe Area (I'm using 4-pts padding on everything). Your view should now look like this (Heart Rate View has a clear background, so we can only see the selection handles):

Now add a constraint from MapView Trailing to HeartRateView Leading (of 4 for the little padding):

Because HeartRateView is still constrained Equal Width to MapView, they automatically fill out the width.

Last step, click Done Varying

Now we get this output:

Here's the third Storyboard source: https://pastebin.com/2hPXisAH



来源:https://stackoverflow.com/questions/65612510/stackview-layout-side-by-side-on-top-of-each-other-like-zstack

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!