SwiftUI - TabView disable background transparency - swiftui

Is there a way to disable the transparency in TabView for iOS 15? If my List doesn't fill the entire screen the TabView background is transparent, I'm looking to always show the TabView background.

Thanks to #Asperi for pointing me in the correct direction. I found scrollEdgeAppearance in UITabBarAppearance.
#available(iOS 15.0, *)
#NSCopying open var scrollEdgeAppearance: UITabBarAppearance?
Describes the appearance attributes for the tabBar to use when an
observable scroll view is scrolled to the bottom. If not set,
standardAppearance will be used instead.
//#available(iOS 15.0, *)
//#NSCopying open var scrollEdgeAppearance: UITabBarAppearance?
let appearance: UITabBarAppearance = UITabBarAppearance()
init() {
UITabBar.appearance().scrollEdgeAppearance = appearance
}

Related

SwiftUI DragGesture swallowed by ScrollView

I want to register a certain drag gesture on any SwiftUI view, including ScrollViews simultaneously with any other gestures (i.e. without influencing existing gestures). However, when adding a DragGesture on a ScrollView as follows, it seems like the gesture is immediately swallowed by the ScrollView.
ScrollView {
Rectangle()
.frame(width: 500, height: 500)
}
.simultaneousGesture(
DragGesture()
.onChanged { value in
print("changed:", value.translation)
}
.onEnded { value in
print("ended:", value.translation)
}
)
When I drag the Rectangle, this code prints:
changed: (3.0, 16.666671752929688)
for example.
So onChanged is only called once, onEnded is never called.
Is there a way to make DragGestures work with ScrollViews as well?
Note:
I tried to find a workaround with GestureState and the updating(_:) modifier as well, but it didn't work either.

Unable to remove Navigation Bar when TabView is used inside the Navigation View - SwiftUI - iOS 15

SwiftUI View Hierarchy
Navigation View --> VStack --> Custom SearchView --> TabView
In the view, with the hierarchy mentioned above, I'm unable to remove navigation bar. It's visibility is successfully changed with the code mentioned shared below.
#available(iOS 15.0, *)
func iOS15UIBarSpecs(){
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithTransparentBackground()
navBarAppearance.backgroundColor = UIColor.red.withAlphaComponent(0.5)
navBarAppearance.shadowImage = UIImage()
navBarAppearance.shadowImage = nil
navBarAppearance.shadowColor = nil
UINavigationBar.appearance().standardAppearance = navBarAppearance
UINavigationBar.appearance().scrollEdgeAppearance = navBarAppearance
}
The presence of this navigation bar is blocking tap gestures on any view coming behind it.
The same view was working fine in iOS 14 with the following line of code.
.navigationBarHidden(true)
Any help would be much appreciated. Thanks!

SwiftUI 2 / WatchOS7 - Changing NavigationBar button & text color (was tint color now accent color)

