How to prevent text compression when centering a View in SwiftUI? - swiftui

See attached:
Squished Toggle in SwiftUI
... The code for this centered toggle is simply:
#State var rememberMe: Bool = false
HStack(alignment: .center) {
Spacer()
Toggle(
"Remember Me",
isOn: $rememberMe
)
Spacer()
}
Obviously, there's no need for ellipsis here, but by eliminating the Spacer() on each side, it'll grow to fill the width.
How do you center the Toggle without squishing its text? 🤔

fixedSize() seems to fix the issue on my end. We don't even need a HStack:
import SwiftUI
struct ContentView: View {
#State var rememberMe: Bool = false
var body: some View {
Toggle(
"Remember Me",
isOn: $rememberMe
).fixedSize()
}
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
Result
From Apple:
fixedSize() Fixes this view at its ideal size.

Related

Swiftui Button to behave like a checkbox doesn't preview but works

Here's the code for the Checkbox I created. It works great but in the Xcode preview canvas it doesn't work. As in, in the preview when you click it, it doesn't change. When I use the checkbox in my app and run it in the simulator it works great. Any ideas why this is?
//
// CheckboxToggle.swift
//
//
//
import SwiftUI
enum CheckboxShape : String {
case circle = "circle"
case square = "square"
}
struct Checkbox: View {
#Binding var isChecked:Bool
var style:CheckboxShape
#State var action:(Bool)->() = {_ in }
var body: some View {
Button {
isChecked.toggle()
action(isChecked)
} label: {
let shape = style.rawValue
Image(systemName: isChecked ? "checkmark.\(shape).fill" : "\(shape)")
.resizable()
.frame(width: 24, height: 24)
.foregroundColor(isChecked ? .green : .gray)
.font(.system(size: 20, weight: .regular, design: .default))
}
.buttonStyle(PlainButtonStyle())
}
}
struct Checkbox_Previews: PreviewProvider {
#State static var isChecked:Bool = false
// Not sure why this preview doens't work but the view works in other views fine.
static var previews: some View {
HStack {
Checkbox(isChecked: $isChecked, style: .circle)
}
}
}
SwiftUI previews don't work this way.
To make Checkbox interactive declare isChecked as #State
#State var isChecked = false
and replace the PreviewProvider with
struct Checkbox_Previews: PreviewProvider {
static var previews: some View {
Checkbox(style: .circle)
}
}
And if you want to see both states (and also the square appearance) and keep the #Binding add more Checkbox views and specify constants
struct Checkbox_Previews: PreviewProvider {
static var previews: some View {
HStack {
Checkbox(isChecked: .constant(true), style: .circle)
Checkbox(isChecked: .constant(false), style: .circle)
Checkbox(isChecked: .constant(true), style: .square)
Checkbox(isChecked: .constant(false), style: .square)
}
}
}
But this preview is not interactive.

TabView taking Top Space in SwiftUI

Hi I am currently working on swiftUI project. I am facing a very strange issue. Here is the code for my problem. As you can see that, this tabView is taking some space from the Top which is highlighted in Red Color. It should be All blue in the View.
Why it is taking that extra space from the Top?
Kindly Review the code and help me with this problem as i'm a beginner.
import SwiftUI
struct StackOverFlowView: View {
#State private var selection = 0
var body: some View {
ZStack() {
Color.red
TabView(selection: $selection) {
Color.blue
}
.tabViewStyle(PageTabViewStyle())
.edgesIgnoringSafeArea(.all)
}.ignoresSafeArea(.all)
}
}
struct StackPreview: PreviewProvider {
static var previews: some View {
StackOverFlowView()
}
}

Best way to present a long Segmented Picker in Swift UI

I need some suggestions on presenting a segmented picker in Swift UI.
It is to display distinct time ranges (<15min, <30min, <45min) all the way to 120min.
It ends up being 8 segments. I am really not a fan of the scrolling picker as it not in theme what what I am looking for in presentation.
The problem with how it stands now is that the time unit is cut off with each segment showing "15.." and doesn't look clean.
I have put the segmented picker in a horizontal scroll view which looks okay but the user may not know to scroll.
One option I used but can't get to work out is splitting the one long segment into 2 separate views.
The problem is the user can select a segment from either pickers which is not what I want.
What I want is if the user selects one picker, the other one is not selectable or vice versa.
I have been messing with some formatting options, so please ignore that.
Is this possible?
Thanks is advance!
struct ContentView: View {
var body: some View {
VStack{
To60min()
To120min()
.foregroundColor(Color.red)
}
}}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}}
struct To60min: View {
#State private var selectedTimeRangeto60 = ""
#State private var timeRangesTo60 = ["15min", "30min", "45min", "60min"]
var body: some View {
Picker("", selection: $selectedTimeRangeto60) {
ForEach(timeRangesTo60, id: \.self) {
Text($0)
}
}
.frame(width: .infinity, height: 75)
.background(.gray)
.padding()
.pickerStyle(.segmented)
.contrast(22.0)
}
}
struct To120min: View {
#State private var selectedTimeRangeto120 = ""
#State private var timeRangesTo120 = ["75min", "90min", "105min", "120min"]
var body: some View {
Picker("", selection: $selectedTimeRangeto120) {
ForEach(timeRangesTo120, id: \.self) {
Text($0)
}
}
.padding()
.pickerStyle(.segmented)
.contrast(22)
}
}
For anything more than 3-4 items (depending on label length), I would switch from a .segmented to .menu picker style. https://developer.apple.com/documentation/swiftui/pickerstyle

How to hide/remove WatchOS 9's .sheet cancel button?

Previous to watchOS 9 you could present a sheet without any out of the box way to cancel or dismiss. However starting in watchOS 9 presenting a sheet also presents a cancel button in the top left of the navigation bar. How can I remove this and handle dismissing myself?
import SwiftUI
struct ContentView: View {
#State var isShowingSheet = false
var body: some View {
VStack {
Button("show sheet") {
isShowingSheet.toggle()
}
}
.sheet(isPresented: $isShowingSheet) {
Text("Sheet 1")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Same issue here, tried an empty view in a ToolBarItem but did not work.
I ended up using this:
NavigationView {
// Your stuff here
}
.navigationTitle("")
.navigationBarTitleDisplayMode(.inline)
What you do is that you set an empty title, and you tell it to go at the same place as of the cancel button.
PS:it looks like #Kurt Lane was a bit faster in the comment. Credits to him.

Fade-in/out animation with a boolean flag

I am trying to implement a simple "tap to toggle the visibility of the UI" in SwiftUI with fade in/out animation. The following code animates the fade-in effect of the Text element as I expected, but it immediately hides the Text element when isVisible become false.
I'd like to understand why this code does not work, and how to fix it in the most natural way.
import SwiftUI
struct ContentView: View {
#State var isVisible = true
var body: some View {
ZStack {
Rectangle()
.foregroundColor(.blue)
.gesture(TapGesture(count: 1).onEnded {
withAnimation(.easeInOut(duration: 1.0)) {
isVisible.toggle()
}
})
if isVisible {
Text("Tap me!")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I'm using Xcode 12.5 on Big Sur, and my iPhone is running iOS 14.5.1.
Thanks to Erik Philips, here is the answer.
import SwiftUI
struct ContentView: View {
#State var isVisible = true
var body: some View {
ZStack {
Rectangle()
.zIndex(1)
.foregroundColor(.blue)
.gesture(TapGesture(count: 1).onEnded {
withAnimation(.easeInOut(duration: 1.0)) {
isVisible.toggle()
}
})
if isVisible {
Text("Tap me!")
.zIndex(2)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}