I'm new to iOS app development and I'm trying to change the screen brightness but it happens pretty abruptly. Is there a way to animate the screen brightness smoothly?
Instead of a timer, a Swift extension:
extension UIScreen {
private static let step: CGFloat = 0.1
static func animateBrightness(to value: CGFloat) {
guard fabs(UIScreen.main.brightness - value) > step else { return }
let delta = UIScreen.main.brightness > value ? -step : step
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
UIScreen.main.brightness += delta
animateBrightness(to: value)
}
}
}
I guess you can set a re-occurring timer like so:
var timer = Timer.scheduledTimer(timeInterval: 0.05, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
And add the update method:
func update() {
UIScreen.main.brightness = UIScreen.main.brightness - CGFloat(0.1)
if UIScreen.main.brightness == CGFloat(0.5) { // or any brightness you want.
timer.invalidate()
}
}
Just play around with the timer interval and the brightness decreasing until you find what you are looking for.
Related
I am trying to set up a custom gesture over an Image in Xcode (Swift).
The gesture is about rubbing the image or tickling it continuously and accordingly firing my function in time interval while the finger is moving.
I would appreciate some help here.
thanks a lot.
//That's my idea, not tested
var time = 0.0
var timeInterval = 1.0
var everyTime = 0.1
func addPan() {
let imageView = UIImageView()
//imageView.frame = xxxx
let pan = UIPanGestureRecognizer(target: self, action: #selector(panGesture(gesture:)))
imageView.isUserInteractionEnabled = true
imageView.addGestureRecognizer(pan)
}
func panGesture(gesture : UIPanGestureRecognizer) {
if gesture.state == .changed, time >= timeInterval {
print("time interval is \(everyTime) every is \(everyTime)")
}
}
func addtimer() {
let timer = Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
RunLoop.current.add(timer, forMode: RunLoopMode.commonModes)
}
func timerAction() {
time += timeInterval
if time >= timeInterval {
time = 0.0
}
}
I want to move a UISlider from minValue to maxValue in a loop when you hit a button and stop it at the current position when hitting the button again, I want to use Swift.
The main problem i got is that the function slider.setValue() is way to fast, I want the animation more slowly.
#IBAction func setSliderValue(_ sender: UIButton){
slider.setValue(100, animated: true)
print("The value of the slider is now \(slider.value)")
sliderValue = Int(slider.value)
}
You can use time to Automatically Move slider.
Create NSTimer variable in global scope:
Also create one Bool variable in global scope for checking if Need to revise it.
var mytimer : NSTimer?
var reversing : Bool?
start timer when you want to animate it:
reversing = NO;
mytimer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
On tImer Action, You can write code to change value of Slider:
var sliderrange = slider.maxValue - slider.minValue;
var increment = sliderrange/100;
var newval = slider.value;
newel = reversing ? (slider.value - increment) : (slider.value + increment);
if(newval >= slider.maxValue)
{
reversing = true;
newval = newval - 2*increment;
}
else if(newel <= 0)
{
reversing = false;
}
slider.setValue(newval, animated: true)
On Button Action, You can just stop the timer,
if mytimer != nil {
mytimer!.invalidate()
mytimer = nil
}
This code is working, though the slider only moves from left to right, not from right to left when he reached maximumValue, it should move from left to right and then right to left until the invalidated.
#IBAction func setSliderValue(_ sender: UIButton){
mytimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
/*slider.setValue(100, animated: true)
print("The value of the slider is now \(slider.value)")
sliderValue = Int(slider.value)*/
}
func timerAction(){
let Range = slider.maximumValue - slider.minimumValue;
let Increment = Range/100;
let newval = slider.value + Increment;
if(Increment <= slider.maximumValue)
{
slider.setValue(newval, animated: true)
print("The value of the slider is now \(slider.value)")
sliderValue = Int(slider.value)
}
else if (Increment >= slider.minimumValue)
{
slider.setValue(newval, animated: true)
}
}
Ive created a timer in swift to move a UISlider from one end to another again and again when a button is pressed. But I'm always getting a breakpoint at the timer line, although everything should be right.
#IBAction func setSliderValue(_ sender: UIButton){
mytimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
}
func timerAction(){
let Range = slider.maximumValue - slider.minimumValue;
let Increment = Range/100;
let newval = slider.value + Increment;
if(Increment >= slider.maximumValue)
{
slider.setValue(newval, animated: true)
}
else
{
slider.setValue(0, animated: true)
}
}
The check of your function is incorrect.
func timerAction(){
let range = slider.maximumValue - slider.minimumValue
let increment = range/100
let newval = slider.value + increment
if newval <= slider.maximumValue {
slider.setValue(newval, animated: true)
} else {
slider.setValue(slider.minimumValue, animated: true)
}
}
Also, in your event handler, should invalidate the timer (if it's not nil) first before instancing a new one.
Its working now with the following code, though the slider is only moving from left to right until it gets invalidated.
#IBAction func setSliderValue(_ sender: UIButton){
mytimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
/*slider.setValue(100, animated: true)
print("The value of the slider is now \(slider.value)")
sliderValue = Int(slider.value)*/
}
func timerAction(){
let Range = slider.maximumValue - slider.minimumValue;
let Increment = Range/100;
let newval = slider.value + Increment;
if(Increment <= slider.maximumValue)
{
slider.setValue(newval, animated: true)
print("The value of the slider is now \(slider.value)")
sliderValue = Int(slider.value)
}
else if (Increment >= slider.minimumValue)
{
slider.setValue(newval, animated: true)
}
}
Hope this helps if someone else needs help on a task "starting a count down timer on a button click".
Timer itself has to be declared inside of the button code and additionally create a Obj-C function to update the timer that will be connected trough the #selector.
class ViewController: UIViewController {
var myTimer = Timer()
var secondsToCount = 100
#IBAction func buttonTapped(_ sender: UIButton) {
myTimer.invalidate()
myTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateTimer), userInfo: nil, repeats: true)
}
#objc func updateTimer() {
secondsToCount -= 1
timerDisplayed.text = String(secondsToCount)
}
}
timerDisplayed is a label that I connected to see the value of the timer on the screen of the app.
SWIFT 5.3 & Xcode 12.0.1
I'm having problem animate UISlider as a MPMusicPlayer playback progress. I've seen many post accomplishing this on obj-c and AVAudioPlayer.
I've tried this:
func startTimer(){
if timer == nil {
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("update:"), userInfo: nil,repeats: true)
timer.fire()
}
}
func stopTimer(){
timer.invalidate()
}
func update(timer: NSTimer){
if myMusicPlayer?.playbackState == MPMusicPlaybackState.Playing{
return
}
var minute_ = abs(Int((myMusicPlayer!.currentPlaybackTime / 60) % 60))
var second_ = abs(Int(myMusicPlayer!.currentPlaybackTime % 60))
var minute = minute_ > 9 ? "\(minute_)" : "0\(minute_)"
var second = second_ > 9 ? "\(second_)" : "0\(second_)"
progressTimerLabel.text = "\(minute):\(second)"
progressBar.value = CFloat(myMusicPlayer!.currentPlaybackTime)
}
ProgressBar is my UISlider.
I called startTimer() when I play the audio, but it still not animate at all. What can I do so it animate the UISlider?
I want to add a score to the top of my scene in the game I am working on. The score is going to based on how long you last, and will increase every second. Thanks for the help in advance!
import SpriteKit
class easyScene: SKScene {
let scrollBarEasyBottom = SKSpriteNode(imageNamed: "scrollBarEasyBottom")
let scrollBarEasyTop = SKSpriteNode(imageNamed: "scrollBarEasyTop")
let ball = SKSpriteNode(imageNamed: "ball")
var origSBEBpositionX = CGFloat(0)
var origSBETpositionX = CGFloat(0)
var maxSBEBX = CGFloat(0)
var SBEBSpeed = 5
var maxSBETX = CGFloat(0)
var SBETSpeed = 5
var score = 0
var timer: NSTimer?
var scoreText = SKLabelNode(fontNamed: "Kailasa")
override func didMoveToView(view: SKView) {
println("Easy Scene is the location")
self.backgroundColor = UIColor.blackColor()
self.scrollBarEasyBottom.position = CGPoint(x:0, y:270)
self.addChild(self.scrollBarEasyBottom)
self.scrollBarEasyBottom.yScale = 0.2
self.origSBEBpositionX = self.scrollBarEasyBottom.position.x
// end scrollBarEasyBottom
self.scrollBarEasyTop.position = CGPoint(x:20, y:400)
self.addChild(self.scrollBarEasyTop)
self.scrollBarEasyTop.yScale = 0.2
self.origSBETpositionX = self.scrollBarEasyTop.position.x
// end scrollBarEasyTop
self.ball.position = CGPoint(x:40, y:293)
self.addChild(self.ball)
self.ball.yScale = 0.17
self.ball.xScale = 0.17
// end ball
self.maxSBEBX = self.scrollBarEasyBottom.size.width - self.frame.size.width
self.maxSBEBX *= -1
self.maxSBETX = self.scrollBarEasyTop.size.width - self.frame.size.width
self.maxSBETX *= -1
//
self.scoreText.text = "0"
self.scoreText.fontSize = 60
self.scoreText.position = CGPoint(x: CGRectGetMidX(self.frame), y: 500)
self.scoreText.text = String(self.score)
self.addChild(self.scoreText)
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("scoreIncrease") , userInfo: nil, repeats: true)
func scoreIncrease (){
score++
println(score)
}
}
override func update(currentTime: NSTimeInterval) {
if self.scrollBarEasyBottom.position.x <= maxSBEBX + 1200 {
self.scrollBarEasyBottom.position.x = self.origSBEBpositionX
}
if self.scrollBarEasyTop.position.x <= maxSBETX + 1200 {
self.scrollBarEasyTop.position.x = self.origSBETpositionX
}
scrollBarEasyBottom.position.x -= CGFloat(self.SBEBSpeed)
scrollBarEasyTop.position.x -= CGFloat(self.SBETSpeed)
// moving bars
var degreeRotation = CDouble(self.SBEBSpeed) * M_PI / 180
self.ball.zRotation -= CGFloat(degreeRotation)
//rotate ball
}
}
After running this code, I always get an
unrecognized selector sent to instance error
You can use one like this:
var timer = NSTimer()
override func viewDidLoad() {
scheduledTimerWithTimeInterval()
}
func scheduledTimerWithTimeInterval(){
// Scheduling timer to Call the function "updateCounting" with the interval of 1 seconds
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("updateCounting"), userInfo: nil, repeats: true)
}
func updateCounting(){
NSLog("counting..")
}
Swift 3:
var timer = Timer()
override func viewDidLoad() { // Use for the app's interface
scheduledTimerWithTimeInterval()
}
override func didMove(to view: SKView) { // As part of a game
scheduledTimerWithTimeInterval()
}
func scheduledTimerWithTimeInterval(){
// Scheduling timer to Call the function "updateCounting" with the interval of 1 seconds
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.updateCounting), userInfo: nil, repeats: true)
}
#objc func updateCounting(){
NSLog("counting..")
}
Swift 5:
Note: this solution is compatible with iOS 10.0+.
// If needing to check for iOS compatibility use
// if #available(iOS 10.0, *) {code}
var timer = Timer()
override func viewDidLoad() {
self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { _ in
updateCounting()
})
}
func updateCounting(){
print("counting...")
}
You can then invalidate (stop) the timer using:
timer.invalidate()
There is something called NSTimer in swift which could solve your problem. I have given an example like how you can use it. Just customise it for your purpose.
var timer = NSTimer.scheduledTimerWithTimeInterval(1.0,
target: self,
selector: Selector("yourMethodToCall"),
userInfo: nil,
repeats: true)
Add this line to the place where you need to call your function repeatedly.
The 1.0 refers to 1 second.
Change the selector to call yourMethodName
repeats is set to true to call that function every second.
Try this out and let me know if your are stuck somewhere. Thanks.
Swift 3
find this solution it worked for me
weak var timer: Timer?
var timerDispatchSourceTimer : DispatchSourceTimer?
func startTimer() {
if #available(iOS 10.0, *) {
timer = Timer.scheduledTimer(withTimeInterval: 3, repeats: true) { [weak self] _ in
// do something here
}
} else {
// Fallback on earlier versions
timerDispatchSourceTimer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.main)
timerDispatchSourceTimer?.scheduleRepeating(deadline: .now(), interval: .seconds(60))
timerDispatchSourceTimer?.setEventHandler{
// do something here
}
timerDispatchSourceTimer?.resume()
}
}
func stopTimer() {
timer?.invalidate()
//timerDispatchSourceTimer?.suspend() // if you want to suspend timer
timerDispatchSourceTimer?.cancel()
}
// if appropriate, make sure to stop your timer in `deinit`
deinit {
stopTimer()
}
I prefer
var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (timer) in
// Do what you need to do repeatedly
}
}
To stop it:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if timer != nil {
timer?.invalidate()
timer = nil
}
}
Xcode 10.2 Swift 5:
override func viewDidLoad() {
super.viewDidLoad()
// ...
Timer.scheduledTimer(timeInterval: 8.0, target: self, selector: Selector(("your #obcj func name")), userInfo: nil, repeats: true)
}
//Anywhere in the same view controller to stop the loop:
Timer.cancelPreviousPerformRequests(withTarget: your #obcj func name())
I don't think you need NSTimer for this.
Since you are using SpriteKit, I am going to suggest simplest solution in my opinion:
Declare a variable var prevScoreCalcTime:TimeInterval = 0
Inside of update func in your GameScene set it up like below:
override func update(_ currentTime: TimeInterval) {
if currentTime - prevScoreCalcTime > 1 {
prevScoreCalcTime = currentTime
// Any function you put here will execute every second
}
}
Good luck!
// For running a piece of code every second
///Runs every second, to cancel use: timer.invalidate()
#discardableResult public static func runThisEvery(
seconds: TimeInterval,
startAfterSeconds: TimeInterval,
handler: #escaping (CFRunLoopTimer?) -> Void) -> Timer {
let fireDate = startAfterSeconds + CFAbsoluteTimeGetCurrent()
let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, fireDate, seconds, 0, 0, handler)
CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, CFRunLoopMode.commonModes)
return timer!
}