Why is happening this weird behaviour between Animations and HorizontalMotionEffects? - swift

I was testing out some code and ended up with this piece of code:
import UIKit
class ViewController: UIViewController {
#IBOutlet var backgroundImageView: UIImageView!
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
hideAndShow()
}
func hideAndShow(){
self.backgroundImageView.alpha = 0
UIView.animateWithDuration(1.0, delay: 0, options: .Repeat | .AllowUserInteraction | .Autoreverse | UIViewAnimationOptions.CurveEaseOut, animations: { [weak self] in
self?.backgroundImageView.alpha = 1
}, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
self.backgroundImageView.contentMode = UIViewContentMode.Center;
self.backgroundImageView.backgroundColor = UIColor(patternImage: UIImage(named: "640x1136launch")!)
self.addParallaxEffectToView(self.backgroundImageView)
self.backgroundImageView.frame = CGRectInset(self.backgroundImageView.frame, -50, -50);
}
func addParallaxEffectToView(view: UIView ) {
// Set vertical effect
var verticalMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.y", type: UIInterpolatingMotionEffectType.TiltAlongVerticalAxis)
verticalMotionEffect.minimumRelativeValue = -50
verticalMotionEffect.maximumRelativeValue = 50
// Set horizontal effect
var horizontalMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.x", type: UIInterpolatingMotionEffectType.TiltAlongHorizontalAxis)
horizontalMotionEffect.minimumRelativeValue = -50
horizontalMotionEffect.maximumRelativeValue = -50
// Create group to combine both
var group = UIMotionEffectGroup.new()
group.motionEffects = [horizontalMotionEffect, verticalMotionEffect]
// Add both effects to your view
view.addMotionEffect(group);
}
}
What this code was supposed to do is to make a blinking effect over an UIImage that I have on my UIViewController.
This image also has an UIMotionEffect (tilt in this case) that works perfect to me when tilting the device vertically but for some reason does not work when my device is tilted horizontally.
Nevertheless, the point is that when I call to my hideandShow() function, my view starts to blink, but also, at the same pace,..starts to move horizontally!!!
Why is this happening? I'm out of ideas.

Related

How do I enable a .jpg image to fade in, in swift uiKit

