Scale Shapes From An Actual Size Instead Of 0 SwiftUI - animation

I am trying to make pulse animation for an app I am making using swiftui. I want a center gray circle to pulse. Currently, the outside circles scale from 0 but I would like them to start from the middle circle size.
This is my current code:
import SwiftUI
struct Pulse: View {
#State var animate = false
#State private var scale: CGFloat = 2
var body: some View {
ZStack
{
Circle()
.fill(Color.black)
.frame(width: 130, height: 130)
Circle()
.stroke(Color.red.opacity(0.1), lineWidth: 5)
.frame(width: 300, height: 300)
.scaleEffect(self.animate ? 1 : 0)
Circle()
.stroke(Color.red.opacity(0.15), lineWidth: 5)
.frame(width: 266, height: 266)
.scaleEffect(self.animate ? 1 : 0)
Circle()
.stroke(Color.red.opacity(0.2), lineWidth: 5)
.frame(width: 232, height: 232)
.scaleEffect(self.animate ? 1 : 0)
Circle()
.stroke(Color.red.opacity(0.3), lineWidth: 5)
.frame(width: 198, height: 198)
.scaleEffect(self.animate ? 1 : 0)
Circle()
.stroke(Color.red.opacity(0.35), lineWidth: 5)
.frame(width: 164, height: 164)
.scaleEffect(self.animate ? 1 : 0)
Circle()
.stroke(Color.red.opacity(0.4), lineWidth: 5)
.frame(width: 130, height: 130)
.scaleEffect(self.animate ? 1 : 0)
Circle()
.fill(Color.gray)
.frame(width: 130, height: 130)
}
.frame(width: 290, height: 290, alignment: .center)
.onAppear(perform: {
self.animate.toggle()
})
.animation(Animation.linear(duration: 6).repeatForever(autoreverses: true))
.ignoresSafeArea()
}
}

The ratio of the size of the inner circle to the outer circle is 130 / 300. At its smallest, you want the circle with width and height of 300 to be 130.
Change all of these:
.scaleEffect(self.animate ? 1 : 0)
to:
.scaleEffect(self.animate ? 1 : 130 / 300)

Related

How Do i maintain Scrollview subitem height with Swiftui

I am new to swift and I am trying to wrap my view in Scrollview. The issue is that, when I wrap the content in the scrollview, the contents shrink. I have the images below.
sample code:
ScrollView(.vertical) {
GeometryReader { metrics in
HStack{
Button(action:{
isVisible = true
}, label: {
VStack(alignment: .center, spacing: 10){
Image(systemName: "book.fill")
.resizable()
.frame(width: 28, height: 22)
.padding(EdgeInsets(top: 15, leading: 0, bottom: 0, trailing: 0))
.foregroundColor(CustomColor.primaryColor)
Text("Daily Reading")
.padding(EdgeInsets(top: 0, leading: 0, bottom: 15, trailing: 0))
.foregroundColor(CustomColor.primaryColor)
}.frame(maxWidth: metrics.size.width/2.3, maxHeight: .infinity)
.background(RoundedRectangle(cornerRadius: 15)
.fill(Color.white)
.shadow(color: .gray, radius: 2, x: 0, y: 2))
})
Spacer()
Button(action: {
}, label: {
VStack(alignment: .center, spacing: 10){
Image("church")
.resizable()
.frame(maxWidth: 28, maxHeight: 22)
.padding(EdgeInsets(top: 15, leading: 0, bottom: 0, trailing: 0))
.foregroundColor(CustomColor.primaryColor)
Text("Church Prayers")
.padding(EdgeInsets(top: 0, leading: 0, bottom: 15, trailing: 0))
.foregroundColor(CustomColor.primaryColor)
}.frame(maxWidth: metrics.size.width/2.3, maxHeight: .infinity)
.background(RoundedRectangle(cornerRadius: 15)
.fill(Color.white)
.shadow(color: .gray, radius: 2, x: 0, y: 2))
})
}.frame(maxHeight: metrics.size.width/2)
.padding(.horizontal, 15)
.padding(.vertical, 7.5)
}
}
I have tried removing the GeometryReader but I am still getting the same result and I can't seem to find any helpful solution online. Thanks
on the HStack{...}, try replacing .frame(maxHeight: metrics.size.width/2) with .frame(height: metrics.size.width/2)

