How to make table view to display like flip animation in all devices in swift 3? - ios

In all devices the table view needs to be display only 70% of the screen irrespective of all devices and it should need to display only from bottom to top with animation and if I select anywhere on screen it should go to below and hide with animation I tried but unable to implement it can any one help me how to implement this ?
Here is my code
#IBAction func addtoCartButtonAction(_ sender: Any) {
UIView.animate(withDuration: 0.5, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {
self.addToCartTableView.isHidden = false
self.addToCartTableView.delegate = self
self.addToCartTableView.dataSource = self
self.addToCartTableView.reloadData()
self.addToCartTableView.frame.origin.y = 200
}) { (Bool) in
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
UIView.animate(withDuration: 1, delay: 0.3, options: .autoreverse, animations: {
}) { (Bool) in
self.addToCartTableView.isHidden = true
}
}
#IBAction func AddtoCartTableViewCloseButtonAction(_ sender: Any) {
self.addToCartTableView.isHidden = true
}

For this you can use CGAffineTransform.
For example :
in viewWillAppear() do this :
addToCartTableView.alpha = 0.0
addToCartTableView.transform = CGAffineTransform(translationX: addToCartTableView.bounds.origin.x, y: self.view.bounds.height)
And in you button action addtoCartButtonAction do this :
UIView.animate(withDuration: 0.5, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {
self.addToCartTableView.delegate = self
self.addToCartTableView.dataSource = self
self.addToCartTableView.reloadData()
self.addToCartTableView.transform = .identity
self.addToCartTableView.alpha = 1.0
}) { (Bool) in
}
And a tap gesture to your view and whenever you want to hide it again do this :
UIView.animate(withDuration: 0.5, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {
self.addToCartTableView.transform = CGAffineTransform(translationX: addToCartTableView.bounds.origin.x, y: self.view.bounds.height)
self.addToCartTableView.alpha = 0.0
}) { (Bool) in
}
Also you should not assign self.addToCartTableView.delegate = self self.addToCartTableView.dataSource = self in button action. Do that in viewDidLoad() or in storyboard only.

Related

Rotate UIBarButtonItem Swift

In Swift, I have a hamburger bar button, so when tapped I want that hamburger Bar button to rotate 90 degrees (so that the lines are vertical) and then when you click it again I would like it to go back to it's original state (horizontal)
NOTE: Can you make sure that this works for a UIBarButtonItem, because some solution to a normal UIButton does not work.
I use a UIButton inside of UIBarButtonItem to achieve this, and a variable with state vertical or not
this is my storyboard setup
Here is the code of simple view controller
import UIKit
class ViewController: UIViewController {
var isVertical : Bool = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func rotateAction(_ sender: Any) {
if(!self.isVertical)
{
UIView.animate(withDuration: 0.2, animations: {
self.navigationItem.leftBarButtonItem?.customView?.transform = CGAffineTransform(rotationAngle: 90 * .pi / 180)
}, completion: { (finished) in
self.isVertical = true
})
}else{
UIView.animate(withDuration: 0.2, animations: {
self.navigationItem.leftBarButtonItem?.customView?.transform = CGAffineTransform.identity
}, completion: { (finished) in
self.isVertical = false
})
}
}
}
Result
Hope this helps
#IBAction func rotateAction1(_ sender: Any) {
if (!self.isVertical) {
UIView.animate(withDuration: 0.2, animations: {
self.navigationItem.leftBarButtonItem?.customView?.transform = CGAffineTransform(rotationAngle: 90 * .pi / 180)
}, completion: {
(finished) in
self.isVertical = true
})
revealViewController().revealToggle(true)
} else {
UIView.animate(withDuration: 0.2, animations: {
self.navigationItem.leftBarButtonItem?.customView?.transform = CGAffineTransform.identity
}, completion: {
(finished) in
self.isVertical = false
})
revealViewController().revealToggle(false)
}
}
Swift 4:
func rotateBarButton() {
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 40, height: 40)) // Create new button & set its frame
button.setImage(#imageLiteral(resourceName: "settings"), for: UIControlState()) // Assign an image
let lef = UIBarButtonItem(customView: button)
self.navigationItem.leftBarButtonItem = lef// Set as barButton's customView
// Gets you half way there //
UIView.animate(withDuration: 0.8, delay: 0.1, options: UIViewAnimationOptions.curveEaseIn, animations: {
self.navigationItem.leftBarButtonItem?.customView?.transform = CGAffineTransform(rotationAngle: CGFloat(M_PI))
}, completion: nil)
// Rotates all the way around //
UIView.animate(withDuration: 0.5, delay: 0.5, options: UIViewAnimationOptions.curveEaseIn, animations: {
self.navigationItem.leftBarButtonItem?.customView?.transform = CGAffineTransform(rotationAngle: CGFloat(M_PI * 2))
}, completion: nil)
}

