Strange picker view hide animation in SwiftUI form - swift

I am trying to show and hide a picker view with an animation. The code for this is pretty simple and although the code works for other views, I can't get it to work with a picker view. Hiding the picker view results in a very odd animation as you can see in the gif below.
When I delete the first or last row in the list, the animation seems correct. Replacing Form {} with a normal List {} also solves the issue. So it only happens in the "inset grouped style".
Issue:
Code:
import SwiftUI
struct ContentView: View {
static let options = ["One", "Two", "Three"]
#State private var showPicker = false
#State private var selectedOption = 0
var body: some View {
Form {
Text("First row") // Removing this row or the last row solves the issue
Button("Show Picker") {
withAnimation {
showPicker.toggle()
}
}
if showPicker {
Picker("Picker", selection: $selectedOption) {
ForEach(0 ..< ContentView.options.count) {
Text(ContentView.options[$0])
}
}.pickerStyle(InlinePickerStyle())
}
Text("Third row")
Text("Last row") // Removing this row or the first row solves the issue
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Does anyone know how to solve this issue? I guess it's a SwiftUI bug so a workaround would be very helpful as well.

Related

Swiftui Tabview causes issues with Textfield

In SwiftUI, whenever I have a TextField inside a TabView, when I use a bluetooth barcode scanner, the Textfield never gets the correct value from the scanner, it always skips numbers. Sometimes it skips 50% of the barcode, sometimes just 1 or 2 numbers. This happens only when the TextField is inside a Tabview.
I never thought I would get stuck on something like this to be honest, maybe I am missing something very simple?
Here is a testcode:
import SwiftUI
struct Testview: View {
#State private var searchProductText = ""
#FocusState var productFieldIsFocused: Bool
var body: some View {
TabView{
HStack {
TextField("", text: $searchProductText)
.focused($productFieldIsFocused)
.opacity(0)
.onSubmit {
print(searchProductText)
searchProductText = ""
productFieldIsFocused = true
}
}.onAppear{
productFieldIsFocused = true
}
}
}
}
struct Testview_Previews: PreviewProvider {
static var previews: some View {
Testview()
}
}

TabView does not change the view

I have created a custom TabView that looks as follows:
and the code:
struct ContentView: View {
#State private var selectedItem: TabItemOption = .market
var body: some View {
ZStack {
VStack {
TabView(selection: $selectedItem){
MarketView().tag(TabItemOption.market.rawValue)
InterestView().tag(TabItemOption.interest.rawValue)
WalletView().tag(TabItemOption.wallet.rawValue)
}.toolbar(.hidden, for: .tabBar)
}
VStack {
Spacer()
TabBar(tappedItem: $selectedItem)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
For example, when I click on the second TabBarItem the view does not get changed. It always shows the MARKET view with Hello Market text in the middle of the screen.
However, the tag modifier is set to identify the view uniquely.
I have also checked if the variable selectedItem gets changed every time when different TabBarItem gets pressed and it changes the value properly corresponding what get pressed.
What am I doing wrong?

Sheet Modal does not present whole View in SwiftUI

I am pretty new to SwiftUI programming and ran into the following problem that I cannot find an answer to.
I want to open a sheet modal from my Main View and want to present a simple View with an Rect on it (for testing purposes).
.sheet(isPresented: $api.showDrawing) {
DrawingViewView()
}
My DrawingViewView looks like:
struct DrawingViewView: View {
var body: some View {
Rectangle()
.fill(Color.red)
.frame(width: 1500, height: 1000)
}
}
No matter how big I make the Rect it is never shown bigger than:
Is there a way to make the sheet bigger in width?
EDIT:
I also thought of using a fullScreenCover, but if I open a PKCanvasView in a fullScreenCover pencilKit is acting weird. The lines I draw do not correspond with the pencilInput
EDIT: Apperently the problem is the horizontal orientation. If I turn my iPad vertical I have no problems at all!
Thanks a lot!
Jakob
I think this is the easiest way to do it.
import SwiftUI
struct FullScreenModalView: View {
#Environment(\.presentationMode) var presentationMode
var body: some View {
ZStack {
Color.red.edgesIgnoringSafeArea(.all)
Button("Dismiss Modal") {
presentationMode.wrappedValue.dismiss()
}
}
}
}
struct ContentView: View {
#State private var isPresented = false
var body: some View {
Button("Present!") {
isPresented.toggle()
}
.fullScreenCover(isPresented: $isPresented, content: FullScreenModalView.init)
}
}
struct ex_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Hope is what you expected!

Is it possible to perform an action on NavigationLink tap?

I have a simple View showing a list of 3 items. When the user taps on an item, it navigates to the next view. This works fine. However, I would like to also perform an action (set a variable in a View Model) when a list item is tapped.
Is this possible? Here's the code:
import SwiftUI
struct SportSelectionView: View {
#EnvironmentObject var workoutSession: WorkoutManager
let sports = ["Swim", "Bike", "Run"]
var body: some View {
List(sports, id: \.self) { sport in
NavigationLink(destination: ContentView().environmentObject(workoutSession)) {
Text(sport)
}
}.onAppear() {
// Request HealthKit store authorization.
self.workoutSession.requestAuthorization()
}
}
}
struct DisciplineSelectionView_Previews: PreviewProvider {
static var previews: some View {
SportSelectionView().environmentObject(WorkoutManager())
}
}
The easiest way I've found to get around this issue is to add an .onAppear call to the destination view of the NavigationLink. Technically, the action will happen when the ContentView() appears and not when the NavigationLink is clicked.. but the difference will be milliseconds and probably irrelevant.
NavigationLink(destination:
ContentView()
.environmentObject(workoutSession)
.onAppear {
// add action here
}
)
Here's a solution that is a little different than the onAppear approach. By creating your own Binding for isActive in the NavigationLink, you can introduce a side effect when it's set. I've implemented it here all within the view, but I would probably do this in an ObservableObject if I were really putting it into practice:
struct ContentView: View {
#State var _navLinkActive = false
var navLinkBinding : Binding<Bool> {
Binding<Bool> { () -> Bool in
return _navLinkActive
} set: { (newValue) in
if newValue {
print("Side effect")
}
_navLinkActive = newValue
}
}
var body: some View {
NavigationView {
NavigationLink(
destination: Text("Dest"),
isActive: navLinkBinding,
label: {
Text("Navigate")
})
}
.navigationViewStyle(StackNavigationViewStyle())
}
}

Why does modifying the label of a NavigationLink change which View is displayed in SwiftUI?

I have an #EnvironmentObject called word (of type Word) whose identifier property I'm using for the label of a NavigationLink in SwiftUI. For the DetailView that is linked to the NavigationLink, all I have put is this:
struct DetailView: View {
#EnvironmentObject var word: Word
var body: some View {
VStack {
Text(word.identifier)
Button(action: {
self.word.identifier += "a"
}) {
Text("Click to add an 'a' to Word's identifier")
}
}
}
}
The ContentView that leads to this DetailView looks like this (I've simplified my actual code to isolate the problem).
struct ContentView: View {
#EnvironmentObject var word: Word
var body: some View {
NavigationView {
NavigationLink(destination: DetailView()) {
Text(word.identifier)
}
}
}
}
When I tap the button on the DetailView, I'd expect it to update the DetailView with a new word.identifier that has an extra "a" appended onto it. When I tap it, however, it takes me back to the ContentView, albeit with an updated word.identifier. I can't seem to find a way to stay on my DetailView when the word.identifier being used by the ContentView's NavigationLink is modified. Also, I am running Xcode 11.3.1 and am currently unable to update, so if this is has been patched, please let me know.
Here is workaround solution
struct DetailView: View {
#EnvironmentObject var word: Word
#State private var identifier: String = ""
var body: some View {
VStack {
Text(self.identifier)
Button(action: {
self.identifier += "a"
}) {
Text("Click to add an 'a' to Word's identifier")
}
}
.onAppear {
self.identifier = self.word.identifier
}
.onDisappear {
self.word.identifier = self.identifier
}
}
}
This works as expected on iOS 13.4, assuming Word is something like:
class Word : ObservableObject {
#Published var identifier = "foo"
}