SwiftUI - Move and rotate an Image when a button is pressed

I have an Image, and I want it to rotate on the y axis, and move towards the bottom of the View when I press a Button. I tried using the .onChange, but I get the error "Result of call to 'animation' is unused", of which I understand the meaning, but I don't understand neither why it comes up nor how can I fix it.
Here's my code:
import SwiftUI
struct ContentView : View {
#State var animateCoin = false
#Environment(\.colorScheme) var colorScheme
var body: some View {
Rectangle()
.foregroundColor(colorScheme == .dark ? .white : .black)
.frame(width: 150, height: 150, alignment: .center)
.offset(y: -60)
.mask(Image("Coin") //That's the name of the Image I have in the assets
.resizable()
.onChange(of: animateCoin, perform: { value in
self.animation(.easeIn) //I put .easeIn just as an example, because the .rotation3DEffect gives me a red warning
}))
Button(action: { animateCoin = true } ) {
ZStack {
RoundedRectangle(cornerRadius: 10)
.foregroundColor(.green)
.frame(width: 100, height: 40, alignment: .center)
.shadow(radius: 10)
Text("Animate")
.foregroundColor(.white)
.shadow(radius: 20)
}
}
}}
The Image is set as a mask so that I can easily control its color depending on the light or dark mode.
Thank to everyone who will help me!
How about doing it like this:
#State var animateCoin = false
#Environment(\.colorScheme) var colorScheme
var body: some View {
VStack {
Rectangle()
.foregroundColor(colorScheme == .dark ? .white : .black)
.frame(width: 150, height: 150, alignment: .center)
.offset(y: -60)
.mask(Image(systemName: "car.fill")
.resizable()
.aspectRatio(contentMode: .fit)
.rotation3DEffect(
Angle(degrees: self.animateCoin ? 360 : 0),
axis: (x: 0, y: self.animateCoin ? 360 : 0, z: 0)
)
)
.offset(y: self.animateCoin ? 600 : 0)
.animation(.linear(duration: 1))
ZStack {
Button(action: { self.animateCoin.toggle() } ) {
ZStack {
RoundedRectangle(cornerRadius: 10)
.foregroundColor(.green)
.frame(width: 100, height: 40, alignment: .center)
.shadow(radius: 10)
Text("Animate")
.foregroundColor(.white)
.shadow(radius: 20)
}
}
}
}
}
As you asked:
Rotate on Y axis.
Move the image to the buttom.

Problem with formatting LazyHGrid - SwiftUI