Stop block of animations with UITapGestureRecognizer

I have got this problem with breaking animations block in my app. I am animating an image inside UIScrollView (zooming-in, moving from left to right, zooming-out). Animation is being launched on tap with UITapGestureRecognizer.
The problem is that even though I can zoom-out the image when it is being animated, animations block continues and as a result I get the image off the iPhone screen.
I have tried to use removeAllAnimations() method on both scrollView.layer and view.layer but it seems not to work.
Here is my code:
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
setupGestureRecognizer()
}
func setupGestureRecognizer() {
let singleTap = UITapGestureRecognizer(target: self, action: #selector(self.handleSingleTap(recognizer:)))
singleTap.numberOfTapsRequired = 1
scrollView.addGestureRecognizer(singleTap)
}
func handleSingleTap(recognizer: UITapGestureRecognizer) {
animateRecipeImage()
}
// MARK: - Recipe Image Animation
func animateRecipeImage() {
let offset = CGPoint(x: 0, y: 0)
var middleOffset = CGPoint()
let endOffset = CGPoint(x: (imageView.bounds.width / 2), y: 0)
// To avoid animation in landscape mode we check for current device orientation
if (UIDeviceOrientationIsPortrait(UIDevice.current.orientation)) {
if (scrollView.zoomScale > scrollView.minimumZoomScale) {
scrollView.setZoomScale(scrollView.minimumZoomScale, animated: true)
// Remove all animations and update image contraints to fit the screen
self.scrollView.layer.removeAllAnimations()
self.view.layer.removeAllAnimations()
updateConstraintsForSize(size: view.bounds.size)
} else {
scrollView.setZoomScale(scrollView.maximumZoomScale, animated: true)
let screenWidth = screenSize.width
// Handle big screen sizes
if (screenWidth < self.imageView.bounds.width) {
middleOffset = CGPoint(x: ((self.imageView.bounds.width - screenWidth) * self.scrollView.zoomScale), y: 0)
} else {
middleOffset = CGPoint(x: (self.imageView.frame.width - screenWidth), y: 0)
}
// Start animating the image
UIView.animate(withDuration: 2, delay: 0.5, options: [.allowUserInteraction], animations: {
self.scrollView.setContentOffset(offset, animated: false)
}, completion: { _ in
UIView.animate(withDuration: 4, delay: 0.5, options: [.allowUserInteraction], animations: {
self.scrollView.setContentOffset(middleOffset, animated: false)
}, completion: { _ in
UIView.animate(withDuration: 1.0, delay: 0.2, usingSpringWithDamping: 0.4, initialSpringVelocity: 1.1, options: [.allowUserInteraction], animations: {
self.scrollView.setContentOffset(endOffset, animated: false)
}, completion: nil)
})
})
}
}
}
Any ideas how to break that animations block? The result I would like to achieve is break animation and zoom-out image.

.xib Called Inside ViewController Does not Recognize Touch Events

Inside a UIViewController, I call a .xib file and present it over the current UIView.
// initiate the pop up ad view and display it
let popUpAdView = PopUpAdViewController(nibName: "PopUpAdView", bundle: nil)
popUpAdView.displayIntoSuperView(view)
There is a button inside that .xib file that should remove itself from the screen when it's touched. However it doesn't perform so.
What exactly am I missing?
class PopUpAdViewController: UIViewController {
#IBOutlet weak var popUpAdView: UIView!
#IBOutlet weak var closeButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// adjust the view size from the device's screen size
let screenSize = UIScreen.mainScreen().bounds
view.frame = CGRectMake(0, 64, screenSize.width, screenSize.height-64)
// cosmetically adjust the view itself
view.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.6)
view.userInteractionEnabled = true
closeButton.userInteractionEnabled = true
// style the pop up ad view
popUpAdView.layer.cornerRadius = 5
popUpAdView.layer.shadowOpacity = 0.8
popUpAdView.layer.shadowOffset = CGSizeMake(0.0, 0.0)
closeButton.addTarget(self, action: #selector(removeOutOfSuperView), forControlEvents: .TouchUpInside)
}
func displayIntoSuperView(superView: UIView!) {
superView.addSubview(self.view)
// define the initial cosmetical values of the items
popUpAdView.transform = CGAffineTransformMakeScale(0.3, 0.3)
popUpAdView.alpha = 0.0
closeButton.alpha = 0.0
// animate...
UIView.animateWithDuration(0.8, delay: 0.0, options: .CurveEaseIn, animations: {
self.popUpAdView.alpha = 1.0
self.popUpAdView.transform = CGAffineTransformMakeScale(1.0, 1.0)
}) { (Bool) in
UIView.animateWithDuration(0.6, delay: 1.5, options: .CurveEaseIn, animations: {
self.closeButton.alpha = 1.0
}, completion: { (Bool) in
})
}
}
func removeOutOfSuperView() {
UIView.animateWithDuration(0.5, delay: 0.0, options: .CurveEaseIn, animations: {
self.closeButton.alpha = 0.0
self.popUpAdView.transform = CGAffineTransformMakeScale(0.1, 0.1)
}) { (finished) in
UIView.animateWithDuration(0.8, delay: 0.0, options: .CurveEaseIn, animations: {
self.view.alpha = 0.0
self.view.removeFromSuperview()
}, completion: nil)
}
}
#IBAction func closePopUpAdView(sender: AnyObject) {
print("Closing the pop up ad...")
removeOutOfSuperView()
}
}
Update
.xib structureL:

