I cannot understand why in the simulator the layout is different from the layout displayed in xcode/preview.
struct ContentView : View {
var body: some View {
ZStack(alignment: .bottom) {
ARViewContainer()
Text("hello")
}
}
}
here the screenshots:
TLDR; I don't know why your simulator and preview don't match, but I do know why it's appearing the way that it is on the device. Are you getting any errors in the debug?
Any container views in SwiftUI will only take up the required space that they need. they will also distribute according to your settings. For example, you have a ZStack that contains a bottom alignment. You also have a ARViewContainter() that takes up a portion of that stack. They are aligned behind each other on the Z axis where the text is in front and the other container is behind. A quick way to prove this and test it is to include a background shape behind everything for example.
var body: some View {
ZStack {
Rectangle().edgesIgnoringSafeArea(.all)
.foregroundColor(Color.red)
//Your Views
}
}
This will force the ZStack to take up all available space and your other views should then align as expected. Basically, your Text is aligning to the bottom of the maximum provided space, which is being provided by your ARViewContainer()
Further Reading and Understanding
Views only take up the space required for what's in them, unless otherwise specified.
ZStacks operate on the Z axis, forward/backwards.
In your case you have a view with a set size called ARViewContainer() which takes up the width of the screen and a portion of the height. Since it's the largest view you have, the ZStack inherits that size.
Your text is smaller than the ZStack so the ZStack does NOT inherit the size. You do however have a .bottom assignment. So your text is over your ARViewContainer() and aligned to the .bottom edge of that container.
Finally the ZStack is centered in the remaining space available, giving it the impression that your .bottom isn't doing anything, when in reality it is.
Reproducing the Issue
Here is a code snippet that reproduces your issue and makes it a bit clearer and easier to understand.
var body: some View {
ZStack(alignment: .bottom) {
Rectangle().foregroundColor(Color.yellow).frame(width: 100, height: 100, alignment: .center)
Text("Test")
}
}
Related
I added a button in the top right. But I want to measure the button from the right and from the top in a way that is compatible with all screens.
Are you looking to use GeometryReader?
var body: some View {
GeometryReader { geometry in
VStack {
Text("Width: \(geometry.size.width)")
Text("Height: \(geometry.size.height)")
}
}
}
The GeometryReader component is a view container that allows access to its size and position. In this way we can correctly align elements and equalize view sizes.
To my knowledge, the only way to assign a navigation bar a background color that is separate from the rest of the screen, you set the background color to whatever object you have flush with the navigation view. (In this case, its a divider with the background set to red)
My intention is to then place a view flush to the divider in an attempt to create some sort of "subtitle view". The problem is, as you can see, there is a space between my Stack and my Divider... I'm not sure what is causing this space and I am not sure how to get rid of it.
My first thought was, perhaps there is some safe area being adhered to... That said, I tried ignoring that, but that didn't work.
struct ContentView: View {
var body: some View {
NavigationStack {
VStack {
Divider()
.background(.red)
.navigationTitle("Main Title")
// There is a space here
ZStack {
Rectangle().frame(height: 35)
Text("Subtitle View")
.foregroundColor(.white)
}.edgesIgnoringSafeArea([.top, .bottom])
Spacer()
}.background(.blue)
}
}
}
struct Test: View {
var body: some View {
ScrollView{
RoundedRectangle(cornerRadius: 5)
.fill(.red)
RoundedRectangle(cornerRadius: 5)
.fill(.red)
Text("test")
}
}
}
So I have this view, and from what I know RoundedRectangles are supposed to be flexible and take up all the space so how come when I put two in a ScrollView like this they seem to take the minimum possible space?
The scroll view sets its content size based on the size of its children. The shapes try to fill their parent. Both are trying to figure out how big to be.
Your going to need to put them in a different container that has a fixed size.
I am trying to loop through a list of 2-6 items. They are all Text() views for this example, and I want them to all squeeze to the left. This code below is as close as I have gotten
Why? I am simplifying the actual problem to make solving easier
HStack{
ForEach(array, id: \.self) { pageItem in
HStack{
PageDataItemView(pageItem: pageItem)
}.fixedSize()
}
VStack(){
Spacer()
}
}
.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
.frame(height: 40.0)
PageDataItemView for this example is just Text().
Anyway what I can't seem to solve is to make PageDataItemView's width based on the text content. In the code above they squeeze, but they all overlap each other, rather than taking their own space. Removing .fixedSize() above causes the items to fill the full width evenly.
In Android's XML I could just use "wrap_content" to produce this. While I understand this is not the ideal way to build UI here, it has to do with a complex client request.
Update:
GeometryReader { geometry in
Seems to be causing my views to break as this is inside PageDataItemView. Even when geometry isn't even used at all. Once removed everything worked as expected, curious why this effects a view indirectly. Let me know if I should remove this question.
I'm embedding a view controller with variable-height UITextView inside a parent SwiftUI VStack and the view controller sizes it's frame to the whole screen between viewDidLoad and viewDidLayoutSubviews. The UITextView expands only to the size of the text inside itself and centers itself inside the parent view.
I'm trying to add this view controller in a VStack and have it behave externally like other SwiftUI components do - sized exactly to the content it contains - but it wants to be sized to the whole screen minus the other VStack elements.
I can get the correct size of the UITextView in didLayoutSubviews and pass it upwards to SwiftUI where it can be set properly - but where do I do that?
In the example screenshot below, the orange is the embedded UIView background, the green is the UITextView and the VStack looks like this:
VStack {
HighligherVC()
Text("Tap and drag to highlight")
.foregroundColor(.gray)
.font(.caption)
}
Without being able to see more of your code, it's slightly difficult to say what the best solution would be, but based purely on this part of your question...
I can get the correct size of the UITextView in didLayoutSubviews and pass it upwards to SwiftUI where it can be set properly - but where do I do that?
I would suggest that you pass a binding property to your view controller that can be set to the calculated text view height, meaning that the view that contains your VStack would have a #State property like this:
#State private var textViewHeight: CGFloat = 0
You would then declare a #Binding property on your HighlighterVC and add an initializer like this:
#Binding var textViewHeight: CGFloat
init(textViewHeight: Binding<CGFloat>) {
self._textViewHeight = textViewHeight
}
And then you would set textViewHeight to the calculated height in your didLayoutSubviews and add a .frame modifier to your HighlighterVC like this:
VStack {
HighlighterVC(textViewHeight: self.$textViewHeight)
.frame(height: self.textViewHeight)
Text("Tap and drag to highlight")
.foregroundColor(.gray)
.font(.caption)
}
Like I said at the beginning of my answer, this solution (that I believe would work, but since I can't test it, I'm not 100% certain) is based on your thoughts about what it is that you need. Without seeing more code, it's impossible for me to say if this is the best solution.
Add fixedSize may solve this.
.fixedSize(horizontal: false, vertical: true)