Good evening.
I downloaded a .jpg image and attached it through storyboard, and linked it to Home.swift. At this point, when I run the simulator the image is there. It does nothing at this time, but it's there.
I am trying to modify the code so that the image fades in when the simulator first runs. However, swift isn't liking my approach.
Much appreciate any guidance.
import Foundation
import UIKit
class Home: UIViewController {
#IBOutlet var lonelinessLbl: UILabel!
#IBOutlet var Image: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
startAnimations()
// Do any additional setup after loading the view.
}
func startAnimations() {
Image.animationImages = [
UIImage(named: "birds.jpg")]
Image.animationDuration = 3
Image.startAnimations()
}
}
Inside startAnimations:
imageView.image = UIImage(named: "birds.jpg")
imageView.alpha = 0
UIViewPropertyAnimator(duration: 5.0, curve: .easeIn) {
self.imageView.alpha = 1.0
}.startAnimation()
(Note that I've renamed Image to imageView -- the Swift convention is to name variables in camel case, starting with a lowercase letter)
You can set the image to image view with animation.
Use the extension to apply animation anywhere.
extension UIImageView{
func setAnimatedImage(_ image: UIImage?) {
UIView.transition(with: self, duration: 0.5, options: .transitionCrossDissolve, animations: {
self.image = image
}, completion: nil)
}
}
Usage
yourImageView.setAnimatedImage(UIImage(named: "birds.jpg"))
Setting an image array to animationImages only helps you when you have a set of images to animate it like a gif.
If you want to present animation like increasing alpha you can do the following.
override func viewDidLoad() {
super.viewDidLoad()
Image.alpha = 0.0
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UIView.animate(withDuration: 0.3,
animations: {
self.Image.alpha = 1.0
},
completion: nil)
}

How to make scrollview scroll separately to its content height in swift

I have view hierarchy like below in storyboard
here for content main constrains top = 0, leading = 0, trailing = 0, bottom = 0
here for scrollview constrains top = 0, leading = 0, trailing = 0, bottom = 0
here for View constrains top = 0, leading = 0, trailing = 0, bottom = 0
for ContentView constrains top = 0, leading = 0, trailing = 0
for TblReview constrains top = 0, leading = 0, trailing = 0, bottom = 20
for Productcollectionview constrains top = 0, leading = 0, trailing = 0, bottom = 20, height = 400
and i have Productcollectionview height outlet like below in swift file
and i don't want collectionview separate scrolling.. i want total view to scroll according to collectionview cells.. so for that i have written below code but with this code contentView and tblReview also scrolling upto productioncollectionview height i need contentView should scroll upto its content height and tblReview should scroll upto its rows
how to make scrolling separately to its height.
please help me to solve this issue
#IBOutlet weak var productCollHeight: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
productCollectionView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
let collectionView = object as? UICollectionView
if collectionView == self.productCollectionView{
if(keyPath == "contentSize"){
if let newvalue = change?[.newKey]
{
let newsize = newvalue as! CGSize
self.productCollHeight.constant = newsize.height
}
}
}
}
#IBAction func aboutCompany(_ sender: UIButton){
self.productCollectionView.isHidden = true
self.tblReview.isHidden = true
self.contentView.isHidden = false
}
#IBAction func review(_ sender: UIButton){
self.productCollectionView.isHidden = true
self.tblReview.isHidden = false
self.contentView.isHidden = true
}
#IBAction func productOfSeller(_ sender: UIButton){
self.productCollectionView.isHidden = false
self.tblReview.isHidden = true
self.contentView.isHidden = true
}
and i am hiding and showing tblReview and contentView according to need
with the above code tblReview and contentView are also scrolling upto productCollectionView height.. please help me to solve this error
EDIT: share this seller is out of scrollview so here contentView height is not not so long but if i scroll the contentView also scrolling too long like productioncollectionview
this is contentView which is scrolling too long like productioncollectionview
if your all constraint are proper than just use it like this you don't need to count every time. UICollectionView has intrinsicContentSize it will count it properly.
final class ContentSizedCollectionView: UICollectionView {
override var contentSize:CGSize {
didSet {
invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
layoutIfNeeded()
return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
}
}
put that code in controller or wherever you wan to put and assign ContentSizedCollectionView class to your collectionview.
NOTE: you can also use it with UITableView after creating for UITableView.

Adding Progress bar - Swift

I want to add a Progress bar to a tableViewController.
I have one function called HelpersFunctions which do all the calculation.
The function doCalculation is responsible for the calculation.
So, I add the following notification to doCalculation as follow:
NotificationCenter.default.post(name: .return_progress, object: self)
for i in 1...n1 {
//Do all the calculation
}
So, once I reach NotificationCenter.default.post, it will move to a Tableview Controller called CreateNewElementVC
now, inside the ViewDidLoad, I added the following line:
//progress
NotificationCenter.default.addObserver(self, selector: #selector(showProgress), name: .return_progress, object: nil)
In the same swift file, I added the following:
let container_elementProperty: ProgressBarView = {
let view = ProgressBarView()
view.backgroundColor = UIColor(white: 0, alpha: 0.5)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
#objc func showProgress() {
if(progressCounter > 1.0){timer.invalidate()}
print("Step 1")
container_elementProperty.frame = CGRect(x: 100, y: 100, width: 200, height: 200)
container_elementProperty.backgroundColor = UIColor(white: 0, alpha: 0.5)
container_elementProperty.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleDismiss)))
let queue = DispatchQueue(label: "queue1", qos: .userInteractive)
queue.async {
print("Step 2")
self.view.addSubview(self.container_elementProperty)
}
//view.addSubview(container_elementProperty)
print("Step 3")
container_elementProperty.progress = progressCounter
progressCounter = progressCounter + progressIncrement
let x1: Float = Float(start_Counting)
let x2: Float = Float(End_Counting)
let xx: Float = x1 / x2 * 100
print("Start at: \(xx) %)")
}
So, first I put all the required data in the CreateNewElementVC, then there is a button called run to do all the calculation and then it will move to another TableViewController with all the result.
So while I am inside the function doCalculation, the progress bar should appear .
In fact, the Progress bar container_elementProperty (UIview) appeared just after the calculation is completed which make the progress bar is useless.
Any idea how to make the View called container_elementProperty UIView to be seen ?
I am close to solve this issue as I can see the progress in the stack as below image, I just want to show this on the screen before completing the calculation.
Why I am not able to put the view on the screen while doing the calculation as you can see that step 2 ran first.
The warning related to this issue is: UIView.addSubview(_:) must be used from main thread only.
A Sample Project can be checked on this link at github.
Appreciate any kind of support.
To simulate a progress, such as a network request you cannot simply do a for loop in the main thread, you should use GCD.
To update the progress of an ongoing action use Delegation, not KVO.
Using global variables makes your code flawed, avoid it!
This is a working version of your code.
# Write By Tushar on 11/02/2021#
import UIKit
class ViewController: UIViewController {
let totalValue:Float = 80.0
var firstNumber:Int? = 0
#IBOutlet weak var progressBar: UIProgressView!
override func viewDidLoad() {
super.viewDidLoad()
progressBar.trackTintColor = .white
progressBar.tintColor = .red
// Do any additional setup after loading the view.
progressBar.setProgress(0.0, animated: false)
}
func setProgress(firstValue:Float){
let processValue = firstValue/totalValue
progressBar.setProgress(processValue, animated: true)
}
#IBAction func btnResetClick(_ sender: UIButton) {
print("Reset Button Clicked")
firstNumber = 0
progressBar.setProgress(0.0, animated: false)
}
#IBAction func btnShowProgressClick(_ sender: UIButton) {
guard let presentValue = firstNumber else { return }
let newValue = presentValue + 1
firstNumber = newValue
setProgress(firstValue: Float(firstNumber!))
}
}

