I'm wondering what is the best way for me to record sound while the user is holding down a UIButton. (i.e. start when the user is holding down and stop when he releases the button). Will something like this work?
Function call
button.addTarget(self, action: "holding:", forControlEvents: .TouchDown)
Function:
func holding (sender:UIButton!) {
// Sound recording code here
}
Also I'm trying to update a UIProgressView as the sound is recorded. Is there a way I can access the amount of time (in seconds / milliseconds) that has elapsed since the recording has started? Can I just use my own timer or will there be some dependency?
I had a similar requirement recently, and instead of using a UIButton I used a regular view (UILabel,UIImageView or whatever you want the 'button' to look like) with a UILongPressGestureRecognizer added. The gesture recognizer's target function can then stop/start recording as needed:
func holding (sender:UILongPressGestureRecognizer!) {
// If the gesture state is UIGestureRecognizerStateBegan start recording
// If it is UIGestureRecognizerStateEnded stop recording
}
Related
I'm using a simple turn based loop, switching between player turn and enemy turn. In the player turn the loop should "pause" until framework function touchDown has been activated, then pass the turn to the enemy. I'm not sure how to implement this as touchDown triggers automatically whenever you press the screen.
Am I to use an observer of some sort or a #selector? Tried both unsuccessfully, but that may just be for my lack of experience. If I use the selector the loop doesn't pause to wait for the screen to be clicked. As for the observer, I'm just not sure how its implemented. I also tried just adding the whole touchDown method into the player turn but that obviously didn't work.
The loop simply looks like this:
var state = "PLAYER"
func runGame() {
while(gameIsProgressing) {
if(state == "PLAYER") {
print("Player is doing stuff")
//THE touchDown METHOD SOULD BE TRIGGERD HERE
state = "ENEMY"
}else if(state == "ENEMY") {
print("\n🙈ENEMY IS DOING STUFF🙈")
state = "PLAYER"
}
}
}
Also, it is important that touchDown is triggerd only in the player turn, and not whenever the screen is pressed.
Any ideas?
Since you are programming something with a GUI here, you should not think in this imperative way. There is no (good) way to "pause" a while loop "until" something happens. You should think in a more event-driven way.
Instead of thinking about the while loop, think in terms of the events that happen. In this case, the event is touchDown. Note that I don't know of a library function called touchedDown (did you mean touchesBegan or is this an action for a UIControl?), but I'll assume it exists. When the player touches the screen, what do you want to happen? Well, probably something like this:
guard gameIsProgressing else { return }
if(state == "PLAYER") {
someFunctionThatShowsWhatThePlayerDid()
state = "ENEMY"
print("\n🙈ENEMY IS DOING STUFF🙈")
someFunctionThatMakesTheEnemyDoStuff(completion: {
self.state = "PLAYER"
})
}
Extreme noob here just getting into Swift and iOS development.
I have already created the basic design for my app in storyboard and inserted some basic code.
Right now I want to do the following but am pretty stuck.
Record the time between an event happening on screen and touch input from the user.
So basically, the even happens on screens and sets off a timer, the timer stops when the user touches the screen and records the value.
Any help will be extremely appreciated.
Use following code to get interval between two events.
let start = NSDate()
// do stuff...
let timeInterval = start.timeIntervalSinceNow()
When event started,(Use first line to record event begin time) you will obviously know. And the user when touches screen few delegate methods will be fired(Use second line here to know time interval). Below is the code for that.
let tap = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
view.addGestureRecognizer(tap)
view.userInteractionEnabled = true
self.view.addSubview(view)
func handleTap(_ sender: UITapGestureRecognizer) {
print("Hello World")
}
I am using Player library, that is using AVPlayer & AVFoundation, which is quiet convenient for my case. I successfully managed to play the video and add a slider. I set the slider's min to 0 and max to duration of the video..
At this point, in order to connect slider to current playtime, I used this answer, on StackOverflow. I setup a protocol and used addPeriodicTimeObserverForInterval, so slider is linked to the currentTime and moving as video moves along successfully.
Now, here is my problem. I want to do the reverse and make - when slider moves, set currentTime of the video (forward,backward).
I made some research and I found out that it's seekToTime that I should link the slider.value (sender.value in my case) but, I couldn't understand how to apply it to Player. How can I make the slider to control the currentTime?
I am not sure if I am right, but as far as I understand, the first step should be:
protocol UserSetsTheTimeDelegate
{
func userSetsTheTime(result: Int)
}
class ViewController: UIViewController, PlayerDelegate {
...
func sliderValueDidChange(sender:UISlider!) {
print("value--\(sender.value)")
self.delegate?.userSetsTheTime(sender.value)
}
}
And add, I think I should add the UserSetsTheTimeDelegate in Player.swift, but I got confused here.
Update:
I realised that I can send the data to the Player.swift by using an instance in ViewController and adding a method in Player class. This is the first step. But now, as currentTime is getting updated (with modifying the slider) so quickly, it doesn't let me manipulate the slider value.
It is preferable from an UX point of view to call the seek() method on your Player after a touchUp on your slider, rather than whenever the value changes.
As you noticed, you had poor experience with the sliderValueDidChange.
Instead, try by adding a target/action on UIControlEvents.TouchUpInside (for instance) on your slider, then only seek. The experience should be better.
var slider : UISlider! {
didSet {
slider.addTarget(self, action: Selector("touchUp:"), forControlEvents: [UIControlEvents.TouchUpInside])
}
}
func touchUp(sender:AnyObject?) {
// player.seek(slider.currentValue)
}
I solved my problem. I created an instance of Player so I was able to send the data from the view controller back to Player class. Then I simply applied seekToTime(). At this point, visually, it was seeming poor but then I noticed that I can use stop(), setCurrentTime() and then play() in order to make it look nicer.
Here's my code for the animation:
UIView.animateWithDuration(3,
animations: {self.redBar.center = CGPointMake(self.redBar.center.x + 600, self.redBar.center.y + 600)},
completion: nil)
I want to make it loop until I press a button. How?
Put the animation code inside of it's own function. Call that function in the completion block of the animation unless your button has been pressed.
When your button is pressed, set a boolean flag that keeps your animation from running again, then use this to cancel the animation that's in progress.
A nice solution here is to call your animation through a function accessed by a timer.
Here's a simple example of employing a timer:
How can I make a countdown with NSTimer?
Would probably be easiest to assign a boolean to stop the animation on button press. Assuming timer repeats was set to true (on declaration), now just call timer.invalidate() and your timer will no longer repeat calls to your animation.
I'm trying to adjust the position of my textField as I long-press my view, but for some reason the while-loop never stops running. My code looks like this:
func buttonLongPressed(gestureRecognizer:UIGestureRecognizer){
if textEdit.editing == true{
self.textEdit.endEditing(true)
}
while gestureRecognizer.state == UIGestureRecognizerState.Began{
println("BEGAN")
self.textEdit.frame = CGRectMake(0, gestureRecognizer.locationInView(self.view).y, self.view.frame.width, 44)
}
}
I don't understand why this shouldn't work, and how to do it in any other way.
Any suggestions would be appreciated.
The gesture recognizer calls your action method when its state changes--it's not valid to poll the state from a while loop, it will never change.
It probably works like this:
Events are sent from the touch screen with a signal to wake up your app.
The gesture recognizer looks at the queued events and decides to enter "Began" state.
The gesture recognizer code invokes your action method (buttonLongPressed)
Your code enters a while look and reads gestureRecognizer.state repeatedly.
You can see, if your action method never returns, the gesture recognizer will never wake up again and look at new input.
You can probably just change your function like this:
func longPressAction( g:UILongPressGestureRecognizer )
{
switch g.state
{
case: .Changed
{
// handle one drag update... but don't loop
}
}
}