SwiftUI round button deforms when clicked - xcode

I have created a round button with following code:
struct RoundButton : View {
var value = "..."
var body: some View {
GeometryReader { geometry in
Button(action: {}) {
VStack {
Text(self.value)
.font(.headline)
.color(Color("NightlyDark"))
Text("MIN")
.font(.footnote)
.color(.white)
}
.frame(width: geometry.size.width, height: geometry.size.height)
}
.clipShape(Circle())
}
}
}
But when clicking the button, the shape gets deformed. Any idea why this happens ?
Same happens when i use .mask(Circle())
Is this a beta thing or normal behavior ? And does anyone maybe know a better way to create rounded buttons ?

what happens here is Button Considers all screen[width + height] as their frame by default.
so you have to set Button also.
I think it's the default behavior in watchOS
Here Your Code :
struct RoundButton: View {
var value = "..."
var body: some View {
GeometryReader { geometry in
Button(action: {}) {
VStack {
Text(self.value)
.font(.headline)
.foregroundColor(Color("NightlyDark"))
Text("MIN")
.font(.footnote)
.foregroundColor(.white)
}
.frame(width: geometry.size.width, height: geometry.size.height)
}
.frame(width: geometry.size.width, height: geometry.size.height)
.clipShape(Circle())
}
}
}
Note: i'm using Xcode 11 Beta 4

Related

view display on the right of the window

hello i have an issue with my project on Xcode when I use navigation view, the window display not normally and appear on the right of the window already displayed,
here is the code.
NavigationLink(destination: Acceuil())
{
HStack{
Image("icone_connexion")
.font(.system(size: 15))
// .scaledToFill()
Text("se connecter")
.font(.system(size: 30))
}.cornerRadius(60)
.frame(width: 400, height: 60)
} .background(Capsule().fill(Color(red: 55/255, green: 66/255, blue: 114/255, opacity:1)))
.frame(width: 400, height: 60) //fin navigationlink
.buttonStyle(PlainButtonStyle())
I would like that the new window replace the older one:)
On macOS it is the standard behavior in NavigationView to show the views (parent view and destination view) next to each other: https://developer.apple.com/design/human-interface-guidelines/macos/windows-and-views/column-views/
If you don't want that you can do:
NavigationView {
...
}
.navigationViewStyle(.stack)
so I found this code
import SwiftUI
struct ContentView: View {
#State private var show = false
var body: some View {
VStack{
if !show {
RootView(show: $show)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.blue)
.transition(AnyTransition.move(edge: .leading)).animation(.default)
}
if show {
NextView(show: $show)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.green)
.transition(AnyTransition.move(edge: .trailing)).animation(.default)
}
}
}
}
struct RootView: View {
#Binding var show: Bool
var body: some View {
VStack{
Button("Next") { self.show = true }
Text("This is the first view")
}
}
}
it work grate for me so thanks you for your help

Animating changes to #FocusState SwiftUI

I am using the new #FocusState to control how my views react to the user deciding to start inputting information into text fields. My current need is to wrap an animation around my top view leaving the screen as the keyboard moves up. Usually this kind of thing can be accomplished by simply wrapping withAnimation() around a boolean toggle, but since Swift is toggling my focus state bool under the hood, I can't wrap an animation around it in this way. How else should I do it?
Here is a minimal reproducible example. Basically I want to animate the top (red) view leaving / coming back into view with changes to my focus state isFocused var.
struct ContentView: View {
#State var text: String = ""
#FocusState var isFocused: Bool
var body: some View {
ZStack {
VStack {
if !isFocused {
Text("How to Animate this?")
.frame(width: 300, height: 300)
.background(Color.red)
.animation(.easeInOut(duration: 5), value: isFocused)
}
Text("Middle Section")
.frame(width: 300, height: 300)
.background(Color.green)
Spacer()
TextField("placeholder", text: $text)
.focused($isFocused)
}
if isFocused {
Color.white.opacity(0.1)
.onTapGesture {
isFocused = false
}
}
}
}
}
I don't think the animation modifier that's currently on the top view is doing anything, but I imagine that that's where I'll put some animation code.
Here is something that works. I've done this before to make an animation happen upon an #FocusState property changing its value. Can't really tell you why though, it's just something I figured out with trial and error.
struct ContentView: View {
#State var text: String = ""
#FocusState var isFocused: Bool
#State private var showRedView = false
var body: some View {
ZStack {
VStack {
if !showRedView {
Text("How to Animate this?")
.frame(width: 300, height: 300)
.background(Color.red)
}
Text("Middle Section")
.frame(width: 300, height: 300)
.background(Color.green)
Spacer()
TextField("placeholder", text: $text)
.focused($isFocused)
}
.onChange(of: isFocused) { bool in
withAnimation(.easeInOut(duration: 5)) {
showRedView = bool
}
}
if isFocused {
Color.white.opacity(0.1)
.onTapGesture {
isFocused = false
}
}
}
}
}

