How to manage Tab bar badge count in SwiftUI 2.0? - swiftui

Here I have use SwiftUI 2.0 and manage TabBar badge count. Reference of
https://medium.com/flawless-app-stories/swiftui-tutorial-showing-badge-on-tab-bar-item-d71e4075b67a
In Xcode 12.1 , the badge gets pushed up when the keyboard appears
How to mange this badge count When keyboard appear ?

Try adding .ignoresSafeArea(.keyboard) to your GeometryReader and/or the badge’s containing ZStack.
Your view is resizing to avoid the keyboard, which is the new default in iOS 14. Use the new .ignoresSafeArea(.keyboard) modifier to disable that behavior.

As of SwiftUI 3, you can use the .badge modifier to add a badge to your tab item. This requires iOS 15 or later.
Examples:
struct Tabs_Previews: PreviewProvider {
static var previews: some View {
TabView {
Text("String tab")
.tabItem {
Text("String")
Image(systemName: "text.quote")
}
.badge("hi")
.tag("string")
Text("Int tab")
.tabItem {
Text("Int")
Image(systemName: "number.circle")
}
.badge(123)
.tag("string")
}
}
}
Result:
You can use an Int, a String, a Substring, a LocalizedStringKey, or a Text. In my testing, the badge ignores any styling applied to the Text.

Related

Bring SwiftUI ButtomSheet behind tab bar

I want to use the new iOS 16 Buttom Sheet Feature to create a view like the find my:
Unfortunately the TabView gets hidden behind the Sheet:
My Code:
TabView {
Text("View 1")
.sheet(isPresented: .constant(true)) {
Text("Sheet View Content")
.presentationDetents([.medium, .large])
}
.tabItem {
Label("Menu", systemImage: "list.dash")
}
Text("View 2")
.tabItem {
Label("Order", systemImage: "square.and.pencil")
}
}
How can I achieve this?
No Solution for the moment
Unfortunately, it is not currently possible to show a modal sheet with a tab bar visible using the current version of SwiftUI. This issue has been raised by other developers on the Apple developer forums and on other threads on StackOverflow, such as the following:
https://developer.apple.com/forums/thread/711702
Swift UI show modal sheet with tab bar visible
SwiftUI present sheet in a TabItem of TabView using presentationDetents
I am also searching for a solution to this problem.
I am currently working on a custom ViewModifier to address this issue, and if it is successful, I will make it publicly available on GitHub.

Animating SwiftUI NavigationLinks that use tags

