TabView with PageTabViewStyle on tvOS navigationlink or buttons not working - swiftui

Neither navigation or Button's actions working in the pages of the TabView with PageTabViewStyle. Anybody has any ideas or workarounds? Repro code:
var body: some View {
VStack {
TabView(selection: $selection) {
Button(action: {
print("First selected")
}){
Text("Fist")
}
.tag(0)
.buttonStyle(PlainButtonStyle()
Button(action: {
print("Second selected")
}){
Text("Second").tag(1)
}
.tag(1)
Button(action: {
print("Third selected")
}){
Text("Third")
}
.tag(2)
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .always))
.frame(width: 900, height: 400)
.background(Color.blue)
}
}

Button action is working in your shared code but the issue is with the tappable area of Button, which is very less.
Hence, you are unable to sense the button action.
Increase the Button tappable area like this :
Text("Fist")
.frame(width: 200, height: 200, alignment: .center)
.background(Color.red)

Related

SwiftUI - closing modal by swipe is breaking view constraints

I have an issue in SwiftUI with modals combined with custom backgrounds.
If I move the app into the background when a modal is open (e.g. home button on the simulator), then returning the app back to the foreground and closing the modal via swipe, the main screen constraints are broken.
The rendering is correct but the click responding constraints are off.
See screenshots about the constraints before moving the app to the background and after moving it back to the foreground:
Here is the code to reproduce the issue.
struct ContentView: View {
#State var modal = false
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
Spacer()
Button{ modal = true } label: {
Text("Show modal")
.contentShape(Rectangle())
}
Spacer()
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
.background(
Color.yellow.ignoresSafeArea(.all)
)
.sheet(isPresented: $modal, content: {
Text("modal")
})
}
}
Am I applying any of the modifiers incorrectly or this is an iOS bug?
I have tried to apply the modifiers in a different order but it did not help.
I suppose it's the .contentShape inside Button. The following works for me:
struct ContentView: View {
#State var modal = false
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
Spacer()
Button{ modal = true } label: {
Text("Show modal")
// .contentShape(Rectangle())
}
Spacer()
}
.frame(maxWidth: .infinity) // reduce to minimum
.background(
Color.yellow.ignoresSafeArea(.all)
)
.sheet(isPresented: $modal, content: {
Text("modal")
})
}
}

How to center a text in the second row with respect to an image in the row below in SwiftUI?

In the screenshot below, the purple image is not aligned horizontally with the globe symbol. I'm trying to center the navigation title with respect to the logo above it which I can totally do with a VStack. However I don't know how to align the logo itself with the navigation trailing item (globe in the screenshot). Any tips? ideas? tutorials? thank you!
struct ContentView: View {
var body: some View {
NavigationView {
Text("Hello")
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button {} label: {Image(systemName: "globe")}
}
ToolbarItemGroup(placement: .principal) {
VStack {
Image("image")
.resizable()
.frame(width: 64.0, height: 24.0)
Text("Navigation Title")
}
}
}
}
.navigationBarTitleDisplayMode(.inline)
}
}
Just do same for leading toolbar item (because items are independent and one alignment does not affect other - only size of bar)
Tested with Xcode 13.4 / iOS 15.5
*borders are for better visibility
Text("Hello")
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
VStack(alignment: .leading) {
Button {} label: {Image(systemName: "globe")}
.frame(height: 24.0)
Text("X").foregroundColor(.clear)
}.border(.red)
}
ToolbarItemGroup(placement: .principal) {
VStack {
Image("picture")
.resizable()
.frame(width: 64.0, height: 24.0)
Text("Navigation Title")
}.border(.green)
}
}

How to increase the size of a Button in SwiftUI? (Multiplatform project)