Span two Buttons across HStack in SwiftUI (Big Sur)

I have a problem getting the correct alignment for two buttons (Cancel and OK) in a sheet using SwiftUI.
I want the two buttons to appear at the bottom of the sheet so that the two of them span the whole horizontal width of the sheet (minus padding).
I've found several answers (such as setting the maxWidth to .infinity or by putting the text contend of a button in a separate Text view and surrounding it by Spacers) but none of them seem to work for me. The only one that works somewhat is by creating my own ButtonStyle. But then I have to recreate the whole default ButtonStyle (different for default button, for day and night mode,...)
The code I have now is:
var body: some View {
VStack() {
...
HStack {
Button("Cancel",action: {
isPresented.toggle()
})
.frame(minWidth: 0, maxWidth: .infinity)
.padding()
.keyboardShortcut(.cancelAction)
.border(Color.red)
Button("OK", action: {
isPresented.toggle()
let newServer = Server(name: name, url: url, port: port, autoConnect: autoConnect)
do {
try model.add(server: newServer)
} catch {
print("Could not add server.")
}
})
.frame(minWidth: 0, maxWidth: .infinity)
.padding()
.keyboardShortcut(.defaultAction)
.border(Color.red)
}
.frame(maxWidth: .infinity)
.padding(.top, 20)
.border(Color.blue)
}
.padding()
.frame(minWidth: 300, maxWidth: 300)
}
This results in the following sheet:
I would like both buttons to fill the area surrounded by the red border.
I'm kinda at a loss on what to try next!
as the red borders show, the buttons do extend to fill the area.
To get the background gray as in the picture, you could use something like:
.background(Color(UIColor.systemGray4))
as the last modifier of each buttons.
Default button style is rendered around provided label content, so possible solution is to calculate needed width for button label dynamically and apply it explicitly.
Note: please also see my comment for alternate
Demo prepared with Xcode 12.5 / macOS 11.3
struct ContentView: View {
#State private var cancelWidth = CGFloat.zero
#State private var okWidth = CGFloat.zero
var body: some View {
VStack() {
Text("Demo here!")
HStack(spacing: 0) {
Button(action: {
}) { Text("Cancel").frame(width: cancelWidth) }
.frame(minWidth: 0, maxWidth: .infinity)
.background(GeometryReader {
Color.clear.preference(key: ViewWidthKey.self,
value: $0.frame(in: .local).size.width) })
.onPreferenceChange(ViewWidthKey.self) { self.cancelWidth = $0 }
.padding()
.border(Color.red)
.keyboardShortcut(.cancelAction)
Button(action: {
}) { Text("OK").frame(width: okWidth) }
.frame(minWidth: 0, maxWidth: .infinity)
.background(GeometryReader {
Color.clear.preference(key: ViewWidthKey.self,
value: $0.frame(in: .local).size.width) })
.onPreferenceChange(ViewWidthKey.self) { self.okWidth = $0 }
.padding()
.keyboardShortcut(.defaultAction)
.border(Color.red)
}
.frame(maxWidth: .infinity)
.padding(.top, 20)
.border(Color.blue)
}
.padding()
.frame(minWidth: 300, maxWidth: 300)
}
}
struct ViewWidthKey: PreferenceKey {
typealias Value = CGFloat
static var defaultValue: CGFloat { 0 }
static func reduce(value: inout Value, nextValue: () -> Value) {
value = value + nextValue()
}
}

SwiftUI Animation Slide In and Out

