Button Internal Code
AniButtonView(bgColor: AppModuleType.debt.bgColor, imageName: AppModuleType.debt.symbols) {
enable.toggle()
debtPresenting.toggle()
executeAnimation()
}
.sheet(isPresented: $debtPresenting, content: {
sheetAction(.debt)
})
.rotationEffect(.degrees(featuresRotation))
.scaleEffect(featuresScale)
.position(x: geometry.size.width + offset.x, y: geometry.size.height + offset.y)
.offset(x: debtOffset.x, y: debtOffset.y)
.animation(.easeInOut(duration: 0.5), value: enable)
present CBRecordView code
CommandButton(offset: UnitPoint(x: -50, y: -150)) { type in
CBRecordView(viewModel: RecordDeploy(type))
}
RecordDeploy is ViewModel
i found program will continue to call
sheet(isPresented: $debtPresenting, content: { .... })
Closures in debug
this Effect
enter image description here
Related
im using this example to build a loading animation, and animated part is just falling from the sky.
struct ContentView: View {
#State private var isLoading = false
var body: some View {
ZStack {
Text("Loading")
.font(.system(.body, design: .rounded))
.bold()
.offset(x: 0, y: -25)
RoundedRectangle(cornerRadius: 3)
.stroke(Color(.systemGray5), lineWidth: 3)
.frame(width: 250, height: 3)
RoundedRectangle(cornerRadius: 3)
.stroke(Color.green, lineWidth: 3)
.frame(width: 30, height: 3)
.offset(x: isLoading ? 110 : -110, y: 0)
.animation(Animation.linear(duration: 1).repeatForever(autoreverses: false))
}
.onAppear() {
self.isLoading = true
}
}
}
You have a couple of problems with your code. First, .animation() has been deprecated because it is unreliable. You should be using .animation(_:value:) instead.
While I can't duplicate the "falling from the top" problem, I think I know what it is. It is an animation timing issue when the animation is triggered before the view is on screen. If you continue to get this, wrap your change in .onAppear() in DispatchQueue.main.asyncAfter(deadline:). The code with this is below:
struct ContentView: View {
#State private var isLoading = false
var body: some View {
ZStack {
Text("Loading")
.font(.system(.body, design: .rounded))
.bold()
.offset(x: 0, y: -25)
RoundedRectangle(cornerRadius: 3)
.stroke(Color(.systemGray5), lineWidth: 3)
.frame(width: 250, height: 3)
RoundedRectangle(cornerRadius: 3)
.stroke(Color.green, lineWidth: 3)
.frame(width: 30, height: 3)
.offset(x: isLoading ? 110 : -110, y: 0)
// Use this init for .animation, as the other one is depracated
.animation(Animation.linear(duration: 1).repeatForever(autoreverses: false), value: isLoading)
}
.onAppear() {
// This may not be necessary, but if you get the "falling from the top" problem, put this
// around isLoading = true
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
isLoading = true
}
}
}
}
Can you try 3 things:
Remove the instances of offset coordinates where value = 0. Like x=0 y=0 etc
Add stop animation inside onDisappear()
.onDisappear() {
self.isLoading = false
}
If you are using .transition() in this or any of its parent view, try removing that
How can you assign different actions if you are creating buttons in a loop when using SwiftUI.
I was using sender tag while using UIView.
At following code, every buttons calls the same function as usual.
How can I make them call different action in case we are using loops to create buttons.
var buttonNames = ["OK", "NOPE"]
var body: some View {
let width = UIScreen.main.bounds.width / CGFloat(buttonNames.count)
ScrollView (.horizontal, showsIndicators: false) {
LazyHStack {
ForEach(0..<buttonNames.count, id: \.self) { index in
Button(buttonNames[index]) {
buttonTouched()
}.frame(width: width)
.background(Color.gray)
}
}
.frame(width: UIScreen.main.bounds.width, height: 45, alignment: .center)
.foregroundColor(.white)
.background(Color.gray)
}
.position(x: UIScreen.main.bounds.width / 2, y: UIScreen.main.bounds.height - 45)
}
After the comment I did it like this and it makes the trick.
var buttonNames = ["OK", "NOPE"]
#State var touchedButton = 0
func buttonTouched(){
print("Button tapped! \(touchedButton)")
}
var body: some View {
let width = UIScreen.main.bounds.width / CGFloat(buttonNames.count)
ScrollView (.horizontal, showsIndicators: false) {
LazyHStack {
ForEach(0..<buttonNames.count, id: \.self) {
index in
Button(action:{
touchedButton = index
buttonTouched()
}
){
Text(buttonNames[index])
}
.frame(width: width)
}
}
.frame(width: UIScreen.main.bounds.width, height: 45, alignment: .center)
.foregroundColor(.white)
.background(Color.gray)
} .position(x: UIScreen.main.bounds.width / 2, y: UIScreen.main.bounds.height - 45)
}
I have two circles on my screen (top and bottom). I want the user to press down on the top circle, and drag to the bottom one.
I'm not dragging and dropping (I don't want the UI to change).
I just want to know that the user started on the top one, and released their finger on the bottom circle. When the user releases their finger on the bottom one.
I haven't been able to find my answer from other questions.
Current code
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Circle()
.fill()
.foregroundColor(.blue)
.frame(width: 100, height: 100)
.gesture(
DragGesture(minimumDistance: 0, coordinateSpace: .named("mySpace"))
.onChanged { value in
}
.onEnded { value in
// if value.location == endPoint {
// print("user started press on blue and ended on green")
// }
}
)
Spacer()
Circle()
.fill()
.foregroundColor(.green)
.frame(width: 100, height: 100)
}.coordinateSpace(name: "mySpace")
}
}
Screenshot
Would appreciate any help!
Here I could find a way for get notified wether this 2 Circles are in some part inside each other:
import SwiftUI
struct ContentView: View {
typealias OffsetType = (offset: CGSize, lastOffset: CGSize)
#State private var objects: [OffsetType] = [(offset: CGSize(width: 0.0, height: -200.0), lastOffset: CGSize(width: 0.0, height: -200.0)),
(offset: CGSize(width: 0.0, height: 200.0), lastOffset: CGSize(width: 0.0, height: 200.0))]
var body: some View {
ZStack {
CircleView(color: Color.blue)
.offset(objects[0].offset)
.gesture(dragGesture(indexOfObject: 0))
CircleView(color: Color.green)
.offset(objects[1].offset)
.gesture(dragGesture(indexOfObject: 1))
}
.animation(Animation.easeInOut(duration: 0.1))
}
func dragGesture(indexOfObject: Int) -> some Gesture {
DragGesture(minimumDistance: 0.0, coordinateSpace: .global)
.onChanged() { value in
objects[indexOfObject].offset = CGSize(width: objects[indexOfObject].lastOffset.width + value.translation.width,
height: objects[indexOfObject].lastOffset.height + value.translation.height)
}
.onEnded() { value in
objects[indexOfObject].lastOffset = CGSize(width: objects[indexOfObject].lastOffset.width + value.translation.width,
height: objects[indexOfObject].lastOffset.height + value.translation.height)
objects[indexOfObject].offset = objects[indexOfObject].lastOffset
distance()
}
}
func distance() {
if pow(pow((objects[1].offset.width - objects[0].offset.width), 2.0) + pow((objects[1].offset.height - objects[0].offset.height), 2.0), 0.5) <= 100 { print("same place!") }
}
}
struct CircleView: View {
let color: Color
var body: some View {
Circle()
.fill(color)
.frame(width: 100, height: 100)
}
}
I have a scrollview with an HStack inside it that is sized according to how many hexagons are to be placed in it. There are three possible values - 25, 64 and 100. The scrollview is positioned correctly for 25 and 64 hexagons, but is shifted to the right for 100. How can I make sure that is centred correctly too?
Incidentally, I have already tried manually setting the position of the scrollview - it worked the same as without.
GeometryReader
{ scrollViewGeometry in
ScrollView([.vertical, .horizontal], showsIndicators: true)
{
Spacer()
HStack(spacing:-(max(minHexagonSize, smallSide)))
{
ForEach(viewModel.hexagons){hexagon in
let hexagonFrame = getFrameFor(hexagon: hexagon, minWidth: smallSide)
let colorArray = getColorsFor(hexagon: hexagon)
ZStack()
{
let thisIndex = hexagon.id
HexagonView(strokeColor: colorArray[0]).onTapGesture(perform: {
viewModel.chooseHexagon(hexagon: hexagon)
})
.scaleEffect(hexagon.pressed ? 1.2 : 1.0)
.animation(Animation.easeInOut(duration: 0.2))
if hexagon.isSelected
{
Circle().fill(playerColorArray[hexagon.playerIndex]).frame(width: hexagonFrame.width * fontScalingFactor, height: hexagonFrame.height * fontScalingFactor, alignment: .center)
Circle().stroke(Color.black).frame(width: hexagonFrame.width * fontScalingFactor, height: hexagonFrame.height * fontScalingFactor, alignment: .center)
}
else
{
Text(verbatim: String(thisIndex+1)).font(Font.system(size: hexagonFrame.size.width * fontScalingFactor)).foregroundColor(colorArray[1])
.onTapGesture(perform: {
Sounds.playSounds(soundName: "pop")
viewModel.chooseHexagon(hexagon: hexagon)
})
.scaleEffect(hexagon.pressed ? 1.2 : 1.0)
.animation(Animation.easeIn(duration: 0.5))
}
if hexagon.isSelected && hexagon.pressed
{
Text(String(viewModel.currentScore))
.foregroundColor(Color.black)
.font(Font.system(size: hexagonFrame.size.width * fontScalingFactor)).foregroundColor(colorArray[1])
.transition(AnyTransition.asymmetric(insertion: .identity, removal: AnyTransition.move(edge: .top).combined(with: .opacity).animation(.easeIn(duration: 1.0))))
.animation(.easeIn(duration: 1.0))
.zIndex(hexagon.isSelected ? 1 : 0)
}
}
.position(x: hexagonFrame.origin.x - (scrollViewGeometry.size.width/2), y: scrollViewGeometry.size.height/2 - hexagonFrame.origin.y)
.frame(width: hexagonFrame.size.width, height: hexagonFrame.size.height)
.zIndex(hexagon.isSelected ? 1 : 0)
}
}
.frame(width: (max(minHexagonSize, smallSide)) * (sqrt(CGFloat(viewModel.hexagons.count)) * 2), height: (max(minHexagonSize, smallSide) * (sqrt(CGFloat(viewModel.hexagons.count)) + 2)))
//.position(x: scrollViewGeometry.size.width, y: scrollViewGeometry.size.height)
}
.padding()
}
OK... so it turns out that the reason it was not centred, is because I was looking at the wrong part of the view. I still don't understand why it worked fine for the smaller scrollable areas in the scrollview, but not for the larger one!
I have a set of subviews that are arranged within an HStack. I have a transition that is run whenever a view is selected successfully, but it is occluded by neighbouring views "above" it.
I found this article here, but I can't see how to integrate it into my solution:
How to bring a view on top of VStack containing ZStacks
Is there a way of getting the selected view to pop on top of the others?
HStack(spacing: -75)
{
ForEach(viewModel.hexagons){hexagon in
let hexagonFrame = getFrameFor(hexagon: hexagon, minWidth: smallSide)
let colorArray = getColorsFor(hexagon: hexagon)
ZStack()
{
let thisIndex = hexagon.id
HexagonView(strokeColor: colorArray[0]).onTapGesture(perform: {
viewModel.chooseHexagon(hexagon: hexagon)
})
.scaleEffect(hexagon.pressed ? 1.2 : 1.0)
.animation(Animation.easeInOut(duration: 0.2))
if hexagon.isSelected
{
Circle().fill(playerColorArray[hexagon.playerIndex]).frame(width: hexagonFrame.width * fontScalingFactor, height: hexagonFrame.height * fontScalingFactor, alignment: .center)
Circle().stroke(Color.black).frame(width: hexagonFrame.width * fontScalingFactor, height: hexagonFrame.height * fontScalingFactor, alignment: .center)
}
else
{
Text(verbatim: String(thisIndex+1)).font(Font.system(size: hexagonFrame.size.width * fontScalingFactor)).foregroundColor(colorArray[1])
.onTapGesture(perform: {
viewModel.chooseHexagon(hexagon: hexagon)
})
.scaleEffect(hexagon.pressed ? 1.2 : 1.0)
.animation(Animation.easeIn(duration: 0.5))
}
This is the view that animates up from the haxagon that has been selected
if hexagon.isSelected && hexagon.pressed
{
Text(String(viewModel.currentScore))
.foregroundColor(Color.gray)
.font(Font.system(size: hexagonFrame.size.width * fontScalingFactor)).foregroundColor(colorArray[1])
.transition(AnyTransition.asymmetric(insertion: .identity, removal: AnyTransition.move(edge: .top)))
.animation(.easeIn(duration: 2.0))
.zIndex(.greatestFiniteMagnitude)
}
}
.position(x: hexagonFrame.origin.x + hexagonFrame.size.width / 3 - (scrollViewGeometry.size.width/2), y: (scrollViewGeometry.size.height/2) - hexagonFrame.origin.y)
.frame(width: hexagonFrame.size.width, height: hexagonFrame.size.height, alignment:.center)
}
}.frame(width: (max(75, smallSide) * 8), height: (max(75, smallSide) * 5))