How to make a button flash or blink?

I am trying to change a button's color (just a flash/blink) to green when a scan is correct and red when there's a problem. I am able to do this with a view like so
func flashBG(){
UIView.animateWithDuration(0.7, animations: {
self.view.backgroundColor = UIColor.greenColor()
})
}
But with a button it stays green
func flashBtn(){
UIButton.animateWithDuration(0.5, animations: {
self.buttonScan.backgroundColor = UIColor.greenColor()
})
}
I have created the button by code
func setupScanButton() {
let X_Co = (self.view.frame.size.width - 100)/2
let Y_Co = (self.viewForLayer.frame.size.height + 36/2)
buttonScan.frame = CGRectMake(X_Co,Y_Co,100,100)
buttonScan.layer.borderColor = UIColor.whiteColor().CGColor
buttonScan.layer.borderWidth = 2
buttonScan.layer.cornerRadius = 50
buttonScan.setTitle("Scan", forState: .Normal)
buttonScan.backgroundColor = UIColor.blueColor()
buttonScan.addTarget(self, action: "buttonScanAction", forControlEvents: .TouchUpInside)
buttonScan.setTitleColor(UIColor(red:255/255, green: 255/255, blue:255/255, alpha: 1), forState: UIControlState.Normal)
self.view.addSubview(buttonScan)
}
Should i call setupScanButton() again?
This should work in Swift 4
extension UIView{
func blink() {
self.alpha = 0.2
UIView.animate(withDuration: 1, delay: 0.0, options: [.curveLinear, .repeat, .autoreverse], animations: {self.alpha = 1.0}, completion: nil)
}
}
This will start and stop a flashing button onClick, if you only want to flash the button immediately just use the first statement.
var flashing = false
#IBAction func btnFlash_Clicked(sender: AnyObject) {
if !flashing{
self.buttonScan.alpha = 1.0
UIView.animateWithDuration(0.5, delay: 0.0, options: [.CurveEaseInOut, .Repeat, .Autoreverse, .AllowUserInteraction], animations: {() -> Void in
self.buttonScan.alpha = 0.0
}, completion: {(finished: Bool) -> Void in
})
flashing = true
}
else{
UIView.animateWithDuration(0.1, delay: 0.0, options: [.CurveEaseInOut, .BeginFromCurrentState], animations: {() -> Void in
self.buttonScan.alpha = 1.0
}, completion: {(finished: Bool) -> Void in
})
}
}
Swift 5.x version
An updated version with extension.
extension UIView {
func blink(duration: TimeInterval = 0.5, delay: TimeInterval = 0.0, alpha: CGFloat = 0.0) {
UIView.animate(withDuration: duration, delay: delay, options: [.curveEaseInOut, .repeat, .autoreverse], animations: {
self.alpha = alpha
})
}
}
To call the function:
button.blink() // without parameters
button.blink(duration: 1, delay: 0.1, alpha: 0.2) // with parameters
I hope that will solve your problem.
buttonScan.alpha = 1.0
UIView.animate(withDuration: 1.0, delay: 1.0, options: UIView.AnimationOptions.curveEaseOut, animations: {
buttonScan.alpha = 0.0
}, completion: nil)
Swift 4:
I've maked an extension with some useful options:
extension UIButton {
open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
return self.bounds.contains(point) ? self : nil
}
func blink(enabled: Bool = true, duration: CFTimeInterval = 1.0, stopAfter: CFTimeInterval = 0.0 ) {
enabled ? (UIView.animate(withDuration: duration, //Time duration you want,
delay: 0.0,
options: [.curveEaseInOut, .autoreverse, .repeat],
animations: { [weak self] in self?.alpha = 0.0 },
completion: { [weak self] _ in self?.alpha = 1.0 })) : self.layer.removeAllAnimations()
if !stopAfter.isEqual(to: 0.0) && enabled {
DispatchQueue.main.asyncAfter(deadline: .now() + stopAfter) { [weak self] in
self?.layer.removeAllAnimations()
}
}
}
}
First of all, I've overrided the hittest function to enabling the touch also when the button have the alpha equals to 0.0 (transparent) during the animation.
Then , all input vars have a default value so you can launch the blink() method without parameters
I've introduced also the enabled parameter to start or stop the animations on your button.
Finally, if you want you can stop animation after a specific time with the stopAfter parameter.
Usage:
yourButton.blink() // infinite blink effect with the default duration of 1 second
yourButton.blink(enabled:false) // stop the animation
yourButton.blink(duration: 2.0) // slowly the animation to 2 seconds
yourButton.blink(stopAfter:5.0) // the animation stops after 5 seconds.
Typical uses:
yourButton.blink(duration: 1.5, stopAfter:10.0)
// your code..
yourButton.blink()
// other code..
yourButton.blink(enabled:false)
You can try something like this:
extension UIView {
func blink() {
UIView.animateWithDuration(0.5, //Time duration you want,
delay: 0.0,
options: [.CurveEaseInOut, .Autoreverse, .Repeat],
animations: { [weak self] in self?.alpha = 0.0 },
completion: { [weak self] _ in self?.alpha = 1.0 })
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,Int64(2 * NSEC_PER_SEC)),dispatch_get_main_queue()){
[weak self] in
self?.layer.removeAllAnimations()
}
}
}
//MARK : Usage
yourButton.flash()
extension UIButton {
func flash() {
let flash = CABasicAnimation(keyPath: "opacity")
flash.duration = 0.5
flash.fromValue = 1
flash.toValue = 0.1
flash.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
flash.autoreverses = true
flash.repeatCount = 3
layer.add(flash, forKey: nil)
}
}
Swift 3.0
func btnFlash_Clicked(sender: AnyObject) {
if !flashing{
callButton.alpha = 1.0
UIView.animate(withDuration: 0.5, delay: 0.0, options: [.allowUserInteraction], animations: {() -> Void in
callButton.alpha = 0.5
}, completion: {(finished: Bool) -> Void in
})
flashing = true
}
else{
flashing = false
callButton.alpha = 0.5
UIView.animate(withDuration: 0.5, delay: 0.0, options: [.allowUserInteraction], animations: {() -> Void in
callButton.alpha = 1.0
}, completion: {(finished: Bool) -> Void in
})
}
}
with UIViewPropertyAnimator and Swift 5
UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 1, delay: 0, options: [.curveLinear,.repeat], animations: {
UIView.setAnimationRepeatCount(3000)
self.buttonScan.alpha = 0.0
}, completion: {_ in })
Swift 3.0
func animateFlash() {
flashView.alpha = 0
flashView.isHidden = false
UIView.animate(withDuration: 0.3, animations: { flashView.alpha = 1.0 }) { finished in flashView.isHidden = true }
}
This UIView extension "blinks" a view and changes the background colour:
/**
Blinks a view with a given duration and optional color.
- Parameter duration: The duration of the blink.
- Parameter color: The color of the blink.
*/
public func blink(withDuration duration: Double = 0.25, color: UIColor? = nil) {
alpha = 0.2
UIView.animate(withDuration: duration, delay: 0.0, options: [.curveEaseInOut], animations: {
self.alpha = 1.0
})
guard let newBackgroundColor = color else { return }
let oldBackgroundColor = backgroundColor
UIView.animate(withDuration: duration, delay: 0.0, options: [.curveEaseInOut], animations: {
self.backgroundColor = newBackgroundColor
self.backgroundColor = oldBackgroundColor
})
}
You would then use as follows:
buttonScan.blink(color: .green)
myButton.alpha = 0.7
UIView.animate(withDuration: 0.3,
delay: 1.0,
options: [UIView.AnimationOptions.curveLinear, UIView.AnimationOptions.repeat, UIView.AnimationOptions.autoreverse],
animations: { myButton.alpha = 1.0 },
completion: nil)
Another smoothly animating version for Swift 5:
public extension UIView {
func blink(duration: TimeInterval) {
let initialAlpha: CGFloat = 1
let finalAlpha: CGFloat = 0.2
alpha = initialAlpha
UIView.animateKeyframes(withDuration: duration, delay: 0, options: .beginFromCurrentState) {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5) {
self.alpha = finalAlpha
}
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) {
self.alpha = initialAlpha
}
}
}
}

