How to run function when long press gesture detected and stopped? - swiftui

I want to implement following example: User needs to press a button at least 0.3 seconds long, after this the audio recording starts and after the user release the button the recording stops.
My solution is:
Image(systemName: "mic.circle")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 70)
.foregroundColor(Color.blue)
.onLongPressGesture(minimumDuration: 0.3){
print("start recording...")
}
How can I implement the function when the user stop pressing the button?

I could solve my problem, hope it's useful for some of you:
#State private var isPressingDown: Bool = false
Image(systemName: "mic.circle")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 70)
.foregroundColor(Color.blue)
.onLongPressGesture(minimumDuration: 0.3){
self.isPressingDown = true
print("started")
}
.simultaneousGesture(
DragGesture(minimumDistance: 0)
.onEnded{ _ in
if self.isPressingDown{
self.isPressingDown = false
print("ended")
}
}
)

Related

How do I create a looping heartbeat animation in swiftUI?

I am trying to create an animation where a small heart icon is pumping. I have the two images I believe are sufficient to create the effect, but I have no idea how to create this animation effect. I have tried several things and none of them seem to work.
Any help you can offer will be greatly appreciated.
Here's what I have so far:
#State var show : Bool = false
var body: some View {
VStack(alignment: .trailing){
ZStack{
BlackView()
if(show){
Image("heartOrgan1")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 50, height:50)
.hidden()
Image("heartOrgan")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 50, height: 50)
} else {
Image("heartOrgan1")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 50, height: 50)
Image("heartOrgan")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 50, height: 50)
.hidden()
}
}
.onAppear(){
withAnimation { self.show.toggle()}
}
}
}
The general idea is to loop the switching between two heart images that represent a heart beating. I am interested in using these particular heart images as they look like actual hearts, and I like that.
You don't necessarily need two images for this. You can use one image and apply the scale effect on it. Make the one image scale up and add a delay to it. Then make it repeat.
Example:
#State private var animationAmount: CGFloat = 1
var body: some View {
ZStack {
Color.black
Image(systemName: "heart.fill")
.resizable()
.frame(width: 50, height: 50)
.foregroundColor(.red)
.scaleEffect(animationAmount)
.animation(
.linear(duration: 0.1)
.delay(0.2)
.repeatForever(autoreverses: true),
value: animationAmount)
.onAppear {
animationAmount = 1.2
}
}
}
You can also change the decimal value in inside the delay() to have different heartbeats. The heartbeat looks consistent with delays between 0.1 - 0.4.
I would slightly modify the great answer provided by Jame to make the animation a little bit more realistic, just by changing the linear animation for a spring animation like this:
struct ContentView: View {
#State private var animationAmount: CGFloat = 1
var body: some View {
ZStack {
Color.black
Image(systemName: "heart.fill")
.resizable()
.frame(width: 50, height: 50)
.foregroundColor(.red)
.scaleEffect(animationAmount)
.animation(
.spring(response: 0.2, dampingFraction: 0.3, blendDuration: 0.8) // Change this line
.delay(0.2)
.repeatForever(autoreverses: true),
value: animationAmount)
.onAppear {
animationAmount = 1.2
}
}
}
}
You can play with repetition, dampingFraction and blenDuration parameters to get a more customised animation.
:)

SwiftUI TextEditor how Hide Keyboard