I am trying to increase the size oaf a Button in SwiftUI, Xcode 12.5 in a Multiplatform project:
Button("Click me") {
// Perform action here
}
.frame(width: 100, height: 100)
.background(Color.yellow)
.buttonStyle(BorderlessButtonStyle())
After checking the API I found that I can style the button but I can not figure out how to make the click box larger. So that the entire yellow frame receives the click action not just the label.
Edit:
The The tap area problem is explained well here: https://alejandromp.com/blog/playing-with-swiftui-buttons/
But the solution there to change add an element to the button and change the size of that does only work in an iOS project. In a Multiplatform project the frame of the button has the wrong size:
Button(action: {}, label: {
Text("Click me")
.frame(width: 100, height: 100)
.background(Color.yellow)
})
Here is a possible solution
For iOS
Button(action: {
//add actions at here
}) {
VStack {
Text("Name")
}.frame(width: 100, height: 100)
.background(Color.yellow)
.cornerRadius(20)
}
For macOS (macOS version works well for iOS version too)
struct ContentView: View {
var body: some View {
VStack{
Button(action: {
//add actions at here
}) {
VStack {
Text("Button Name")
}.frame(width: 100, height: 100)
.background(Color.yellow)
.cornerRadius(20)
}.buttonStyle(CustomButtonStyle())
}
}
}
struct CustomButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.foregroundColor(Color.blue)
.cornerRadius(10.0)
.padding()
}
}
I have found this solution where adding contentShape seems to do the trick:
Button(action: doSomething) {
Text("Click me")
.frame(width: 100, height: 100)
.contentShape(Rectangle())
}
.background(Color.yellow)
.buttonStyle(PlainButtonStyle())
The button cannot recognize the modifiers on that place. The solution would be:
Button(action: {}, label: {
Text("Click me")
.frame(width: 100, height: 100)
.background(Color.yellow)
})

Is it possible to replace the default back button and sidebar icon in iPad's Navigation Bar using NavigationView in SwiftUI?

I'm trying to make an iOS app that uses SwiftUI's NavigationView to build a side menu.
On iPhone it works perfectly, but on iPad I cannot get Rid of the Sidebar button and the back button text and icon. I would like to replace those buttons with the three horizontal lines icon named line.horizontal.3
Landscape screenshot with side menu icon I'd like to replace with three lines icon
Portrait screenshot with back button (woth icon and text) I'd like to replace with three lines icon
The code I'm using is the following:
import SwiftUI
struct ContentView_iPad: View {
#State var showMenu: Bool = false
var body: some View {
NavigationView{
MenuView()
iPad_menu()
.navigationBarTitle("Side Menu", displayMode: .inline)
.navigationBarItems(leading:
(Button(action: {
withAnimation{
self.showMenu.toggle()
}
}){
Image(systemName: "line.horizontal.3").imageScale(.large)
}
))
.navigationViewStyle(StackNavigationViewStyle())
}
}
}
The MainView:
import SwiftUI
struct iPad_menu: View {
var body: some View {
EmptyView()
.background(Color.black)
}
}
The MenuView:
import SwiftUI
struct MenuView: View {
var body: some View {
VStack(alignment: .leading) {
HStack {
Image(systemName: "person")
.foregroundColor(.gray)
.imageScale(.large)
Text("Profile")
.foregroundColor(.gray)
.font(.headline)
}
.padding(.top, 100)
HStack {
Image(systemName: "envelope")
.foregroundColor(.gray)
.imageScale(.large)
Text("Messages")
.foregroundColor(.gray)
.font(.headline)
}
.padding(.top, 30)
HStack {
Image(systemName: "gear")
.foregroundColor(.gray)
.imageScale(.large)
Text("Settings")
.foregroundColor(.gray)
.font(.headline)
}
.padding(.top, 30)
}
.padding()
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color(red: 32/255, green: 32/255, blue: 32/255))
.edgesIgnoringSafeArea(.all)
}
}

Button appears on top but not pressable

public struct Frontside: View
{
#Binding public var kanatext: String
public var body: some View
{
ZStack{
RoundedRectangle(cornerRadius: 25, style: .continuous)
.foregroundColor(Color.red)
.frame(width: 160, height: 160)
.zIndex(0)
Text(self.kanatext)
.font(.title)
.fontWeight(.black)
.padding(50)
.zIndex(1)
VStack {
Spacer()
HStack {
Button(action: {
print("button pressed")
}) {
Image(systemName: "xmark.circle")
.font(.title)
}
.mask(Circle())
.opacity(0.4)
Button(action: {
print("button pressed")
}) {
Image(systemName: "checkmark.circle")
.font(.title)
}
.mask(Circle())
.opacity(0.4)
}
}
.zIndex(2)
}
}
}
In the above code snippet, I have used a Zstack to layer different parts of a flash card, a background, the text, and then correct/incorrect buttons. The uppermost layer are the buttons, which appear correctly, but for some reason they are not actually pressable.
Have you tried using onTapGesture? It might have to do with the fact that you're using a ZStack.
Try something like:
Image(systemName: "checkmark.circle")
.font(.title)
.onTapGesture {
print("button pressed")
}
In this case there would be no needed to wrap the Image in a Button.
If this doesn't work add onTapGesture to your VStack and have it be empty.