Update:
It looks like that it only happens on notch-less models. You don't need to do anything on newer models to make both swiftui and the bounds coordinate anchored on the same center.
The red star is the default center on the View. The black star is the "UIScreen midX" which is offset by the status bar I guess. Do I need to calculate the status bar height to center the black star? Thank you.
ZStack{
Text("✧")
.position(x: UIScreen.main.bounds.minX, y: UIScreen.main.bounds.minY)
Text("✧")
.foregroundColor(Color.red)
Text("✧")
.position(x: UIScreen.main.bounds.midX, y: UIScreen.main.bounds.midY)
}
I came across the issue again. And I found that the difference between the swiftui default center point and the UIScreen.main.bounds.height/2 is different across difference device models. You need to use the GeometryReader to get the View's default center and then pass it to other subviews or UIViewRepresentalbe so that the center of other subviews could be aligned to the SwiftUI default view center.
GeometryReader{ proxy in
ZStack{
Text("✧")
.position(x: proxy.size.width/2, y: proxy.size.height/2)
Text("✧")
.foregroundColor(Color.red)
}
}
Related
This is my example code of my app. I want my background to be like this image with soft pink transition to soft blue with some texture soft blur on top of it.
how may i replicate this with just swiftui?
So the first thing you're going to want to do is to utilize LinearGradient and RadialGradient which are the two types of gradients that you can use to compose several layers. There are other ways you can do it by using .background or .overlay modifiers however in my example I want to keep it as simple as possible and allow you the freedom to explore other options with it. I've created two extensions so that you can simply reference LinearGradient.blueClearGradient, for example, directly anywhere in your app. NOTE:: I used different colors, feel free to use what you want to use for your colors. I did this to make it more visually apparent what the individual pieces of the view were composed of.
extension LinearGradient {
static let blueClearGradient = LinearGradient(colors: [.blue, .clear],
startPoint: .bottom,
endPoint: .top)
}
extension RadialGradient {
static let radialYellowGradient = RadialGradient(colors: [.yellow, .clear],
center: .topLeading,
startRadius: 100,
endRadius: 400)
static let radialRedGradient = RadialGradient(colors: [.red, .clear],
center: .topTrailing,
startRadius: 100,
endRadius: 400)
}
Once you have those extensions it's as simple as utilizing them the same as you would any other view. You can use them to .fill or even as a straight up view themselves. In this example, I used them as a .fill for a shape.
struct GradientExample: View {
var body: some View {
ZStack {
Rectangle()
.fill(RadialGradient.radialRedGradient)
Rectangle()
.fill(RadialGradient.radialYellowGradient)
Rectangle()
.fill(LinearGradient.blueClearGradient)
}
}
}
Doing it this way produces a view that might look something like this.
I want to register a certain drag gesture on any SwiftUI view, including ScrollViews simultaneously with any other gestures (i.e. without influencing existing gestures). However, when adding a DragGesture on a ScrollView as follows, it seems like the gesture is immediately swallowed by the ScrollView.
ScrollView {
Rectangle()
.frame(width: 500, height: 500)
}
.simultaneousGesture(
DragGesture()
.onChanged { value in
print("changed:", value.translation)
}
.onEnded { value in
print("ended:", value.translation)
}
)
When I drag the Rectangle, this code prints:
changed: (3.0, 16.666671752929688)
for example.
So onChanged is only called once, onEnded is never called.
Is there a way to make DragGestures work with ScrollViews as well?
Note:
I tried to find a workaround with GestureState and the updating(_:) modifier as well, but it didn't work either.
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")
}
}
I am attempting to build a soccer app. My main detail view shows match statistics. I cannot find any way to get the central text element showing the score of the match to stay in the absolute center, so that the colon in the text is perfectly centred over the guideline on the middle of the screen. With different numbers either side of the colon, it gets shifted slightly out of place.
Is there any way to fix this element to be exactly centered under any circumstances? I have attached a screenshot showing the misalignment.
Code:
VStack() {
HStack(alignment: .center) {
Text("\(matchItem.HomeGoals) : \(matchItem.AwayGoals)")
.font(.system(size: 35.0))
.fontWeight(.heavy)
.foregroundColor(Color.white)
.lineLimit(3)
.multilineTextAlignment(.center)
.fixedSize(horizontal: true, vertical: true)
.allowsTightening(false)
}.padding(15)
}.frame(width: 75, height: 80, alignment: .center)
Example:
You can put your View in a ZStack and the ":" on another Z-level, so it no longer depends on other elements in the same horizontal stack.
I have two views (VStacks) one on top of the other in a ZStack
The first VStack that is behind the second view is used like a menu. The second view that is on top, is the main application view.
When i click on a button i'm scaling down the main view and move it a bit to the right side of the screen to show the menu.
I have a ScrollView inside the main view every time i scale down or up the main view, the animation doesn't work smoothly the page flickers and it looks ugly. if i remove the ScrollView it works perfectly fine.
I tried to replace the ScrollView with a List but it didn't solve the problem the flickering remains the same.
Is there any way to fix this glitch?
below is a sample code
struct ContentView: View {
var body: some View {
ZStack {
Menu()
VStack {
ScrollView(.vertical, showsIndicators: false) {
VStack(spacing:0) {
Header()
MainAppView()
}
}
TabBar()
}
.scaleEffect(self.openMenu ? 0.5 : 1, anchor: UnitPoint(x: 1.5, y: 0.5))
.animation(.easeInOut(duration: 0.2))
}
}
}
Please click to check animated gif example
What you can try is, to make screenshot of the flickering view and then do the animation with the screenshot which you just add on the real view. After the animation just remove the screenshot. Of course you have to make the screenshot programmatically.
I can't repeat all the behavior, because of lack of code. I think you have this problem, because you're scaling down ScrollView and it recomputes all the content. Try just to make some offset for it, instead of scaling and there should be no flickers:
// replace this
.scaleEffect(self.openMenu ? 0.5 : 1, anchor: UnitPoint(x: 1.5, y: 0.5))
// with this:
.offset(x: self.openMenu ? 300 : 0)