I have à problem with TextEditor, I cannot hide the Keyboard after editing my text on the Texteditor.
#State var monTexte: String = "
var body: some View {
VStack {
Spacer()
.frame(height :15)
.clipped()
Text("Project ")
.font(Font.system(size: 39.00))
.fontWeight(.black)
.foregroundColor(Color.white)
.multilineTextAlignment(.center)
.padding(.all, 16.0)
.clipped()
TextEditor(text: $monTexte)
.keyboardType(.alphabet)
.font(.subheadline)
.padding(.horizontal)
.font(Font.system(size: 38.00))
.frame(minWidth: 10, maxWidth: .infinity, minHeight: 10, maxHeight: 200, alignment: .topLeading)
.border(Color.black)
.clipped()
}
}
}
I’ve found a method to hide the keyboard using a textfield but not using a TextEditor
Coule you help me please
Thank you "Asperi" it's works using the code below :
var body: some View {
VStack {
Spacer()
.frame(height :15)
.clipped()
Text("Project ")
.font(Font.system(size: 39.00))
.fontWeight(.black)
.foregroundColor(Color.white)
.multilineTextAlignment(.center)
.padding(.all, 16.0)
.clipped()
HStack {
Spacer()
Button("Close Keyboard") {
UIApplication.shared.endEditing()
}.font(Font.system(size: 20))
.foregroundColor(Color.blue)
}.clipped()
TextEditor(text: $monTexte)
.keyboardType(.alphabet)
.font(.subheadline)
.padding(.horizontal)
.font(Font.system(size: 38.00))
.frame(minWidth: 10, maxWidth: .infinity, minHeight: 10, maxHeight: 200, alignment: .topLeading)
.border(Color.black)
.clipped()
}
}
}
//----------------------------------------------------//
// Masquer le clavier
//----------------------------------------------------//
extension UIApplication {
func endEditing() {
sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}```
I found this worked adequately for me. It's pure SwiftUI, without having to resort to UIKit.
struct TestView: View {
#State private var response = ""
#FocusState private var responseIsFocussed: Bool // dismiss response editor keyboard when hit Return
var body: some View {
TextEditor(text: $response)
.focused($responseIsFocussed)
.onReceive(response.publisher.last()) {
if ($0 as Character).asciiValue == 10 { // ASCII 10 = newline
responseIsFocussed = false // unfocus TextEditor to dismiss keyboard
response.removeLast() // remove newline at end to prevent retriggering...
}
}
}
}
The .focused() modifier on the view triggers attaches a trigger to the TextEditor to enable you to programmatically focus (show) or unfocus (dismiss) the keyboard. And the .onReceive() captures key entry; it checks whether the last char entered in the string is a newline (ASCII 10), and if so triggers the unfocus. Its important to immediately remove this Return/newline from the end of the string, otherwise it can keep triggering...
Caveat: this only triggers off the last char; if you edit the string and move the cursor midway and hit Return, nothing will happen (which actually behaves somewhat intuitively, IMO...)

Aligning image to navigationBarTitle in SwiftUI

I'm trying to add a User Image (button) next to the .navigationBarTitle, but with the code bellow, the image appears on top of the title alignment. (picture attached). Many thanks for your help!
.navigationBarTitle(Text("Watch"))
.navigationBarItems(trailing:
Image("User")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 36, height: 36)
.clipShape(Circle())
)
Image should be bottom - aligned to the text
This code produces this view:
struct ContentView: View {
var body: some View {
NavigationView {
List {
Text("Chocolate")
Text("Vanilla")
Text("Strawberry")
}.navigationBarTitle(Text("Watch"))
.navigationBarItems(trailing:
Image(systemName: "person.circle")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 36, height: 36)
.clipShape(Circle())
.padding(.top, 90)
)
}
}
}
There is a default space for the Items and a default space for the Text. Imagine it like two HStacks in a VStack. Where the Title is in the lower HStack and the items are in the upper one. There is no "real" way on getting in the lower one.
I'd recommend to create an own NavigationBar for your purposes.
Thanks #Simon, the best option for what I was looking for is to Add the User Icon to the Title (not NavBar) and apply an Offset of y: -55. When scrolling up the icon disappears under the NavBar. The same effect on the Apple TV app (mobile).` VStack(alignment: .leading) {
HStack {
Text("Children")
.font(.title)
.fontWeight(.bold)
.padding(.leading, 24)
.padding(.top, 20)
Spacer ()
Image("User")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 36, height: 36)
.clipShape(Circle())
.offset(y: -55)
.padding(.trailing, 24)[final result][1]`

swiftui edgesIgnoreSafeArea only showing on canvas and not working on actual device

Im using .edgesIgnoringSafeArea(.top) to ignore the safe area on the top. this seems to work, and show the image going over the safe area on the top as expected on the canvas. But when I run this on a iPhone 11 plus simulator or iPhone x device (i also tested on other devices on the simulator) it doesn't seem to ignore the edges.
I have tried excluding:
.navigationBarTitle("")
.navigationBarBackButtonHidden(true)
But I need the above so I can use a custom back button.
var body: some View {
VStack (alignment: .leading ) {
Image("user1")
.resizable()
.frame(width: (UIScreen.main.bounds.width), height: ((UIScreen.main.bounds.height) / 2) + 50)
ScrollView {
HStack {
Text("\(userData.username), 30")
.fontWeight(.semibold)
.font(.system(.largeTitle, design: .rounded))
.padding([.leading,.top])
Spacer()
Image(systemName: "paperplane")
.aspectRatio(contentMode: .fill)
.frame(width: 65, height: 65)
.background(Color("message-background"))
.foregroundColor(.white)
.cornerRadius(25)
.font(.system(size: 25))
.padding(.top)
}.padding(.trailing)
HStack {
Text("Singer, London")
.fontWeight(.light)
.padding([.leading])
Spacer()
}
HStack {
Text("all the bio info will go there all the bio info will go thereall the bio info will go thereall the bio info will go there all the bio info will go there.")
.fontWeight(.light)
.padding([.leading])
.padding(.top)
.frame(width: (UIScreen.main.bounds.width - 20))
Spacer()
}.padding(.bottom,50)
}
}.edgesIgnoringSafeArea(.top)
.navigationBarTitle("")
.navigationBarBackButtonHidden(true)
.navigationBarItems(leading: Button(action: {
self.presentationMode.wrappedValue.dismiss()
}){
Image(systemName: "arrow.left")
.aspectRatio(contentMode: .fill)
.frame(width: 40, height: 40)
.background(Color("message-background"))
.foregroundColor(.white)
.cornerRadius(15)
.font(.system(size: 15))
.padding(.top,20)
})
}
Your code works for me on the simulator as expected. I just added the Text "This works" to demonstrate it:
So your problem must be somewhere outside the code which you presented in your question.

SwiftUI button image inset

Is there same thing as ImageEdgeInsets for SwiftUI. For example I have button 60x60. And want to make inset for image inside.
VStack(alignment: .leading, spacing: 0.0){
Section{
Button(action: {
if self.accountViewModel.signInContext == .quote{
self.presentationMode.wrappedValue.dismiss()
}else{
self.viewController?.dismiss(animated: true)
}
}){
Image("Close Icon").renderingMode(.template).padding(.vertical, 20).padding(.horizontal, 20).foregroundColor(.white).scaledToFit()
}
.frame(width: 60, height: 60)
Rectangle().line().padding(.horizontal, -30)
}
}
Yes, .padding is for that purpose, just needed to make image resizable. I suppose you need the following
Image("Close Icon")
.renderingMode(.template)
.resizable()
.aspectRatio(contentMode: .fit)
.padding(.vertical, 20).padding(.horizontal, 20)