I am trying to create a basic lazyHGrid but after looking at a couple of different tutorials online I still can't manage to build it properly. I am trying to make a grid that is filled with rectangles with symbols and text inside those rectangles. See image below:
If I make this in a HStack all the rectangles are presented correctly, but as soon as I put it into a LazyHGrid I get this problem. Any ideas?
let rows = [
GridItem(.fixed(200)),
GridItem(.fixed(200)),
]
var product: ProductModel
var body: some View {
LazyHGrid(rows: rows, alignment: .center) {
ForEach(0..<product.imageStack01Image.count, id: \.self) { item in
ZStack(alignment: .top){
RoundedRectangle(cornerRadius: 25, style: .continuous)
.fill(Color.white)
.frame(width: 200, height: 200)
.shadow(color: Color.black.opacity(0.08), radius: 20, x: 0, y: 5)
VStack(alignment: .leading) {
Image(systemName:product.imageStack01Image[item])
.font(.system(size: 40.0))
.frame(height: 40)
.foregroundColor(.red)
.padding(.top, 40)
.padding(.leading, 10)
Text(product.imageStack01Text[item])
.font(.title2)
.fontWeight(.medium)
.multilineTextAlignment(.trailing)
.padding(10)
}
}
}
}
}
As far as I understood your try to put image and text into rectangle, so try to use overlay instead of ZStack
ForEach(0..<product.imageStack01Image.count, id: \.self) { item in
RoundedRectangle(cornerRadius: 25, style: .continuous)
.fill(Color.white)
.frame(width: 200, height: 200)
.shadow(color: Color.black.opacity(0.08), radius: 20, x: 0, y: 5)
.overlay(
VStack(alignment: .leading) {
Image(systemName:product.imageStack01Image[item])
.font(.system(size: 40.0))
.frame(height: 40)
.foregroundColor(.red)
.padding(.top, 40)
.padding(.leading, 10)
Text(product.imageStack01Text[item])
.font(.title2)
.fontWeight(.medium)
.multilineTextAlignment(.trailing)
.padding(10)
})
}
}
It might have to do with the hardcoded frame in your square. Try using aspectRatio if you just want a square or frame each layer of the ZStack or frame the ZStack depending on what you want to achieve.
import SwiftUI
struct LazyGridSample: View {
///Sample Products to reproduce
#State var products = ["0xxxxxxxxxx0xxxxxxxxxx","1xxxxxxxxxx0xxxxxxxxxx","2xxxxxxxxxx0xxxxxxxxxx","3xxxxxxxxxx0xxxxxxxxxx","4xxxxxxxxxx0xxxxxxxxxx","5xxxxxxxxxx0xxxxxxxxxx","6xxxxxxxxxx0xxxxxxxxxx","7xxxxxxxxxx0xxxxxxxxxx","8xxxxxxxxxx0xxxxxxxxxx","9xxxxxxxxxx0xxxxxxxxxx"]
let rows = [
GridItem(.fixed(200)),
GridItem(.fixed(200)),
]
let squareSize: CGSize = CGSize(width: 200, height: 200)
var body: some View {
//ScrollView(.horizontal){
LazyHGrid(rows: rows, alignment: .center) {
//HStack{
ForEach(0..<products.count, id: \.self) { idx in
ZStack(alignment: .top){
RoundedRectangle(cornerRadius: 25, style: .continuous)
.fill(Color.white)
//.frame(width: squareSize.width, height: squareSize.height)
//.aspectRatio(1, contentMode: .fill)
.shadow(color: Color.black.opacity(0.08), radius: 20, x: 0, y: 5)
VStack(alignment: .leading) {
//Removed Image
Text(products[idx].description)
.font(.title2)
.fontWeight(.medium)
.multilineTextAlignment(.trailing)
.padding(10)
}//.frame(width: squareSize.width, height: squareSize.height, alignment: .center)
//.aspectRatio(1, contentMode: .fill)
}//Adjusts the the entire ZStack
//.frame(width: squareSize.width, height: squareSize.height, alignment: .center)
.aspectRatio(1, contentMode: .fill)
}
}
//}//ScrollView
}
}
struct LazyGridSample_Previews: PreviewProvider {
static var previews: some View {
LazyGridSample()
}
}

SwiftUI Scrollview contents are outside scrollable area

I'm having trouble keeping the contents of a ScrollView contained within the scrollview:
Initially, I want to display letters A and B in the ScrollView and have the user scroll to see additional letters. However, even though I've constrained the parent VStack to a frame with height of 120, you can also see the letter C which is outside of the ScrollView (as indicated by the blue background). Here's the code:
var body: some View {
VStack(alignment: .leading, spacing: 0) {
HStack(alignment: .center , spacing: 5) {
Text("Letter").font(.tableHeader).frame(width: 75, height: 30, alignment: .center)
} // HStack
.frame(width: 195, height: 50, alignment: .center)
.background(Color.green)
VStack(alignment: .leading, spacing: 0) {
GeometryReader { outsideProxy in
ScrollView (.vertical, showsIndicators: false) {
ZStack(alignment: .top) {
GeometryReader { insideProxy in
Color.clear
// get offset
} // GeometryReader inside
VStack(alignment: .leading, spacing: 10) {
HStack(alignment: .center, spacing: 5){
Text("A").font(.tableData).frame(width: 75, height: 50, alignment: .center)
}
HStack(alignment: .center, spacing: 5){
Text("B").font(.tableData).frame(width: 75, height: 50, alignment: .center)
}
HStack(alignment: .center, spacing: 5){
Text("C").font(.tableData).frame(width: 75, height: 50, alignment: .center)
}
HStack(alignment: .center, spacing: 5){
Text("D").font(.tableData).frame(width: 75, height: 50, alignment: .center)
}
} // VStack
} // ZStack
} // Scrollview
} // GeometryReader outside
.background(Color.blue)
} // VStack
.frame(width: 195, height: 120, alignment: .leading)
} // VStack
}
The full code requires that use of GeometryReader (and consequently, the ZStack) which is why I've left those items in the sample above.
What is the best way to solve this issue? Open to any improvements for coding the above layout. Keep in mind that ultimately, I want to the user to be able to click on A, B, C, or D to be taken to the next view in the navigation stack.
Make it clipped
ScrollView (.vertical, showsIndicators: false) {
ZStack(alignment: .top) {
GeometryReader { insideProxy in
Color.clear
// get offset
} // GeometryReader inside
VStack(alignment: .leading, spacing: 10) {
HStack(alignment: .center, spacing: 5){
Text("A").font(.tableData).frame(width: 75, height: 50, alignment: .center)
}
HStack(alignment: .center, spacing: 5){
Text("B").font(.tableData).frame(width: 75, height: 50, alignment: .center)
}
HStack(alignment: .center, spacing: 5){
Text("C").font(.tableData).frame(width: 75, height: 50, alignment: .center)
}
HStack(alignment: .center, spacing: 5){
Text("D").font(.tableData).frame(width: 75, height: 50, alignment: .center)
}
} // VStack
} // ZStack
} // Scrollview
.clipped() // << here !!

