I am not sure why, but VStack won't center images or text all of a sudden. I have tried to use the VStack(alignment:.center) but with no success.
struct ContentView: View {
var body: some View {
NavigationView {
GeometryReader { geo in
Group{
VStack() {
Image(systemName: "car.fill")
}
}
}
}
}
}
My understanding is that this should center. At least all the documents say it should center.
It is centred in VStack but VStack is not centred in GeometryReader. You can do the following...
GeometryReader { geo in
VStack {
Image(systemName: "car.fill")
}
.frame(width: geo.size.width, height: geo.size.height)
}
Just use a HStack to center the VStack.
struct ContentView: View {
var body: some View {
NavigationView {
GeometryReader { geo in
Group{
HStack {
Spacer()
VStack() {
Image(systemName: "car.fill")
}
Spacer()
}
}
}
}
}
}
or
struct ContentView: View {
var body: some View {
NavigationView {
GeometryReader { geo in
Group{
VStack() {
HStack {
Spacer()
Image(systemName: "car.fill")
Spacer()
}
}
}
}
}
}
}
Related
This is my code:
struct Account: View {
var body: some View {
VStack {
ScrollView {
HStack {
Text("Account")
.font(.largeTitle)
.fontWeight(.bold)
Spacer(minLength: 0)
}
.padding()
.background(Color.indigo)
VStack {
Text("Doe, John Jack")
.font(.title)
Divider()
.foregroundColor(Color.indigo)
HStack {
Text("")
}
}
Spacer(minLength: 0)
VStack {
Button(action: {
}) {
Text("Log Out")
.foregroundColor(.red)
.fontWeight(.bold)
}
}
}
}
}
}
If you run the code above, you will see that the indigo doesn't go behind the time and battery precentage. How can I make it do that?
Try like this:
struct Account: View {
var body: some View {
VStack {
ScrollView {
HStack {
Text("Account")
.font(.largeTitle)
.fontWeight(.bold)
Spacer(minLength: 0)
}
.padding()
.background(Color.indigo)
VStack {
Text("Doe, John Jack")
.font(.title)
Divider()
.foregroundColor(Color.indigo)
HStack {
Text("")
}
}
Spacer(minLength: 0)
VStack {
Button(action: {
}) {
Text("Log Out")
.foregroundColor(.red)
.fontWeight(.bold)
}
}
}.padding(.top, 66)
}
.background(Color.indigo)
.edgesIgnoringSafeArea(.all)
}
}
You would also have to add some top padding to the ScrollView since ignoring safe area is going to push all your views to the margins
You should ignore the top safe area for this:
.ignoresSafeArea(.container, edges: .top)
Full working example
struct ContentView: View {
var body: some View {
Color
.indigo
.ignoresSafeArea(.container, edges: .top)
}
}
I hide the navigation bar and provide a customized navigation bar.
But my list appears below the navigation bar.
I want the list to appear below the navigation bar when scrolling.
My desired effect:
Actual effect: Blocked 0
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
TabView {
FirstView()
.tabItem {
Image(systemName: "folder.fill")
Text("Home")
}
SecondView()
.tabItem {
Image(systemName: "folder.fill")
Text("SecondView")
}
}
.navigationBarTitleDisplayMode(.inline)
}
}
}
struct FirstView: View {
var body: some View {
ZStack(alignment: .top) {
List {
ForEach(0..<40, id: \.self) { index in
Text("cell view \(index)")
}
}
.listStyle(.inset)
HStack {
Text("首页")
}
.frame(maxWidth: .infinity)
.frame(height: 44)
.background(.bar)
}
.navigationBarTitleDisplayMode(.inline)
//.ignoresSafeArea(edges: .)
}
}
struct SecondView: View {
var body: some View {
List {
ForEach(0..<40, id: \.self) { index in
Text("FirstView2")
}
}
.listStyle(.inset)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Please do not add padding to the List. This is a security zone problem.
Edit: scrolling under the header
For a glass effect under the header:
You can add a "dummy" element that will push the list one row down. So the the header will cover the dummy element and the whole list will be visible.
struct FirstView: View {
var body: some View {
ZStack(alignment: .top) {
List {
// Dummy Text
Text("")
ForEach(0..<40, id: \.self) { index in
Text("cell view \(index)")
}
}
.listStyle(.inset)
HStack {
Text("首页")
}
.frame(maxWidth: .infinity)
.frame(height: 44)
.background(.bar)
.opacity(0.7)
}
.navigationBarTitleDisplayMode(.inline)
//.ignoresSafeArea(edges: .)
}
}
Original answer
Your FirstView is using a ZStack, which tells exactly the compiler to show one view on top of (covering) the other. Use a VStack, that should solve your issue.
struct FirstView: View {
var body: some View {
VStack {
HStack {
Text("首页")
}
.frame(maxWidth: .infinity)
.frame(height: 44)
.background(.bar)
List {
ForEach(0..<40, id: \.self) { index in
Text("cell view \(index)")
}
}
.listStyle(.inset)
}
.navigationBarTitleDisplayMode(.inline)
//.ignoresSafeArea(edges: .)
}
}
I am writing a simple watchOS app using SwiftUI but I am having issues to proper layout it.
This is the code:
struct ContentView: View {
var body: some View {
VStack(spacing: 0) {
HeaderView()
NavigationView {
ScrollView {
NavigationLink(destination: View1()) {
Text("View 1")
}
NavigationLink(destination: View2()) {
Text("View 2")
}
NavigationLink(destination: View2()) {
Text("View 3")
}
NavigationLink(destination: View2()) {
Text("View 4")
}
}
}
.navigationBarTitleDisplayMode(.inline)
}
}
}
struct HeaderView: View {
var body: some View {
VStack() {
Text("Header")
}
.frame(maxWidth: .infinity)
.background(Color.red)
}
}
struct View2: View {
var body: some View {
VStack {
Text("View 2 Content")
}
.navigationTitle("View 2")
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button("+") {
}
}
}
}
}
Issues:
I cannot rid of this unused space
No matter what the "+" button shows up below the toolbar. I would like to have it in the shown position
Here is my code
struct ContentView: View {
#State var showingPopover = false
var body: some View {
VStack {
Spacer()
Text("Hello World")
Spacer()
HStack {
Spacer()
Button {
self.showingPopover.toggle()
} label: {
Image(systemName: "plus.circle")
}
.popover(isPresented: $showingPopover) {
List(0..<100) { Text("\($0)") }
}.padding(30)
}
}
}
}
This should produce a really nice popover coming from the plus button. But all I get is a really squashed down popover.
Any idea what I am missing here? Is there a way to tell the popover to expand more (without specifying a size)?
You may use a ScrollView and ForEach instead of a List:
struct ContentView: View {
#State var showingPopover = false
var body: some View {
VStack {
Spacer()
Text("Hello World")
Spacer()
HStack {
Spacer()
Button(action: {
self.showingPopover.toggle()
}) {
Image(systemName: "plus.circle")
}
.padding(30)
}
}
// can be attached to the button as well (as in the question)
.popover(isPresented: $showingPopover,
attachmentAnchor: .point(.bottomTrailing),
arrowEdge: .bottom) {
ScrollView(.vertical, showsIndicators: false) {
ForEach(0 ..< 100) {
Text("\($0)")
}
}
}
}
}
You can provide a custom frame for the List. Also, don't forget to embed List inside a ScrollView if you want it to scroll.
ScrollView {
List(0..<100) {
Text("\($0)")
}
.frame(width: 100, height: 250)
}
How can I make this arrow on the centre of the list?
struct ProductsList : View {
var body: some View {
VStack {
List {
Image(systemName: "shift")
}
}
}
}
You may just wanna use some Spacers.
struct ProductList : View {
var body: some View {
VStack {
List {
HStack {
Spacer()
Image(systemName: "shift")
Spacer()
}
}
}
}
}
I would suggest to use ViewModifier:
struct CenterModifier: ViewModifier {
func body(content: Content) -> some View {
HStack {
Spacer()
content
Spacer()
}
}
}
so that in your list, if you have more different type of UI elements its more convenient way to do so:
struct ExampleList: View {
var body: some View {
List {
Image(systemName: "shift").modifier(CenterModifier())
SomeOtherView().modifier(CenterModifier())
}
}
}
Try this:
var body: some View {
List {
GeometryReader { geometry in
VStack(alignment: .center) {
Image(systemName: "shift")
}.frame(width: geometry.size.width)
}
}
}