I updated my SwiftUI Watch App from Xcode 11 to Xcode 12, using the new Xcode 12 / SwiftUI LifeCycle methodology. Unfortunately in doing that the "tint color" (which defines the color of NavigationBar back button & test) is lost & reverts to the defaults (which is not what I want or had set before in Xcode 11).
Does anyone know how to change the color of the ‘back’ button & text on NavigationBar - using the new lifecycle SwiftUI with Xcode 12 & WatchOS7?
In xcode 11 one could change the ‘tint’ color using inspector on the StoryBoard to do that (for the whole App). But with the new SwiftUI lifecycle in xcode 12, I can’t figure out how this is now set (probably some parameter in ‘init()’ of App?)
I have tried the the below code but it gives the below syntax error (remember this is for WatchOS7):
"Cannot find 'UINavigationBarAppearance' in scope"
#main
struct myApp: App {
init() {
print("App Initializing....")
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
}
#SceneBuilder var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Also tried:
#SceneBuilder var body: some Scene {
WindowGroup {
ContentView().accentColor(.white)
}
But that has no effect (no matter where the .accentColor modifier is placed).
Any help / suggestions?
Thanks!
Gerard
SwiftUI NavigationBar WatchOS7
OK - figured it out from Apple Documentation!
See: https://developer.apple.com/documentation/watchos-apps/setting-the-app-s-accent-color/
and follow instructions for "Update Existing Projects"
NOTE:
The new "AccentColor" color set must be added to the assets in the Frameworks->AppName WatchKit App->Assets.xcassets file. This is the same file where the App's Icon is placed.

SwiftUI animation of a ScrollView

I have two views (VStacks) one on top of the other in a ZStack
The first VStack that is behind the second view is used like a menu. The second view that is on top, is the main application view.
When i click on a button i'm scaling down the main view and move it a bit to the right side of the screen to show the menu.
I have a ScrollView inside the main view every time i scale down or up the main view, the animation doesn't work smoothly the page flickers and it looks ugly. if i remove the ScrollView it works perfectly fine.
I tried to replace the ScrollView with a List but it didn't solve the problem the flickering remains the same.
Is there any way to fix this glitch?
below is a sample code
struct ContentView: View {
var body: some View {
ZStack {
Menu()
VStack {
ScrollView(.vertical, showsIndicators: false) {
VStack(spacing:0) {
Header()
MainAppView()
}
}
TabBar()
}
.scaleEffect(self.openMenu ? 0.5 : 1, anchor: UnitPoint(x: 1.5, y: 0.5))
.animation(.easeInOut(duration: 0.2))
}
}
}
Please click to check animated gif example
What you can try is, to make screenshot of the flickering view and then do the animation with the screenshot which you just add on the real view. After the animation just remove the screenshot. Of course you have to make the screenshot programmatically.
I can't repeat all the behavior, because of lack of code. I think you have this problem, because you're scaling down ScrollView and it recomputes all the content. Try just to make some offset for it, instead of scaling and there should be no flickers:
// replace this
.scaleEffect(self.openMenu ? 0.5 : 1, anchor: UnitPoint(x: 1.5, y: 0.5))
// with this:
.offset(x: self.openMenu ? 300 : 0)

Update UIViewRepresentable size from UIKit in SwiftUI

I'm embedding a view controller with variable-height UITextView inside a parent SwiftUI VStack and the view controller sizes it's frame to the whole screen between viewDidLoad and viewDidLayoutSubviews. The UITextView expands only to the size of the text inside itself and centers itself inside the parent view.
I'm trying to add this view controller in a VStack and have it behave externally like other SwiftUI components do - sized exactly to the content it contains - but it wants to be sized to the whole screen minus the other VStack elements.
I can get the correct size of the UITextView in didLayoutSubviews and pass it upwards to SwiftUI where it can be set properly - but where do I do that?
In the example screenshot below, the orange is the embedded UIView background, the green is the UITextView and the VStack looks like this:
VStack {
HighligherVC()
Text("Tap and drag to highlight")
.foregroundColor(.gray)
.font(.caption)
}
Without being able to see more of your code, it's slightly difficult to say what the best solution would be, but based purely on this part of your question...
I can get the correct size of the UITextView in didLayoutSubviews and pass it upwards to SwiftUI where it can be set properly - but where do I do that?
I would suggest that you pass a binding property to your view controller that can be set to the calculated text view height, meaning that the view that contains your VStack would have a #State property like this:
#State private var textViewHeight: CGFloat = 0
You would then declare a #Binding property on your HighlighterVC and add an initializer like this:
#Binding var textViewHeight: CGFloat
init(textViewHeight: Binding<CGFloat>) {
self._textViewHeight = textViewHeight
}
And then you would set textViewHeight to the calculated height in your didLayoutSubviews and add a .frame modifier to your HighlighterVC like this:
VStack {
HighlighterVC(textViewHeight: self.$textViewHeight)
.frame(height: self.textViewHeight)
Text("Tap and drag to highlight")
.foregroundColor(.gray)
.font(.caption)
}
Like I said at the beginning of my answer, this solution (that I believe would work, but since I can't test it, I'm not 100% certain) is based on your thoughts about what it is that you need. Without seeing more code, it's impossible for me to say if this is the best solution.
Add fixedSize may solve this.
.fixedSize(horizontal: false, vertical: true)