I need to make my image jump and move down with animation. I am using sprites to show the jump animation. But, when I try to combine it with move down animation, it does not work. I am trying it on click of a button. Below is my code.
My animation works properly for second click but for first click it just jumps at its current location and at second click it jumps and moves down. I am trying to make it jump and move down at first button click.
#IBAction func targetTouchAction(_ sender: Any) {
let images: [UIImage] = (1...10).map { return UIImage(named: "Jump_\($0)")! }
self.jackImage.frame.origin.y = self.jackImage.frame.origin.y + 100.0
self.jackImage.animationImages = images
self.jackImage.animationDuration = 2.0
self.jackImage.animationRepeatCount = 1
self.jackImage.startAnimating()
}
I am trying this from last two three hours but no luck.
You are mixing 2 different types of animation. Don't do that. Using the animationImages property of a UIImageView is separate from using UIView animation methods like UIView.animate(duration:animations:)
Get rid of that UIView animation wrapper, and just specify the animation images and other settings for your image view:
#IBAction func targetTouchAction(_ sender: Any) {
let jumpImages = ["Jump_1","Jump_2","Jump_3","Jump_4","Jump_5","Jump_6","Jump_7","Jump_8","Jump_9","Jump_10"]
var images = [UIImage]()
for image in jumpImages{
images.append(UIImage(named: image)!)
}
self.imageView.frame.origin.y = self.imageView.frame.origin.y + 100.0
self.imageView.animationImages = images
self.imageView.animationDuration = 2.0
self.imageView.animationRepeatCount = 1
self.imageView.startAnimating()
}
Note that loading the array of images into the image view each time you trigger the animation is unnecessary, but it should still work.
I haven't worked with SpriteKit, so I'm not sure how your image view animation will interact with that. (Plus you didn't show that part of your code.)
Also, note that you could create your array of images with 1 line of code, and without using a hard-coded array of filenames:
let images: [UIImage] = (1...10).map { return UIImage(named: "Jump_\($0)") }
That code creates a sequence from 1 to 10. It then uses the map statement to map that sequence into an array of images by feeding the value into a string, and using that string as the image name in a call to UIImage(named:)
Related
I am trying to make a simple game with Xcode 11.2 which contains an animated loop background and a view which shows and changes various animations from several Lottie JSON files in project.
When I click the "Next" button to change the view animation, background view which is looping gets stuck for a second until the next animation inside the view is loaded an everything in the app freezes at the same time just like the background animation.
CPU usage varies from 30% to 63%.
I don't like to complicate the question, so I am just showing the way I used Lottie.
#IBAction func SubmitButtonAction(_ sender: UIButton) {
showNextQuestion()
}
func showNextQuestion()->(){
myTimer.invalidate()
startCountdown(fromTime: 15)
Manager.generateQuestion()
lblLevel.text = String(Manager.questionNumber) + "/" + String(DataModel.Questions.count)
nIndex = 0
let animation = AnimationView(name: Manager.currentImage)
animation.loopMode = .loop
animation.play()
animation.backgroundColor = UIColor.clear
animation.frame = self.AnimView.bounds
animation.backgroundBehavior = .pauseAndRestore
if AnimView.subviews.isEmpty{
self.AnimView.addSubview(animation)
}
else {
for one in imgImageView.subviews{
one.removeFromSuperview()
}
self.AnimView.addSubview(animation)
}
AnswerCollectionView.reloadData()
RandomCollectionView.reloadData()
}
I am interested in suggestions as to what the problem is related to - could it be related to a threading issue?
In response to Jaseel.Dev, I created a function that returned a LottieView with the following:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
withAnimation(.spring()) {
LottieView(name: animation)
}
}
I have a car image and I wanted just the rear wheels to spin when the image is pressed. Is it possible to select a portion of the image to animate? I was thinking of uploading 2 images, the car and wheel, since the car does not need to move yet. I was hoping there was a cleaner way to do this.
Any suggestions would be great thanks !
Add following extension : (If you don't know ->What is Extension? How to Add Extension? click question hyperlink.)
extension UIView {
func rotate360Degrees(duration: CFTimeInterval = 2) {
let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation")
rotateAnimation.fromValue = 0.0
rotateAnimation.toValue = CGFloat(Double.pi * 2)
rotateAnimation.isRemovedOnCompletion = false
rotateAnimation.duration = duration
rotateAnimation.repeatCount=Float.infinity
self.layer.add(rotateAnimation, forKey: nil)
}
}
Usage :
override func viewDidLoad() {
super.viewDidLoad()
carFirstWheelImage.rotate360Degrees()
carSecondWheelImage.rotate360Degrees() // you can change the time interval to change speed
}
Suggestion:
You can also change the Background with multiple image changing. That will give your car a running animation look. That will make your story more awesome !
Using code found in another post on here, I was able to programmatically draw and erase a subview, including location, width, and height, as shown in func addLoadButton and func removeSubview below. I have also figured out how to programmatically draw a picture on the main View Controller, as shown in func trailerLoadImage below. However, after many hours and attempts, I have tried to programmatically add and remove images into that subview without success.
My end goal is to be able to press three different trailer load type buttons to insert three different images (button 1 loads image 1, button 2 loads image 2, etc.) in a subview located in a specific location on the screen, and to be able to remove the images one at a time (may not be in order put on screen) by tapping on the images with a finger. The subview can be permanent or can be created and removed programmatically (as used below).
What code would I use to insert an image or multiple different images into a subview that has already been created, to remove the image(s) in the reverse order added, and to clear all images out of the subview? If this can’t be done, an acceptable alternative would be the ability to remove the image from the main VC by either tapping on it or pressing a button to clear all added images.
//Class declaration
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate {
//Boolean to include load type one in calculations
var trailerLoad : Bool = false
var trailerLoadDistanceFromFront = 20
//Boolean to include load type two in calculations
var trailerLoadTwo : Bool = false
var trailerLoadTwoDistanceFromFront = 80
//Boolean to include load type three in calculations
var trailerLoadThree : Bool = false
var trailerLoadThreeDistanceFromFront = 120
var trailerLoadWidth : Int = 0
var trailerLoadX : Int = 0
//Boolean true only when subView on trailer is active
var subViewActive : Bool = false
override func viewDidLoad() {
super.viewDidLoad()
//Picker view data sources and delegates included in here and work fine
}
//Adds subview for loads
#IBAction func addLoadButton(_ sender: Any) {
let trailerLoadView: UIView = UIView(frame: CGRect(x: 252, y: 233, width: 378, height: 100))
trailerLoadView.backgroundColor = .blue
trailerLoadView.alpha = 0.5
trailerLoadView.tag = 100
trailerLoadView.isUserInteractionEnabled = true
self.view.addSubview(trailerLoadView)
subViewActive = true
}
//If subViewActive is true, calls alert to get distance load type one is from front, moves on to insert and position image, changes trailerLoad bool to true
#IBAction func trailerLoadOneButton(_ sender: Any) {
//If subViewActive is true:
//Calls alert to get distance load type one is from front, puts in var trailerLoadDistanceFromFront
//Calls trailerLoadImage() to insert and position load type one image
//Changes bool trailerLoad to true
//If subViewActive is false:
//Calls alert to tell user that they need to click Add Load button (create subview) before adding load types one, two, or three
}
//Add trailer load type one image, scales and positions it relatively accurately in view.
//To be duplicated and modified for load types two and three in the future, with different images (trailerLoadTypeTwoPic and trailerLoadTypeThreePic)
func trailerLoadImage() {
trailerLoadWidth = 378 * 60 / trailerTotalLength
trailerLoadX = 378 * trailerLoadDistanceFromFront / trailerTotalLength
let imageView = UIImageView(frame: CGRect(x: (252 + trailerLoadX), y: (333 - trailerLoadWidth), width: trailerLoadWidth, height: trailerLoadWidth));
let image = UIImage(named: “trailerLoadTypeOnePic”);
imageView.image = image;
self.view.addSubview(imageView)
}
//Calls func removeSubview to remove subview
#IBAction func resetButton(_ sender: Any) {
removeSubview()
}
//Removes subview for loads
#objc func removeSubview(){
subViewActive = false
if let viewWithTag = self.view.viewWithTag(100) {
viewWithTag.removeFromSuperview()
}else{
print("No!")
}
}
}
Thank you very much to anybody that offers assistance or advice.
Don't use tags! Just create variables in global scope for your views
var imageViews = [UIImageView]()
then when you need to add them first append them to your array and then add them to view
imageViews.append(imageView)
view.addSubview(imageView)
Then when you need to remove your all views from their superview, use method removeFromSuperview() for each view in array
imageViews.forEach { $0.removeFromSuperview() }
imageViews.removeAll()
or if you need to remove just one view at specific index
imageViews[index].removeFromSuperview()
imageViews.remove(at: index)
I have a XCUI test case in swift where I am trying to determine if a cell has scrolled off screen. However, I've noticed that once a cell has been on screen the static text is always findable, even when the cell scrolls off screen, when using
XCTAssertTrue(app.tables.cells.StaticText["person"].exists)
This also does not work for me
let window = app.windows.elementBoundByIndex(0)
let element = app.tables.cells.staticTexts["person"]
XCTAssertTrue(CGRectContainsRect(window.frame, element.frame))
As that second test will pass, even when the cell has scrolled off screen.
Is there a way to determine whether a table cell is no longer within the view on the screen?
Use the hittable API on XCUIElement to determine if an element both exists and is on screen. You should use it on the cell.
Note: hittable will become isHittable in Swift 3.
let cell = app.tables.cells.containingType(.StaticText, identifier: "person").elementBoundByIndex(0)
XCTAssertTrue(cell.hittable)
A solution to this problem, kind of clunky but works, is that I used a function like this
func tapOnSpecifiedPointOnList(cellNumber: Float) {
let cellSpacing: Float = 75
let xCoordinate: Float = 25
let yOffSet: Float = 90
let yCoordinate = yOffSet + (cellSpacing * cellNumber)
let pointToTap = CGPointMake(CGFloat(xCoordinate), CGFloat(yCoordinate))
map().tapAtPosition(pointToTap)
}
tapOnSpecifiedPointOnList(0)
let startingCell = app.cells.otherElements["callout"].elementBoundByIndex(0).label
app.cells.otherElements["callout"].swipeUp()
for i in 0...numberOfCells {
tapOnSpecifiedPointOnList(i)
let nextCell = app.cells.otherElements["callout"].elementBoundByIndex(0).label
XCTAssertNotEqual(startingCell, nextCell)
}
When a cell was tapped, it opened up a separate callout, which didn't exist before. By attaching an accessibilityId on this callout object, I was able to grab the info from the cell and compare it to other cells which I tapped on. Therefore, if I tapped on all possible cell locations on screen, and none of callouts matched the original, it must have gone offscreen.
On a viewcontroller I have 101 buttons. If one of the first 100 buttons is pressed, I want to change the image of button number 101 ( I have 100 images in this project; image1,image2,image3 etc.)
So I have done this by giving every button a tag from 0-100 and then make a switch statement based on sender.tag
#IBOutlet weak var button101 : UIButton!
var i = 1
// I hooked up all the other 100 buttons to a single IBAction
#IBAction func buttonTapped(sender: UIButton) {
switch sender.tag {
case 0: i = 1
let image = UIImage (named: "image\(i)")
button101.setImage(image, forState:.Normal)
case 1: i = 2
let image = UIImage (named: "image\(i)")
button101.setImage(image, forState:.Normal)
case 2: i = 3
let image = UIImage (named: "image\(i)")
button101.setImage(image, forState:.Normal)
case ..: // etc. until case 99 (because button 100 has tag 99)
default: break
This super ugly code works: It changes the image of button number 101 into the specified image(i). But I want a more elegant and better solution.
I have 2 questions:
How to initialise the 'image' constant/variable in a better way (outside the IBAction)?
What kind of (loop)statement to use instead of this large switch statement?
So: I want to determine which button is pressed, then update the value of var i, loop through the images and find and update the image of button101 with the image(i).
I hope my questions are clear. Please let me know if they are not.
Help is much appreciated!
Your switch statement acts the same as:
if sender.tag < 100 {
let image = UIImage (named: "image\(sender.tag + 1)")
button101.setImage(image, forState:.Normal)
}
You can put your UIImage at the top of your ViewController with var UIImage: UIImage! if you want to, but I do not see any reason to do this.