SwiftUI animations of elements in a scrollview doesn't work ? Xcode GM update

I just switched to the GM version of xcode and since then I have a problem that I did not have before it seems to me.
I created a simplified version of the problem:
I have a scrollview with several elements inside.
I add animations states on the blue square but I have the impression the elements have no animations and changes state brutally.
I tried with an element outside the scrollview (purple square) and it works
I don't see why animations do not work someone has an idea?
#State var Enter = false
var body: some View {
VStack {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 15) {
Rectangle()
.foregroundColor(Color.red)
.frame(width: 80, height: 80, alignment: .center)
Button(action: {
withAnimation(.easeInOut(duration: 1.12)) {
self.Enter = true
}
}) {
Rectangle()
.foregroundColor(Color.blue)
.frame(width: 80, height: 80, alignment: .center)
.opacity(self.Enter ? 0 : 1)
}
//.padding(.horizontal, self.Enter ? 50 : 10)
Rectangle()
.foregroundColor(Color.green)
.frame(width: 80, height: 80, alignment: .center)
.offset(x: self.Enter ? 30 : 0 , y: 0)
Rectangle()
.foregroundColor(Color.red)
.frame(width: 80, height: 80, alignment: .center)
}
.padding(.leading, 67 )
.padding(.trailing, 110)
// .padding(.top, (screen.height)/81.2)
.padding(.bottom, 10)
}
HStack {
Rectangle()
.foregroundColor(Color.purple)
.frame(width: 80, height: 80, alignment: .center)
.offset(x: self.Enter ? 80 : 0 , y: 0)
}
}
}
Using implicit vice explicit animation often works for me in these situations. This should accomplish what you were looking for: (works in the Xcode 11 GM seed)
Update: GM seed is apparently not passing the animation inside the scroll view. Edited to apply animation to both the HStack and the lone purple box
struct Square: View {
let color: Color
var body: some View {
Rectangle()
.fill(color)
.frame(width: 80, height: 80)
}
}
struct SquareAnimation: View {
#State private var enter = false
var body: some View {
VStack {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 15) {
Square(color: .red)
Square(color: .blue)
.opacity(self.enter ? 0.25 : 1)
.onTapGesture {
self.enter.toggle()
}
Square(color: .green)
.offset(x: self.enter ? 30 : 0)
Square(color: .red)
}
.animation(.easeInOut)
}
Square(color: .purple)
.offset(x: self.enter ? 80 : 0)
.animation(.easeInOut)
}
}
}
I am stuck with same problem. Solution by smr has helped. However, I was not able to get show/hide view animation. Following is an example:
struct Test: View {
#State var showView = false
var body: some View {
ScrollView {
Button(action: {
self.showView.toggle()
}) {
Text("Toggle View")
}
if showView {
Text("Some View")
}
}
.animation(.easeInOut)
}
}

Resources