SwiftUI Remove Extra Space between NavigationTitle and TextView - swiftui

Started learning SwiftUI, I want to remove this highlighted space between navigation title and Text inside VStack.

If you were to remove the NavigationView and had your VStack as the top-level view in your body, you'd see much the same layout.
That's because its frame is smaller than the frame available for it (in this case, most of the screen) and by default the smaller internal view gets centered both horizontally and vertically.
To move the text to the top of the screen, you need to ensure that your view will grow in size. The easiest way will be add to add a Spacer to the bottom of the VStack:
VStack(alignment: ...) {
Text("...")
Text("...")
Spacer()
}
Another approach would be to wrap your VStack in a scroll view. This view will automatically expand itself to fill the height, and layout its subviews (your VStack) from the top downwards:
ScrollView {
VStack(alignment: ...) {
Text("...")
Text("...")
}
}
Each approach has upsides and downsides depending on how much other data you expect to also be in the view.
You could also manually adjust the frame of your VStack using the .frame() modifier:
VStack(alignment: ...) {
Text("...")
Text("...")
}
.frame(maxHeight: .infinity, alignment: .top)
This would give you much the same effect as using the spacer. But the spacer version is a better way to go, especially if you're only starting out with SwiftUI layout.

Related

How to overlay view on top of multiple other views in a VStack in SwiftUI

In SwiftUI I currently have a VStack of views, and I'd like to put an overlay over the bottom two views, like this:
VStack {
Spacer()
Group {
centerView
Spacer()
}
.overlay(overlayedView)
}
The goal of the above layout is ensure that centerView is vertically centered, while also ensuring that the overlayedView goes from the top of centerView all the way to the bottom of the VStack.
However, the above code actually results in one instance of overlayedView getting overlayed on top of centerView and another overlayedView getting overlayed on top of the bottom Spacer. But what I want is a single overlayedView spread on top of both centerView and the bottom Spacer.
How can I achieve my desired behavior?
Using Group will add view modifiers to all the subviews of the group, resulting in 2 seperate overlays. To have one common overlay, you can use VStack instead of Group.
VStack {
Spacer()
VStack {
centerView
Spacer()
}
.overlay(overlayedView)
}

Prevent Navigation Bar from collapsing and being sticky when on scroll SwiftUI / UIKit

I would like the NavigationBar (from a SwiftUI NavigationView) to just stay large and scroll out whenever I scroll in a Pages ScrollView. Right now it is always collapsing and showing even on scroll in ".inline"-display mode. So when I try to completely hide it I also hide the large title I'd like to keep.
Is there a way to just let it stay large and just scroll out?
Any solution in SwiftUI or UIKit is appreciated as I can introspect from UIKit.
I especially don't want the NavigationBar to be hidden and rebuild by VStack or HStack as this causes loosing all Navigation Gestures like swiping back to the previous Navigation View and so...
Here is a basic codesnipped to recreate
struct TestTestView: View {
var body: some View {
NavigationView {
ScrollView() {
Color.green
.frame(height: 1000)
}
.navigationTitle("Test")
}
}
}

SwiftUI: Different Widths for Multiline Text Views in Boxes

