As the picture shows, I want the button to be in the bottom right corner.
https://i.imgur.com/GiVor8a.png
var body: some View {
ZStack {
HStack {
Color.black
}
Button(action: {}) {
HStack {
Image(systemName: "rectangle.grid.1x2.fill")
}
.padding()
.background(Color.yellow)
.mask(Circle())
}.frame(width: 60, height: 60)
.border(Color.red, width: 1)
}
}
You can use Spacer() for that,
Here is Your Code :
ZStack {
HStack {
Color.black
}
VStack(alignment:.trailing) {
Spacer()
HStack {
Spacer()
Button(action: {}) {
HStack {
Image(systemName: "rectangle.grid.1x2.fill")
}
.padding()
.background(Color.yellow)
.mask(Circle())
}.frame(width: 60, height: 60)
.border(Color.red, width: 1)
}
}
}
Related
I wanted to make a RoundedRectangle that shows all the information and under it, there's a list of data.
The goal was, to make it look like a card, but when I change the background, it leaves a weird white gap, where it doesn't change the color. I already tried to change the background color, foreground color, accent color and everything I know for every single layer but I can't find the problem...
I made the RoundedRectangle .background green in this case, to make it more obvious.
Picture of the app, arrows are edited!
```var body: some View {
NavigationView {
VStack(alignment: .center) {
ZStack {
RoundedRectangle(cornerRadius: 25)
.padding()
.foregroundColor(.white)
.background(Color.green)
.frame(width: nil, height: 250)
VStack {
Text("Verfügbar")
.foregroundColor(.gray)
.italic()
.font(.title2)
Text("\(totalMoneyToday(), specifier: "%.2f")€")
.foregroundColor(.blue)
.bold()
.font(.largeTitle)
HStack {
Spacer()
VStack(alignment: .leading) {
Text("Einkommen")
.foregroundColor(.gray)
.italic()
HStack {
Label("", systemImage: "arrow.up.circle")
.foregroundColor(.green)
Text("\(posMoney(), specifier: "%.2f")€").bold()
}
}
Spacer()
VStack(alignment: .trailing) {
Text("Ausgaben")
.foregroundColor(.gray)
.italic()
HStack {
Label("", systemImage: "arrow.down.circle")
.foregroundColor(.red)
Text("\(negMoney(), specifier: "%.2f")€").bold()
}
}
Spacer()
}
.padding(5)
}
}.background(Color.red)
List {
ForEach(money) { money in
NavigationLink(destination: EditMoneyView(money: money)) {
HStack {
VStack(alignment: .leading, spacing: 6) {
Text(money.name!)
.bold()
Text("\(money.amount, specifier: "%.2f")") + Text("€")
}
Spacer()
Text("\(money.date!, style: .date)")
.foregroundColor(.gray)
.italic()
}
}
}
.onDelete(perform: deleteMoney)
}
}
.navigationBarTitle("Financist", displayMode: .inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
showingAddView.toggle()
} label: {
Label("Hinzufügen", systemImage: "plus.circle")
}
}
}
.sheet(isPresented: $showingAddView) {
AddMoneyView()
}
}
}```
Thank you so much guys!
I think it is just default spacing, make it zero
NavigationView {
VStack(alignment: .center, spacing: 0) { << here !!
It's your ZStack background.
var body: some View {
NavigationView {
VStack(alignment: .center) {
ZStack {
RoundedRectangle(cornerRadius: 25)
.padding()
.foregroundColor(.white)
.background(Color.green)
.frame(width: nil, height: 250)
VStack {
Text("Verfügbar")
.foregroundColor(.gray)
.italic()
.font(.title2)
Text("Money")
.foregroundColor(.blue)
.bold()
.font(.largeTitle)
HStack {
Spacer()
VStack(alignment: .leading) {
Text("Einkommen")
.foregroundColor(.gray)
.italic()
HStack {
Label("", systemImage: "arrow.up.circle")
.foregroundColor(.green)
Text("money").bold()
}
}
Spacer()
VStack(alignment: .trailing) {
Text("Ausgaben")
.foregroundColor(.gray)
.italic()
HStack {
Label("", systemImage: "arrow.down.circle")
.foregroundColor(.red)
Text("money").bold()
}
}
Spacer()
}
.padding(5)
}
}.background(Color.red)
List {
// ForEach(money) { money in
// NavigationLink(destination: EditMoneyView(money: money)) {
// HStack {
// VStack(alignment: .leading, spacing: 6) {
// Text(money.name!)
// .bold()
//
// Text("\(money.amount, specifier: "%.2f")") + Text("€")
// }
// Spacer()
// Text("\(money.date!, style: .date)")
// .foregroundColor(.gray)
// .italic()
// }
// }
// }
// .onDelete(perform: deleteMoney)
}
}
.navigationBarTitle("Financist", displayMode: .inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
// showingAddView.toggle()
print("DEBUG: Button")
} label: {
Label("Hinzufügen", systemImage: "plus.circle")
}
}
}
.background(.red) // added this
// .sheet(isPresented: $showingAddView) {
// AddMoneyView()
// }
}
}
I don't really follow why the following button:
Button { } label: {
Image(systemName: "globe")
.resizable()
.scaledToFill()
}
.frame(width: size, height: size)
.border(.yellow)
is behaving differently in the body and in the NavigationView?
Why isn't the one in the NavigationView filling the entire frame?
struct ContentView: View {
let size = 45.0
let fontSize = 17.0
var body: some View {
NavigationView {
Button { } label: {
Image(systemName: "globe")
.resizable()
.scaledToFill()
}
.frame(width: size, height: size)
.border(.yellow)
.toolbar {
HStack(alignment: .top) {
Button { } label: {
Image(systemName: "globe")
.resizable()
.scaledToFill()
}
.frame(width: size, height: size)
.border(.red)
// Image and Title
VStack {
Image("nemo")
.resizable()
.scaledToFit()
.frame(height: size)
Text("Navigation Title")
.font(.system(size: fontSize))
.bold()
}.border(.green)
}
//.frame(maxWidth: .infinity)
}
}
}
}
This is a design of default button in toolbar, instead we can use custom, like
Button { print(">> action here")} label: {
Image(systemName: "globe")
.resizable()
.scaledToFill()
}
.buttonStyle(MyTabbarButtonStyle())
.frame(width: size, height: size)
.border(.red)
// and style (tune colours as you want)
struct MyTabbarButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.foregroundColor(configuration.isPressed ? .gray : .blue)
}
}
I want to make a segment tab page in SwiftUI such as bellow.
My code is as bellow:
struct ContentView: View {
#State var index = 0
#State private var offset: CGFloat = 0
var body: some View {
VStack(spacing: 0) {
HStack() {
Button("tab1") {
self.index = 0
}
Button("tab2") {
self.index = 1
}
}
ScrollView(.horizontal, showsIndicators: false) {
HStack(alignment: .center, spacing: 0) {
VStack() {
List {
VStack {
HStack() {
Text("tab1 line1")
Spacer()
}
.frame(height: 126)
.contentShape(Rectangle())
.onTapGesture {
print("click tab1 line1")
}
}
VStack {
HStack() {
Text("tab1 line2")
Spacer()
}
.frame(height: 126)
.contentShape(Rectangle())
.onTapGesture {
print("click tab1 line2")
}
}
}
.frame(width: UIScreen.main.bounds.size.width, height: 300)
}
.frame(width: UIScreen.main.bounds.size.width, height: 300)
.cornerRadius(30)
VStack() {
List {
VStack {
HStack() {
Text("tab2 line1")
Spacer()
}
.frame(width: UIScreen.main.bounds.size.width, height: 126)
.contentShape(Rectangle())
.onTapGesture {
print("click tab2 line1")
}
}
VStack {
HStack() {
Text("tab2 line2")
Spacer()
}
.frame(width: UIScreen.main.bounds.size.width, height: 126)
.contentShape(Rectangle())
.onTapGesture {
print("click tab2 line2")
}
}
}
.frame(width: UIScreen.main.bounds.size.width, height: 300)
.onAppear() {
print("load")
}
}
.frame(width: UIScreen.main.bounds.size.width, height: 300)
.cornerRadius(30)
}
}
.content
.offset(x: self.getOffset())
.animation(.spring())
.frame(width: UIScreen.main.bounds.size.width, alignment: .leading)
}
.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
.background(Color.gray)
}
private func getOffset() -> CGFloat {
let offset = CGFloat(self.index) * (-UIScreen.main.bounds.size.width)
return offset
}
}
Everything works well expect the onTapGesture in tab2. When tap the line of "tab1",the onTapGesture works well to print "click tab1 line1" or "click tab1 line2".
After click button "tab2", the page will scroll to tab2 page. When click the line of list "tab2", onTapGesture not works.
I try a day, and found two methods to make it works:
After scroll to page "tab2", Scroll up or down the tab2 list, the onTapGesture will works to print "click tab2 line1" and "click tab2 line2".
remove the code .cornerRadius(30), the click in tab2 page will also works.
I just want to keep the radius of list. How to fix this incredible bug?
The problem is here:
.content
.offset(x: self.getOffset())
This duplicates the scrollview's content and offsets it to the right. As a result, what you are tapping is the duplicated content, which probably affects the tap gesture.
Instead, use ScrollViewReader to scroll the ScrollView, and remove your getOffset code.
struct ContentView: View {
#State var index = 0
#State private var offset: CGFloat = 0
var body: some View {
VStack(spacing: 0) {
HStack() {
Button("tab1") {
self.index = 0
}
Button("tab2") {
self.index = 1
}
}
ScrollView(.horizontal, showsIndicators: false) {
ScrollViewReader { proxy in
HStack(alignment: .center, spacing: 0) {
VStack() {
List {
VStack {
HStack() {
Text("tab1 line1")
Spacer()
}
.frame(height: 126)
.contentShape(Rectangle())
.onTapGesture {
print("click tab1 line1")
}
}
VStack {
HStack() {
Text("tab1 line2")
Spacer()
}
.frame(height: 126)
.contentShape(Rectangle())
.onTapGesture {
print("click tab1 line2")
}
}
}
.frame(width: UIScreen.main.bounds.size.width, height: 300)
}
.frame(width: UIScreen.main.bounds.size.width, height: 300)
.cornerRadius(30)
.id(0) /// set id here
VStack() {
List {
VStack {
HStack() {
Text("tab2 line1")
Spacer()
}
.frame(width: UIScreen.main.bounds.size.width, height: 126)
.contentShape(Rectangle())
.onTapGesture {
print("click tab2 line1")
}
}
VStack {
HStack() {
Text("tab2 line2")
Spacer()
}
.frame(width: UIScreen.main.bounds.size.width, height: 126)
.contentShape(Rectangle())
.onTapGesture {
print("click tab2 line2")
}
}
}
.frame(width: UIScreen.main.bounds.size.width, height: 300)
.onAppear() {
print("load")
}
}
.frame(width: UIScreen.main.bounds.size.width, height: 300)
.cornerRadius(30)
.id(1) /// also set id here
}
.onChange(of: index) { _ in /// scroll the ScrollView
withAnimation(.spring()) {
proxy.scrollTo(index)
}
}
}
}
.frame(width: UIScreen.main.bounds.size.width, alignment: .leading)
}
.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
.background(Color.gray)
}
}
I'm currently working on trying to implement a custom dropdown menu in SwiftUI that displays a grid of buttons (1-16) and allows you to select one of them. I am using an overlay to display the dropdown below the corresponding button, and it seems to be functioning properly except it's displaying the dropdown below all of the other elements in the view. I found another post here regarding this issue and they used a ZStack to solve it, but I haven't been able to get the same success. Does anyone have any ideas on how to fix this? Here's my code:
struct ContentView: View {
#State var showDropdown = false
#State var selected = 0
var body: some View {
ZStack {
HStack(spacing: 30) {
VStack(alignment: .leading, spacing: 10) {
HStack {
Text("Some Text")
.lineLimit(1)
Spacer()
Button(action: { showDropdown.toggle() }) {
Text(selected == 0 ? "Omni" : String(selected))
.frame(width: 80, height: 36)
}
.zIndex(1)
.overlay(
VStack(spacing: 0) {
if self.showDropdown {
Spacer(minLength: 26)
DropdownMenu(selection: self.$selected)
} else {
EmptyView()
}
}, alignment: .topLeading
)
}
HStack {
Text("Some Text")
.lineLimit(1)
Spacer()
Button(action: { }) {
Text("Omni")
.frame(width: 80, height: 36)
}
}
}
VStack(alignment: .leading, spacing: 10) {
HStack {
Text("Some Text")
.lineLimit(1)
Spacer()
Button(action: { }) {
Text("Omni")
.frame(width: 80, height: 36)
}
}
HStack {
Text("Some Text")
.lineLimit(1)
Spacer()
Button(action: { }) {
Text("Omni")
.frame(width: 80, height: 36)
}
}
}
}
}
.padding()
.frame(maxHeight: .infinity)
.buttonStyle(PlainButtonStyle())
}
}
and here are some images of the results:
Before Press
After Press
Thank you in advance!
The .zIndex works for view in same container, so you need something like the following (or make custom flat layout container with all such buttons at same level, then rise clicked button atop).
VStack(alignment: .leading, spacing: 10) {
HStack {
Text("Some Text")
.lineLimit(1)
Spacer()
Button(action: { showDropdown.toggle() }) {
Text(selected == 0 ? "Omni" : String(selected))
.frame(width: 80, height: 36)
}
.zIndex(1)
.overlay(
VStack(spacing: 0) {
if self.showDropdown {
Spacer(minLength: 26)
DropdownMenu(selection: self.$selected)
}
}, alignment: .topLeading
)
}.zIndex(showDropdown ? 1 : 0) // << this !!
HStack {
Text("Some Text")
.lineLimit(1)
Spacer()
Button(action: { }) {
Text("Omni")
.frame(width: 80, height: 36)
}
}
}.zIndex(showDropdown ? 1 : 0) // << and this !!
I made a card style List row which work fine. The issue is that the list row background color remains. I can make it disappear by setting it to systemGray6 but it's not very adaptive for dark mode and there is very likely a better way of doing this.
Card View:
var body: some View {
ZStack {
Rectangle().fill(Color.white)
.cornerRadius(10).shadow(color: .gray, radius: 4)
.frame(width: UIScreen.main.bounds.width - 40)
HStack {
Image(uiImage: (UIImage(data: myVideo.thumbnailImage!) ?? UIImage(systemName: "photo"))!)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 100, height: 100)
VStack {
Text(myVideo.title!)
.multilineTextAlignment(.center)
.font(.body)
.padding(.bottom, 10)
.frame(maxWidth: UIScreen.main.bounds.width - 40, maxHeight: .infinity, alignment: .center)
Text(myVideo.youtuber!)
.font(.subheadline)
}
}
.padding(5)
}
}
List View:
var body: some View {
NavigationView {
if myVideos.isEmpty {
Text("You have not added videos yet!")
font(.subheadline)
} else {
List() {
Section(header: Text("Not Watched")) {
ForEach(myVideos) { video in
if !video.watched {
NavigationLink(destination: MyVideoView(myVideo: video)) {
MyListRowView(myVideo: video)
}
}
}
.onDelete(perform: removeItems)
}
Section(header: Text("Watched")) {
ForEach(myVideos) { video in
if video.watched {
NavigationLink(destination: MyVideoView(myVideo: video)) {
MyListRowView(myVideo: video)
}
}
}
.onDelete(perform: removeItems)
}
.listRowBackground(Color(UIColor.systemGray6))
}
.navigationBarTitle("Videos")
.listStyle(GroupedListStyle())
}
}
}
Image: (Intended behaviour in "WATCHED" and Incorrect behaviour in "NOT WATCHED"