SwiftUI animation affecting other views - ios

Here is my View:
struct HomeView: View {
#ObservedObject var instance = Instance()
#State var dotColor = Color.gray
var repeatingAnimation: Animation {
Animation
.easeInOut(duration: 1.0)
.repeatForever()
}
var body: some View {
ZStack {
TabView(selection: $selectedTab) {
Settings(auth: auth)
.tabItem {
Image(systemName: "gear")
Text("Settings")
}.tag(0)
ZStack {
MapView(locationManager: locationManager)
Color.black.opacity(self.instance.status.opacity)
VStack {
Spacer()
Button(action: {
print("clicked")
withAnimation(self.repeatingAnimation) {
self.dotColor = Color.white
}
self.instance.changeStatus()
}){
HStack {
Text(self.instance.status.text)
.font(.system(size: 24))
.fontWeight(.bold)
.foregroundColor(Color.white)
Circle().frame(width: 12, height: 12)
.foregroundColor(self.dotColor)
.colorMultiply(self.dotColor)
.overlay(
Circle()
.stroke(Color.black, lineWidth: 1)
)
}
}.padding()
My animation, changes the color of the Circle() from gray to white every second. However, it also changes my ZStack color opacity (Color.black.opacity(self.instance.status.opacity)) every second - even though it's not related to my animation.
If I remove the animation this weird behaviour does not occur to the ZStack opacity.
How can I fix this?

You can disable animation of some modifier explicitly, like
Color.black.opacity(self.instance.status.opacity)
.animation(nil)

Related

SwiftUI View does not disappear instantly after the transition animation ends

I created an application with move transition, which sends a View up from below with SwiftUI. However, when View disappears, transition animation is over, but the View remains for about 1 second.
This is my code.
struct ContentView: View {
#State var animation: Bool = false
var body: some View {
VStack {
// This is the Button
Button(action: {
withAnimation(.spring(dampingFraction: 1, blendDuration: 0.5)) {
animation.toggle()
}
}) {
Image(systemName: "star.fill")
.resizable()
.frame(width: 100, height: 100)
.foregroundColor(.accentColor)
}
// This condition sends up the View
if animation {
SecondView()
.transition(.move(edge: .bottom))
}
}
.padding()
}
}
struct SecondView: View {
var body: some View {
VStack {
Text("Hello, world!")
.font(.largeTitle)
.fontWeight(.bold)
Spacer()
}
}
}
And this happened.
I think what you need to do is to apply the animation directly to your button by using the animation modifier so your code may look like this:
Button(action: {
withAnimation {
animation.toggle()
}
}) {
Image(systemName: "star.fill")
.resizable()
.frame(width: 100, height: 100)
.foregroundColor(.accentColor)
}
.animation(.spring(dampingFraction: 1, blendDuration: 0.5), value: animation)
if animation {
SecondView()
.transition(.move(edge: .bottom))
}

Jumpy performance issue when offset and opacity used

I have a header that is fixed in place using an offset relative to the scroll position. Strangely enough though, when the contents of the scroll view has a dynamic opacity to the buttons, the offset is very jumpy:
This is the scroll view code, the HeaderView is "fixed" in place by pinning the offset to the scroll view's offset. The opacity seems to be causing the performance issue is on the MyButtonStyle style on the last line of code:
struct ContentView: View {
#State private var isPresented = false
#State private var offsetY: CGFloat = 0
#State private var headerHeight: CGFloat = 200
var body: some View {
GeometryReader { screenGeometry in
ZStack {
Color(.label)
.ignoresSafeArea()
ScrollView {
VStack(spacing: 0.0) {
Color.clear
.frame(height: headerHeight)
.overlay(
HeaderView(isPresented: $isPresented)
.offset(y: offsetY != 0 ? headerHeight + screenGeometry.safeAreaInsets.top - offsetY : 0)
)
VStack(spacing: 16) {
VStack(alignment: .leading) {
ForEach(0...10, id: \.self) { index in
Button("Button \(index)") {}
.buttonStyle(MyButtonStyle(icon: Image(systemName: "alarm")))
}
}
Spacer()
}
.frame(maxWidth: .infinity, minHeight: screenGeometry.size.height)
.padding()
.background(
GeometryReader { geometry in
Color.white
.cornerRadius(32)
.onChange(of: geometry.frame(in: .global).minY) { newValue in
offsetY = newValue
}
}
)
}
}
}
.alert(isPresented: $isPresented) { Alert(title: Text("Button tapped")) }
}
}
}
struct HeaderView: View {
#Binding var isPresented: Bool
var body: some View {
VStack {
Image(systemName: "bell")
.resizable()
.frame(width: 100, height: 100)
.foregroundColor(Color(.systemBackground))
Button(action: { isPresented = false }) {
Text("Press")
.padding()
.frame(maxWidth: .infinity)
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(16)
}
}
.padding()
}
}
struct MyButtonStyle: ButtonStyle {
let icon: Image
func makeBody(configuration: Configuration) -> some View {
Content(
configuration: configuration,
icon: icon
)
}
struct Content: View {
let configuration: Configuration
let icon: Image
var body: some View {
HStack(spacing: 18) {
Label(
title: { configuration.label },
icon: { icon.padding(.trailing, 8) }
)
Spacer()
Image(systemName: "chevron.right")
.accessibilityHidden(true)
}
.padding(18)
.foregroundColor(.white)
.background(Color.green)
.cornerRadius(8)
.opacity(configuration.isPressed ? 0.5 : 1) // <-- Comment this out and jumpiness goes away!!
}
}
}
Is there a performance improvement that can be done to use the opacity on the button press and make the jumpiness go away? Or a different way to approach this sticky offset because not sure if this is actually the source of the issue and I use opacity in a lot of places in my app (not just button presses)? The purpose of doing it this way is so the button can be tapped instead of putting it in the background of the scroll view. Thanks for any help or insight!

Unable to change background color of view in SwiftUI

I am trying to change background color main this view but unable to do it. I tried to put background(Color.green) at HStack, VSTack and even on ZStack but it did not work, not sure if i am putting at right place. By default it is taking phone or simulator color which is white but i want to apply custom background color
My Xcode version is 11.5
struct HomePageView: View {
#State var size = UIScreen.main.bounds.width / 1.6
var body: some View {
GeometryReader{_ in
VStack {
HStack {
ZStack{
// main home page components here....
NavigationView{
VStack {
AssignmentDaysView()
}.background(Color.lairBackgroundGray)
.frame(width: 100, height: 100, alignment: .top)
.navigationBarItems(leading: Button(action: {
self.size = 10
}, label: {
Image("menu")
.resizable()
.frame(width: 30, height: 30)
}).foregroundColor(.appHeadingColor), trailing:
Button(action: {
print("profile is pressed")
}) {
HStack {
NavigationLink(destination: ProfileView()) {
LinearGradient.lairHorizontalDark
.frame(width: 30, height: 30)
.mask(
Image(systemName: "person.crop.circle")
.resizable()
.scaledToFit()
)
}
}
}
).navigationBarTitle("Home", displayMode: .inline)
}
HStack{
menu(size: self.$size)
.cornerRadius(20)
.padding(.leading, -self.size)
.offset(x: -self.size)
Spacer()
}
Spacer()
}.animation(.spring()).background(Color.lairBackgroundGray)
Spacer()
}
}
}
}
}
struct HomePageView_Previews: PreviewProvider {
static var previews: some View {
HomePageView()
}
}
In your NavigationView you have a VStack. Instead you can use a ZStack and add a background below your VStack.
Try the following:
NavigationView {
ZStack {
Color.green // <- or any other Color/Gradient/View you want
.edgesIgnoringSafeArea(.all) // <- optionally, if you want to cover the whole screen
VStack {
Text("assignments")
}
.background(Color.gray)
.frame(width: 100, height: 100, alignment: .top)
}
}
Note: you use many stacks wrapped in a GeometryReader which you don't use. Consider simplifying your View by removing unnecessary stacks. Also you may not need a GeometryReader if you use UIScreen.main.bounds (however, GeometryReader is preferred in SwiftUI).
Try removing some layers: you can start with removing the top ones: GeometryReader, VStack, HStack...
Try the following:
Change the view background color especially safe area also
struct SignUpView: View {
var body: some View {
ZStack {
Color.blue //background color
}.edgesIgnoringSafeArea(.all)

View with fullscreen image and navigationLink

i'm new to swiftui and struggling with some basic stuff
I'm trying to create a view with 2 buttons on the botton.
I want an image as background of the whole view.
var body: some View {
ZStack {
Image("bg-welcome").edgesIgnoringSafeArea(.all)
}
}
This works fine
I set my view like this
NavigationView {
ZStack {
VStack(alignment: HorizontalAlignment.leading, spacing: 10) {
Text("1").foregroundColor(.white)
Text("2").foregroundColor(.white)
Spacer()
Button(action: {}){
Text("ooooooooo")
}
}.background(Image("bg-welcome"))
}
}
Now I have 2 problems:
- a white space is dispalyed just before the background image
- the first text is pushed below, surely after the space reserved for the navigationbar and I don't want it because when I navigate to the next screen, the space is still taken and I want to have the whole avaiblable screen
thank you for your help
try this:
var body: some View {
NavigationView {
ZStack {
VStack(alignment: HorizontalAlignment.leading, spacing: 10) {
Text("1").foregroundColor(.white)
Text("2").foregroundColor(.white)
Spacer()
Button(action: {}){
Text("Button 1")
}
Button(action: {}){
Text("Button 2")
}
}.background(Image("remachine_poster")
.resizable()
.aspectRatio(contentMode: .fill)).edgesIgnoringSafeArea(.all)
}
}
}
you can add a padding to your button....
NavigationView {
ZStack {
VStack() {
Text("1").foregroundColor(.green).padding(.top, 40)
Text("2").foregroundColor(.green)
Spacer()
Button(action: {}){
Text("Button 1")
}.foregroundColor(Color.red)
Button(action: {}){
Text("Button 2")
}.foregroundColor(Color.red)
}
}.background(Image("remachine_poster")
.resizable()
.aspectRatio(contentMode: .fill))
.edgesIgnoringSafeArea(.vertical)
}
I ended up doing something like this.
Please let me know if there is a better way
NavigationView {
GeometryReader { gr in
ZStack {
VStack(alignment: HorizontalAlignment.center, spacing: 10) {
HStack{
Spacer()
}
Text("1").foregroundColor(.white).padding(EdgeInsets(top: 30, leading: 0, bottom: 0, trailing: 0))
Text("2").foregroundColor(.white)
Spacer()
HStack {
NavigationLink(destination: SigninScreen()){
Text("Button 1")
}
Button(action: {}){
Text("Button 2")
}
}.padding()
}.background(Image("bg-welcome")
.resizable()
.aspectRatio(contentMode: .fill)).edgesIgnoringSafeArea(.all)
}.navigationBarHidden(true)
}
}

Remove circular button background in SwiftUI (WatchKit)

I'm struggling to remove the background of a custom circular Button element in SwiftUI which is defined as follows:
struct NavButton: View {
var body: some View {
Button(action: {})
VStack {
Text("Button")
}
.padding(40)
.background(Color.red)
.font(.title)
.mask(Circle())
}
}
}
This results in a rectangular light gray background around the button, where I want it to not be shown:
I tried to append a "background" modifier to the button, and it demonstrates very strange behavior: if it's set to "Color.clear", there is no effect. But if I set it to "Color.green" it does change the background as expected.
Example of setting the "Background" modifier to "Color.green":
struct NavButton: View {
var body: some View {
Button(action: {})
VStack {
Text("Button")
}
.padding(40)
.background(Color.red)
.font(.title)
.mask(Circle())
}
.background(Color.green) // has no effect if set to "Color.clear"
}
}
I wonder if I'm missing something here?
PS: I'm using Xcode 11.1 (11A1027)
Try adding .buttonStyle(PlainButtonStyle()) on the button itself.
You would have something like this:
Button(action: {}){
VStack{
Text("Button")
}
.padding(40)
.background(Color.red)
.font(.headline)
.mask(Circle())
}
.buttonStyle(PlainButtonStyle())
Declare your own ButtonStyle:
struct RedRoundButton: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.padding(40)
.font(.title)
.background( Circle()
.fill(Color.red))
}
}
and then use it like this:
Button("Button") {}
.buttonStyle(RedRoundButton())
Try this:
struct ContentView: View {
var body: some View {
Button(action: {}) {
Text("Button")
.frame(width: 80, height: 80)
}
.background(Color.red)
.cornerRadius(40)
.frame(width: 80, height: 80)
}
}
Try this.
struct ContentView: View {
var body: some View {
VStack {
Button(action: {}){
Text("button")
.font(.system(size: 50))
.foregroundColor(.black)
.bold()
}
.padding(30)
.background(Color.yellow)
.font(.headline)
.mask(Circle())
.buttonStyle(PlainButtonStyle())
} // end Vstack
}// end body
}

Resources