animation: stop reset position of an element (swift)

I'm trying animations and I'm facing a big problem: when my animation finished and I do something ( touch the screen, etc), the elements reset their positions to their first position.
I found this: [blog]: Animation Blocks resets to original position after updating text
they say it's because elements have constraints or auto layout so turn it off to fix it but I don't want to turn it off.
Can we update constraints programmatically?
is there an other solution?
here's my animation:
#IBOutlet var tfUser: UITextfiled!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
tfUser.center.x += view.bounds.width
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
UIView.animateWithDuration(2, delay: 1.8, options: [.CurveEaseInOut], animations: {
self.tfUser.center.x += self.view.bounds.width
//self.tfUser.frame = CGRectMake(0, 233, 375 , 89)
// i tried CGRectMake but it delete the animation
}, completion: nil)
}
In comment of my question , #Hardik Shekhat told to use :
self.tfUser.translatesAutoresizingMaskIntoConstraints = true
it works for me !

Detect if user is moving finger left or right (Swift)

This is not Sprite Kit.
If I have a variable like the one below
var value = 0
How am I able to increase the value if the user drags right and decrease if they drag left?
Thanks!
Like Caleb commented, Ray's tutorial is great, but if you want the actual swift example, please check the next example:
class ViewController: UIViewController, UIGestureRecognizerDelegate {
private var value: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.blackColor()
let recognizer = UIPanGestureRecognizer(target: self, action: Selector("handleDragging:"))
let inputView = UIView(frame: CGRectMake(0, 0, 100, 100))
inputView.backgroundColor = UIColor.whiteColor()
inputView.userInteractionEnabled = true
inputView.addGestureRecognizer(recognizer)
self.view.addSubview(inputView)
}
func handleDragging(recognizer: UIPanGestureRecognizer) {
if (recognizer.state == .Changed) {
let point = recognizer.velocityInView(recognizer.view?.superview)
if (point.x > 0) {
self.value++;
} else {
self.value--;
}
println(self.value)
}
}
}
You can use the velocityInView method of UIPanGestureRecognizer to determine which direction you're going. It returns a CGPoint, so you can pull out the x and y values as you wish. Positive is right/down, negative is left/up.