I've added onboarding steps to my app using SwiftUI instead of a UIPageViewController. The root-level view has several steps:
struct OnboardingView: View {
#EnvironmentObject private var onboardingModel: OnboardingModel
var body: some View {
NavigationView {
VStack {
FirstStep()
NavigationLink(destination: SecondStep(),
tag: "second-step",
selection: $onboardingModel.selectedStep) {
EmptyView()
}
NavigationLink(destination: ThirdStep(),
tag: "third-step",
selection: $onboardingModel.selectedStep) {
EmptyView()
}
// etc.
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
The OnboardingModel keeps track of the selectedStep, so that changes to it will trigger the corresponding NavigationLink's tag.
When the onboarding view starts up, the FirstStep animates in from the right, just like an ordinary push navigation. The remaining steps, however, simply replace the previous step without any animation. Adding an .animation(.easeIn) to each step does nothing. How can I make this look and feel like a UIPageViewController?
I should note that each step hides the navigation bar and title:
.navigationTitle(Text(""))
.navigationBarHidden(true)
but removing these lines doesn't restore any built-in animation that the NavigationView provides.
Click the screencap to see it in action. Note that only the first scene is animated in; the rest just appear, even though that is obscured a bit by the permissions dialogs.

How do I add a highlight to a TabItem label in SwiftUI

I have a TabView with custom icons - like this:
PastView( settings ).tabItem
{
Image("past")
Text("Past")
}.tag(1)
which works great - but just the text changing color is very subtle - it's not obvious which tab is "current". I want to make it much more obvious by doing something to the image. I've tried all of thse
Image("past").shadow( radius:5 )
Image("past").border( Color.red, width:8 )
Image("past").background( Color.green )
but none of them have any effect at all - and I don't really understand why
try adding ".accentColor(.red)" to the TabView.
TabItem image in SwiftUI has very limited customization at present. Even in UIKit you would be making those changes to the ImageView container not the Image itself.
Design selected and unselected versions of your icons, and then use them as below. You may also want to create different versions of the icons in the Asset Catalog for dark mode.
#State private var selectedTab = 0
var body: some View {
TabView(selection: $selectedTab) {
ViewA()
.tabItem {
selectedTab == 0 ? Image("past-selected") : Image("past-unselected")
}.tag(0)
ViewB()
.tabItem {
selectedTab == 1 ? // etc ...
}.tag(1)
}
}

How do I prevent SwiftUI's TabView from moving vertically when dragging? [duplicate]

I have set up a TabView in my application, so that I can swipe horizontally between multiple pages, but I also have an unwanted vertical scroll that may appear, with a bounce effect so. How can I disable this vertical scroll?
My code:
struct ContentView: View {
#State private var currentTabIndex: Double = 0
var body: some View {
VStack {
TabView(selection: $currentTabIndex) {
Text("Text n°1")
.tag(0)
Text("Text n°2")
.tag(1)
}
.border(Color.black)
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
}
}
}
I had this same problem. It's not an exact solution, but you can turn off bouncing on scrollviews (which is used within a TabView). And as long as the items within the TabView are not larger than the TabView frame, it should act as if you disabled vertical scrolling.
I would call it either .onAppear or in your init function:
.onAppear(perform: {
UIScrollView.appearance().bounces = false
})
Note: this disables the bouncing on ALL scrollviews across your app... So you may want to re-enable it .onDisappear.
Still an issue with Xcode 12.4.
I managed to workaround that by wrapping the TabView within a ScrollView and using the alwaysBounceVertical property set to false, as follow:
ScrollView(.horizontal) {
TabView {
///your content goes here
}
.tabViewStyle(PageTabViewStyle())
}
.onAppear(perform: {
UIScrollView.appearance().alwaysBounceVertical = false
})
.onDisappear(perform: {
UIScrollView.appearance().alwaysBounceVertical = true
})
I actually came across this because I saw this effect in a tutorial but couldn’t replicate it on iOS 15.2. However, I managed to replicate it on iOS 14.4 on another simulator side by side. So I guess this behaviour is disabled or fundamentally changed in the newer iOS.
Demonstration

Set navigation bar item style in SwiftUI

When adding a navigation bar item with UIKit, you set its style with UIBarButtonItem.style. This is important for a Done button, which is displayed with bold text.
SwitftUI's navigationBarItems(leading:trailing:) takes a View but no style. You could hack a style look-alike by using a bold button in the view, but it won't adjust to future OS style changes (e.g. a font weight other than bold).
How do you set the navigation bar item's style with SwiftUI?
iOS 14+
It is worth noting that using ToolbarItem(placement:) within a toolbar modifier will automatically apply emboldened text to buttons in the .confirmationAction placement position.
For example:
struct MyView: View {
var body: some View {
NavigationView {
Form {
// other elements
}
.navigationTitle("Edit Publication")
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Cancel") { }
}
ToolbarItem(placement: .confirmationAction) {
Button("Save") { }
}
}
}
}
As you can see from the illustration below, the Save button appears in bold.
If you want a button in the same place as the Save button below but not to be emphasised, you'd use the .primaryAction modifier.
Using the placement types that describe toolbar items' context – rather than using the deprecated navigationBarItems modifier, or the .navigationBarTrailing and .navigationBarLeading placement values – is the best way to make your SwiftUI views adapt to any changes in future versions of iOS.
They're also applicable across multiple platforms that don't necessarily have navigation bars, and other platforms may choose to render them differently. For example, using .confirmationAction on macOS creates a button with the app accentColor as a background.
I think we have to change how we think about SwiftUI as the concepts of "UIBarButtonItem.style" won't be directly applicable. SwiftUI tries to hide implementation details and wants concepts like changing the font-weight to "auto-magically work" depending on the context.
On Xcode 12.3, and iOS 14.3, seems that by default the button styles are bold (in the context of NavigationView):
.navigationBarItems(
leading:
Button(action: {}) {
Text("Cancel")
},
trailing:
Button(action: {}) {
Text("Save")
}
)
One way to change styling is by adding a button style:
.navigationBarItems(
leading:
Button(action: {}) {
Text("Cancel")
}.buttonStyle(PlainButtonStyle()),
trailing:
Button(action: {}) {
Text("Save")
}
)
But that did not achieve the desired effect. I had to change the font weight to have the "Cancel" be a regular style, and "Save" be bold...just like standard iOS:
.navigationBarItems(
leading:
Button(action: {}) {
Text("Cancel")
.fontWeight(Font.Weight.regular)
},
trailing:
Button(action: {}) {
Text("Save")
}
)
The nice thing about this is that you don't need to know about the concept of "UIBarButtonItem.style:" you just need to know about the concepts of what a Button is, and what Text is - which API should be familiar over-time as they are standard building blocks.
in SwiftUI instead of passing a style you append it to the View component. this will adjust to future OS style changes:
import SwiftUI
import PlaygroundSupport
struct ContentView: View {
var body: some View{
NavigationView {
Text("blah")
.navigationBarItems(leading: Text("done button")
.fontWeight(.medium)
.bold()
.foregroundColor(Color.red))
}
}
}
PlaygroundPage.current.setLiveView(ContentView())