I have a View that will display over another View. The view animation slides in from the right perfectly, but when I click on the Close button, the view disappears without the desired animation of sliding back to the right before disappearing.
I have tried using .opacity(self.isShowing ? 1 : 0), but then the View fades in and out, I need it to slide in and out. Other variations have not produced the desired results.
What am I doing wrong? Any guidance, even a duplicate solution (that I could not find) would be greatly appreciated.
struct NotificationView<parentView>: View where parentView: View {
#Binding var isShowing: Bool
let parentView: () -> parentView
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .center) {
self.parentView()
if(self.isShowing == true){
VStack {
Text("This is a test view\n")
Button(action: {
self.isShowing.toggle()
}) {
Text("Close")
}
}
.frame(width: geometry.size.width, height: geometry.size.height)
.background(Color(UIColor.systemBackground))
// .opacity(self.isShowing ? 1 : 0)
.transition(.move(edge: self.isShowing ? .trailing : .leading))
.animation(Animation.easeInOut(duration: 1.0))
}
}
}
}
}
Move conditional part into container and add animation to container, so it will animate content, like
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .center) {
self.parentView()
VStack { // << here !!
if(self.isShowing == true){
VStack {
Text("This is a test view\n")
Button(action: {
self.isShowing.toggle()
}) {
Text("Close")
}
}
.frame(width: geometry.size.width, height: geometry.size.height)
.background(Color(UIColor.systemBackground))
.transition(.move(edge: self.isShowing ? .trailing : .leading))
}
}.animation(Animation.easeInOut(duration: 1.0)) // << here !!
}
}
}

Navigation bar Display Mode is not working Perfectly in SwiftUI

I'm using SwiftUI with Version 11.3.1 (11C504).
I Implement Tab bar on the Screen and that screen will come after the navigation from login Screen.
If navigation displayMode is .automatic so i’am showing a white space(which is in bordered with black line in picture) when I scroll a list in up side. Otherwise navigation title show.
And When I set displayMode, .inline so it works perfect. And when I run a project so many time so some time it works perfect and some time showing a space.
i mentioned a white space in the picture with black border.
//ContentView
struct ContentView: View {
var body: some View {
HomeTabView()
}
}
//HomeTabView
struct HomeTabView: View {
#State private var selection = 0
//Inclose user intraface of tab View.
var body: some View {
TabView(selection: $selection){
TestListView().tabItem {
Image(systemName: "book.fill")
Text("Learn")
}.tag(0)
Text("Community").tabItem {
Image(systemName: "globe")
Text("Community")
}.tag(1)
//Add Notification List on the Screen.
Text("Notification").tabItem {
Image(systemName: "bell.fill")
Text("Notification")
}.tag(3)
//Add Account on the Tab Bar
Text("Account").tabItem {
Image(systemName: "person.circle.fill")
Text("Account")
}.tag(4)
}.accentColor(.pink)
.navigationBarTitle("SwiftUI")
}
}
TestListView
struct TestListView: View {
var body: some View {
VStack{
List(1...10, id: \.self){ num in
ListCards()
}
}.edgesIgnoringSafeArea(.all)
}
}
//ListCards
struct ListCards: View {
var body: some View {
ZStack{
RoundedRectangle(cornerRadius: 16)
.frame(height: 180)
.foregroundColor(.white)
.shadow(radius: 5)
VStack(alignment: .leading, spacing: 10){
HStack(alignment: .top){
Rectangle()
.frame(width: 100, height: 100)
.cornerRadius(16)
.foregroundColor(.pink)
VStack(alignment: .leading, spacing: 4){
Text("SwiftUI")
.font(.title)
Text("Description of title")
.foregroundColor(.gray)
}
}
.padding()
}.padding(.leading, 2)
}.padding(.all, 6)
}
}
You need to change your HomeTabView in this way:
var body: some View {
TabView(selection: $selection) {
NavigationView {
TestListView()
.navigationBarTitle("SWIFTUI")
}.tabItem {
Image(systemName: "book.fill")
Text("Learn")
}.tag(0)
NavigationView {
Text("Community")
}.tabItem {
Image(systemName: "globe")
Text("Community")
}.tag(1)
//Add Notification List on the Screen.
NavigationView {
Text("Notification")
}.tabItem {
Image(systemName: "bell.fill")
Text("Notification")
}.tag(3)
//Add Account on the Tab Bar
NavigationView {
Text("Account")
}.tabItem {
Image(systemName: "person.circle.fill")
Text("Account")
}.tag(4)
}.accentColor(.pink)
}
also, remove .edgesIgnoringSafeArea(.all) from TestListView

Resources