I am very new to Xcode, so this could be something very basic that i'm just not finding, but i'm trying to create an app that moves 2 images away from each other (at least one width away) when the user taps the screen, and then have the images return to their original positions when the user taps the screen again, however, i have been unable to find out how to move an image in a specific direction, a specific distance.
i'm also new to Stack Overflow, so i'm sorry if i'm doing something wrong
I am breaking the rules by giving up the answer when it appears you have not googled enough. The general rule is to show the code you have attempted and indicate what part you are having issues with.
The code below will achieve what you are attempting to do.
import UIKit
class slidingIamgesViewController: UIViewController {
#IBOutlet weak var topImage: UIImageView!
#IBOutlet weak var bottomImage: UIImageView!
var doubleTap: Bool! = false
//MARK: View LifeCycle
override func viewDidLoad() {
super.viewDidLoad()
let singleFingerTap = UITapGestureRecognizer(target: self, action: #selector(slidingIamgesViewController.handleSingleTap(_:)))
self.view.addGestureRecognizer(singleFingerTap)
}
// MARK: gestutre recognizer
func handleSingleTap(_ recognizer: UITapGestureRecognizer) {
if (doubleTap) {
UIView.animate(withDuration: 0.7, delay: 1.0, options: .curveEaseOut, animations: {
var basketTopFrame = self.topImage.frame
basketTopFrame.origin.y += basketTopFrame.size.height
var basketBottomFrame = self.bottomImage.frame
basketBottomFrame.origin.y -= basketBottomFrame.size.height
self.topImage.frame = basketTopFrame
self.bottomImage.frame = basketBottomFrame
}, completion: { finished in
print("Images Moved back!")
})
doubleTap = false
} else {
UIView.animate(withDuration: 0.7, delay: 1.0, options: .curveEaseOut, animations: {
var basketTopFrame = self.topImage.frame
basketTopFrame.origin.y -= basketTopFrame.size.height
var basketBottomFrame = self.bottomImage.frame
basketBottomFrame.origin.y += basketBottomFrame.size.height
self.topImage.frame = basketTopFrame
self.bottomImage.frame = basketBottomFrame
}, completion: { finished in
print("Images sperated!")
})
doubleTap = true
}
}
}
Make sure in your storyboard to added a Tap Gesture Recognizer.
Related
Currently I'm building a quiz app with the PanGestureRecognizer functional. The idea is that user can drag one of the answer option to 'questionMark' cell and drop it there. The app should be able to check whether a dropped answer option in the 'questionMark' cell is correct or not.
So here is the question: how can I write a user answerCheck function for this app?
Please see below the code and related screens from my app.
To do that per understanding the following steps should be executed:
1) check whether sender.currentImage intersected 'questionMark' cell (which is UIImageView by nature) or not (if yes, it means that an answer was submitted by user by adding answer option in the 'questionMark' cell).
2) 'correct answr' is the answer which equals to the prescribed 'correct' answer option, however it should be located in 'questionMark' cell. Consequently, app should check whether sender.currentImage equals to the correct answer or not. Of course further actions depends on user answer (correct or wrong).`import UIKit
Obviously my checking function does not work at all. There are even error from Xcode (because of different types 'Bool' and UIImage). So need help, please let me know if my post is not clear and additional comments are required.
class MainViewController: UIViewController {
#IBOutlet weak var questionImageView: UIImageView!
#IBOutlet weak var questionMarkView: UIImageView!
#IBOutlet weak var buttonLabel1: UIButton!
#IBOutlet weak var buttonLabel2: UIButton!
#IBOutlet weak var buttonLabel3: UIButton!
//This var was added to access 'TestBrain' struct and its functions
var testBrain = TestBrain()
override func viewDidLoad() {
super.viewDidLoad()
//GestureRecognizer->>>
buttonLabel1.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.handlePanGesture1)))
buttonLabel2.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.handlePanGesture2)))
buttonLabel3.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.handlePanGesture3)))
}
#IBAction func answerButtonPressed(_ sender: UIButton) {
let userAnswer = sender.currentImage!
let correctAnswer = buttonLabel3.imageView!.frame.intersects(questionMarkView.frame)
if userAnswer == correctAnswer {
print("Correct")enter image description here
} else {
print("Wrong")
}
}
// ObjC functions for GestureRecognizer #1 ->>>
#objc func handlePanGesture1(gesture1: UIPanGestureRecognizer) {
let answerOptionView1 = gesture1.view!
switch gesture1.state {
case .began, .changed:
let translation1 = gesture1.translation(in: self.view)
buttonLabel1.transform = CGAffineTransform(translationX: translation1.x, y: translation1.y)
case .ended:
if answerOptionView1.frame.intersects(questionMarkView.frame) {
answerOptionView1.frame = questionMarkView.frame
answerOptionView1.isUserInteractionEnabled = false
} else {
UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 1, options: .curveEaseIn, animations: {
self.buttonLabel1.transform = .identity
})
}
default:
break
}
}
// ObjC functions for GestureRecognizer #2 ->>>
#objc func handlePanGesture2(gesture2: UIPanGestureRecognizer) {
let answerOptionView2 = gesture2.view!
switch gesture2.state {
case .began, .changed:
let translation2 = gesture2.translation(in: self.view)
buttonLabel2.transform = CGAffineTransform(translationX: translation2.x, y: translation2.y)
case .ended:
if answerOptionView2.frame.intersects(questionMarkView.frame) {
answerOptionView2.frame = questionMarkView.frame
answerOptionView2.isUserInteractionEnabled = false
} else {
UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 1, options: .curveEaseIn, animations: {
self.buttonLabel2.transform = .identity
})
}
default: break
}
}
#objc func handlePanGesture3(gesture3: UIPanGestureRecognizer) {
let answerOptionView3 = gesture3.view!
switch gesture3.state {
case .began, .changed:
let translation3 = gesture3.translation(in: self.view)
buttonLabel3.transform = CGAffineTransform(translationX: translation3.x, y: translation3.y)
case .ended:
if answerOptionView3.frame.intersects(questionMarkView.frame) {
answerOptionView3.frame = questionMarkView.frame
answerOptionView3.isUserInteractionEnabled = false
} else {
UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 1, options: .curveEaseIn, animations: {
self.buttonLabel3.transform = .identity
})
}
default: break
}
}
}`
[1]: https://i.stack.imgur.com/UAFpS.jpg - this is screen of my project, if necessary I can provide you with the whole project itself.
I am trying to animate the stretch and shrink of a lightsaber in my app. Currently I have everything working except for the stretching/shrinking of the lightsaber.
Ideally, I would like to be able to have the bottom anchor of actual saber be flush below the top anchor of saber handle. I've been able to achieve somewhat well with Auto Layout constraints. However, I'm struggling to find the right code for animations. As you can see from my code, I have tried frame.size.height/width, however that only moves the frame of the saber (not the handle). The line with frame.size.height achieves what I want in terms of making it stretch/grow, but it's a very bootleg way of doing it.
The current frame.size.height/width method only shifts the images, how would I achieve the stretch/shrink capability? Is it possible to achieve it with the multiplier function from Auto Layout constraints?
#objc func lightsaberTapped() {
print("lightsaber open!")
if mainView.saberImage.isHidden == true {
mainView.saberImage.isHidden = false
UIView.animate(withDuration: 0.5, animations: {
self.mainView.saberImage.frame.size.height -= 500
// self.mainView.saberImage.frame.size.width += 20
}, completion: nil)
lightsaberModel.turnSaberOnAudio.play()
} else {
mainView.saberImage.isHidden = true
UIView.animate(withDuration: 0.5, animations: {
self.mainView.saberImage.frame.size.height += 500
// self.mainView.saberImage.frame.size.width += 20
}, completion: nil)
}
}
Your main issue is the frame animation while you have constraints, you need 1 of 2 or animate constrains or remove it and animate with frame property, in that case you need to make sure that your UIImageView is added with translatesAutoresizingMaskIntoConstraints = false
To animate width and height in Autolayout system you need to get the constraint reference as IBOutlet and animate the constant property inside an animation block,
this is a very small example
class ViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var imageHeightConstraint: NSLayoutConstraint!
#IBOutlet weak var imageWidthConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
#IBAction func action(_ sender: Any) {
UIView.animate(withDuration: 0.5, animations: {
self.imageHeightConstraint.constant = self.imageHeightConstraint.constant - 10
self.imageWidthConstraint.constant = self.imageWidthConstraint.constant - 10
self.view.layoutIfNeeded()
})
}
}
First add constraints for width and height
#IBOutlet weak var saberImageHeightConstraint: NSLayoutConstraint!
#IBOutlet weak var saberImageWidthConstraint: NSLayoutConstraint!
Try this to get animation while resize frame.
if mainView.saberImage.isHidden == true
{
mainView.saberImage.isHidden = false
self.saberImageHeightConstraint.constant -= 500
UIView.animate(withDuration: 0.5, animations: {
self.view.layoutIfNeeded()
self.viewDidLayoutSubviews()
}, completion: nil)
lightsaberModel.turnSaberOnAudio.play()
}
else
{
mainView.saberImage.isHidden = true
self.saberImageHeightConstraint.constant += 500
UIView.animate(withDuration: 0.5, animations: {
self.view.layoutIfNeeded()
self.viewDidLayoutSubviews()
}, completion: nil)
}
I'm a very new-to-code learner. I've been taking some online courses, and came across this project recently.
I basically copied the code as I saw it on the screen, as the project files weren't available to download.
The animation is supposed to bring the UILabels from outside the view and position them within the view.
What seems to happen however, is the labels are starting within the view screen and animate outward and beyond.
I've copied the project below. Any help is so very appreciated.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var helloWorld: UILabel!
#IBOutlet weak var secondLabel: UILabel!
#IBOutlet weak var hiddenLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
helloWorld.center.y -= view.bounds.height
secondLabel.center.y += view.bounds.height
hiddenLabel.alpha = 0.0
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
// Animate Hello World label
UIView.animateWithDuration(1.5, animations: {
self.helloWorld.center.y += self.view.bounds.height
}, completion: { finished in
self.secondAnimation()
})
// Animate background color change
UIView.animateWithDuration(2.0, delay: 1.5, options: [], animations: {
self.view.backgroundColor = UIColor.yellowColor()
}, completion:nil)
}
// Animate second Label
func secondAnimation() {
UIView.animateWithDuration(1.5, delay: 0.0, options: [], animations: { () -> Void in
self.secondLabel.center.y -= self.view.bounds.height
}, completion:nil)
}
func backgroundColor() {
UIView.animateWithDuration(2.5, animations: {
self.view.backgroundColor = UIColor.blackColor()
}, completion: nil)
UIView.animateWithDuration(1.0, delay: 1.5, options: [], animations: {
self.hiddenLabel.alpha = 1.0
}, completion:nil)
}
}
I would check hello world.center.y value in viewWillAppear, before you subtract the view.bounds.height. If center.y value is large and positive, then the subtraction might be setting the center.y value to be inside of the view. If this is the case, then you would want to change the subtraction in viewWillAppear to addition and then the addition in the viewDidAppear animation to subtraction.
I have a viewController where am showing image for adding the zooming functionality I added the scrollView in viewController and inside of ScrollView I added ImageView everything is working fine expect of one thing, am hiding, and showing the bars (navigation bar + tab bar) on tap but when hiding them my imageView moves upside see the below images
See here's the image and the bars.
Here I just tapped on the view and bars got hidden but as you can see my imageView is also moved from its previous place, this is what I want to solve I don't want to move my imageView.
This is how am hiding my navigation bar:
func tabBarIsVisible() ->Bool {
return self.tabBarController?.tabBar.frame.origin.y < CGRectGetMaxY(self.view.frame)
}
func toggle(sender: AnyObject) {
navigationController?.setNavigationBarHidden(navigationController?.navigationBarHidden == false, animated: true)
setTabBarVisible(!tabBarIsVisible(), animated: true)
}
any idea how can I hide and show the bars without affecting my other Views?
The problem is that you need to set the constraint of your imageView to your superView, not TopLayoutGuide or BottomLayoutGuide.
like so:
Then you can do something like this to make the it smootly with animation:
import UIKit
class ViewController: UIViewController {
#IBOutlet var imageView: UIImageView!
var barIsHidden = false
var navigationBarHeight: CGFloat = 0
var tabBarHeight: CGFloat = 0
override func viewDidLoad() {
super.viewDidLoad()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.hideAndShowBar))
view.addGestureRecognizer(tapGesture)
navigationBarHeight = (self.navigationController?.navigationBar.frame.size.height)!
tabBarHeight = (self.tabBarController?.tabBar.frame.size.height)!
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func hideAndShowBar() {
print("tap!!")
if barIsHidden == false {
UIView.animateWithDuration(0.5, delay: 0.0, options: .CurveEaseOut, animations: {
// fade animation
self.navigationController?.navigationBar.alpha = 0.0
self.tabBarController?.tabBar.alpha = 0.0
// set height animation
self.navigationController?.navigationBar.frame.size.height = 0.0
self.tabBarController?.tabBar.frame.size.height = 0.0
}, completion: { (_) in
self.barIsHidden = true
})
} else {
UIView.animateWithDuration(0.5, delay: 0.0, options: .CurveEaseOut, animations: {
// fade animation
self.navigationController?.navigationBar.alpha = 1.0
self.tabBarController?.tabBar.alpha = 1.0
// set height animation
self.navigationController?.navigationBar.frame.size.height = self.navigationBarHeight
self.tabBarController?.tabBar.frame.size.height = self.tabBarHeight
}, completion: { (_) in
self.barIsHidden = false
})
}
}
}
Here is the result:
I have created an example project for you at: https://github.com/khuong291/Swift_Example_Series
You can see it at project 37
Hope this will help you.
I'd like to animate an existing UIButton in swift, the goal is to let get the attention of the user to this button when he taps the view controller. The animation is supposed to start from the top in the view controller and go to the initial position of the button.
I did the following scenario but it's not working:
import UIKit
class ViewController: UIViewController {
#IBOutlet var dismissButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
dismissButton = UIButton()
var tapGesture = UITapGestureRecognizer(target: self, action: Selector("handleTapGesture:"))
view.addGestureRecognizer(tapGesture)
}
func handleTapGesture(tapGesture: UITapGestureRecognizer) {
println("tap")
UIView.animateWithDuration(2.0, delay: 0.5, usingSpringWithDamping: 0.2, initialSpringVelocity: 0.0, options: nil, animations: {
self.dismissButton.center = CGPoint(x: 200, y: 90 + 200)
}, completion: nil)
}
}
Any suggestion?
Thank you!
Step 1: Take IBOutlet of your Top Constraint of button
Step 2: Update your Constraint's constant by using constraintName.constant property
Step 3: In animation block type self.view.layoutIfNeeded()
Here is an simple example: https://stackoverflow.com/a/26040569/3411787