Here is how two boxes with text are rendering in SwiftUI, but I want them to both be full-width:
Here is my code:
VStack(spacing: 20){
//Help ---
VStack(alignment: .leading, spacing:10){
Text("Help").h2()
Text("Please view our online user guide before contacting us since we answer most questions there.")
.lineLimit(nil) //Make the text wrap
.prefsText()
Button("Online Help"){
openURL(URL(string: "https://avid.pro/help")!)
}.foregroundColor(Color(accentColor))
.buttonStyle(PlainButtonStyle())
.prefsLink()
}.unoBoxRoundPad()
.frame(maxWidth: .infinity)
//Support ---
VStack(alignment: .leading, spacing:10){
Text("Support").h2()
Text("Email us if you need to submit a bug or get specialized help. It may take us a few days to get back to you.")
.lineLimit(nil) //Make the text wrap
.prefsText()
Button("Email Us"){
openURL(URL(string: "mailto:help#avid.pro")!)
}.foregroundColor(Color(accentColor))
.buttonStyle(PlainButtonStyle())
.prefsLink()
}.unoBoxRoundPad()
.frame(maxWidth: .infinity)
}.background(Color.yellow) //For testing
I can't for the life of me figure out why they aren't the same width. .unoBoxRoundPad() is a view modifier that adds these shared styles:
.padding(20)
.background(Color("UnoDark"))
.cornerRadius(7)
If I put .frame(maxWidth: .infinity) on the Text() instead of on the containing VStack, it seems to get a little closer, but then it disregards the containing view's padding():
Any ideas on what I'm doing wrong?
There are two issues at play here:
You've got two modifiers swapped (.frame(...) and .unoBoxRoundPad()); you want the roundedness to apply to the entire stretched thing. By putting .unoBoxRoundPad() first, you're saying "pad this thing" and then "place that rounded thing inside an infinitely-wide box"; you want the reverse: your thing should be placed inside an infinitely-wide box, and it's the infinitely wide box that should have the rounded corners and padding.
You need to specify an alignment: when using that .frame() modifier; when the inner view is placed inside an infinitely-wide box, it's going to default to being centered vertically and horizontally inside it. Based on your screenshots, you probably want to use .topLeading so that the content ("Support", "Help", etc) start in the top-left corner (or top-right in RTL languages).

Make view fall in multiple rows like text in SwiftUI

I have a similar problem to this: SwiftUI HStack with wrap and dynamic height
But I want this tags to aligned in center instead of left aligned. I tried but can't make it work.
You can try VStack with alignment.
VStack(alignment: .center) {
// your views
}
SkillChipView is just rename of TagCloudView.

SwiftUI: Navigation bar of destination view has no background and is not animated on scroll

I'm trying to make navigation view that leads to destination view with scroll view, where navigation title of destination view would animate towards inline display mode or at least scroll behind the nav bar itself.
Basically I'm trying to replicate behavior of standard Music app, specifically when you go from Library to Songs.
There you have source view (Library) with its own title that is animated into inline display mode on scroll. When you tap Songs you also get list with new title (Songs) that also animates into inline display mode on scroll.
So I have main NavigationView with NavigationBarTitle. I move to destinationView with its own NavigationBarTitle and some long list of content. On scroll, NavigationBarTitle of main Navigation view changes to inline display mode, but NavigationBar of destination view behaves very odd: it's basically an overlay with no background and no animation.
And if you remove NavigationBarTitle of destination view all together it only makes things worse. It seems like it adds another transparent NavigationBar with nothing in it.
Also tried to add background to the navigation bar, looked around documentation, but found no solution.
Not sure if I'm doing something very wrong or it's just beta bug of SwiftUI or Xcode.
import UIKit
struct ContentView: View {
var body: some View {
NavigationView{
List(0..<20) { item in
NavigationLink(destination: DetailedView()) {
Text("Next view")
}
}
.navigationBarTitle("Source View")
}
}
}
struct DetailedView: View {
var body: some View {
List(0...25) { number in
Text("This is \(number)'th row")
}
.navigationBarTitle(Text("Destination View"))
// comment out line above to see empty frame of navigation bar
}
}
This is not a full answer to your question, but a temporary workaround: add top or vertical padding to your list on the child view, depending on your preference. This is what I have been doing until there is a better solution.
This will at least make the content scroll under the navigation header with a proper background rendered behind the header. It doesn't have the nice animation to make the title smaller.
struct DetailedView: View {
var body: some View {
List(0...25) { number in
Text("This is \(number)'th row")
}
.padding(.top)
.navigationBarTitle(Text("Destination View"))
}
}
This is fixed in the iOS 13.1 public release (with the App Store release of Xcode 11).
I'm currently on beta 5, and I think this is an ongoing bug with SwiftUI.
I noticed the same issue while doing the SwiftUI Landmarks Tutorials, and you can easily reproduce the issue: https://imgur.com/a/aYgUUH0
For now, to avoid seeing all the content scroll under a transparent navBar, I've converted all of my Navbars to display as inline, since automatic and large experience the issue.
List {
// ...
}
.navigationBarTitle(Text("MyTitle"), displayMode: .inline)