Swift Continuous Rotation Animation not so continuous

Here is my code. Intent is to continuously rotate the UIImageView named swirls[l]. However, there is a small pause between every rotation start/end. I have gone through every single animation tutorial but cant figure out what the mistake is?
let fullRotation = CGFloat(M_PI * 2)
let duration = 2.0
let delay = 0.0
let options = UIViewKeyframeAnimationOptions.Repeat | UIViewKeyframeAnimationOptions.CalculationModeLinear
UIView.animateKeyframesWithDuration(duration, delay: delay, options: options, animations: {
UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: 1/3, animations: {
swirls[l].transform = CGAffineTransformMakeRotation(1/3 * fullRotation)
})
UIView.addKeyframeWithRelativeStartTime(1/3, relativeDuration: 1/3, animations: {
swirls[l].transform = CGAffineTransformMakeRotation(2/3 * fullRotation)
})
UIView.addKeyframeWithRelativeStartTime(2/3, relativeDuration: 1/3, animations: {
swirls[l].transform = CGAffineTransformMakeRotation(3/3 * fullRotation)
})
}, completion: {finished in
})
EDIT: I see that it has been suggested that a previous solution is available, but it simply does not work for continuous uninterrupted rotation. The only trick that worked for me is the answer that I chose below. Thanks
Try below extension for swift 4.
extension UIView {
func rotate360Degrees(duration: CFTimeInterval = 3) {
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)
}
}
For start rotation.
MyView.rotate360Degrees()
And for Stop.
MyView.layer.removeAllAnimations()
You can use UIButton, UILabel and many more.
I'm not sure what's wrong with your code, but I've implemented continuous rotation using this method,
#IBAction func rotateView(sender: UIButton) {
UIView.animate(withDuration: 0.5, delay: 0, options: .curveLinear, animations: { () -> Void in
self.spinningView.transform = self.spinningView.transform.rotated(by: .pi / 2)
}) { (finished) -> Void in
self.rotateView(sender: sender)
}
}
If you want to continuous rotate Button or View and stop that rotation whenever you want then you can try this:
For start rotation:
#IBOutlet weak var RotateBtn: UIButton!
var timeTimer: Timer?
viewDidLoad()
{
self.rotateView()
timeTimer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(self.rotateView), userInfo: nil, repeats: true)
}
func rotateView()
{
UIView.animate(withDuration: 0.5, delay: 0, options: .curveLinear, animations: { () -> Void in
self.RotateBtn.transform = self.RotateBtn.transform.rotated(by: CGFloat(M_PI_4))
})
}
If you want to stop rotation then use:
#IBAction func StopBtn_Pressed(_ sender: AnyObject)
{
timeTimer?.invalidate()
self.RecordBtn.layer.removeAllAnimations()
}

Resources