Swift color change shows different color - swift

I am trying to do a scale animation on an image view. Upon completion I am changing the image to a red colored version of it. But in between it shows a weird blue color which I dont want to show. This is the code I am using for the animation. Thanks
self.likeAnimateView.image = self.likeAnimateView.image!.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
UIView.animate(withDuration: 0.182,
animations: {
self.likeAnimateView.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
},
completion: { _ in
UIView.animate(withDuration: 0.182) {
self.likeAnimateView.transform = CGAffineTransform.identity
self.likeAnimateView.image = UIImage(named: "heartsel") // Red image
}
})

As per the suggestion of #Karthikeyan Bose. I added this line of code before the animation.
self.likeAnimateView.image = UIImage(named: "heart")//Deafault color before the animation to get rid of the blue color
UIView.animate(withDuration: 0.182,
animations: {
self.likeAnimateView.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
},
completion: { _ in
UIView.animate(withDuration: 0.182) {
self.likeAnimateView.transform = CGAffineTransform.identity
self.likeAnimateView.image = UIImage(named: "heartsel") // Red image
}
})

Related

How to redraw a subviews in landscape

Good afternoon Community,
I am trying to add two subviews to a viewcontroller by means of an extension, but when rotating the device it does not respect the layout, any option on how to make it look correct?
I attach my code below and a couple of example photos, the first photo is how I would like it to look, and the rest of the ui is lost.
This is my code:
func presentCustomAlertController(on ViewController:UIViewController,toPresentCustomView customView:UIView,withBackgroundView backGroundView:UIView){
customView.translatesAutoresizingMaskIntoConstraints = false
guard let targetView = ViewController.view else {return}
backGroundView.alpha = 0
backGroundView.backgroundColor = .black
backGroundView.frame = targetView.bounds
targetView.addSubview(backGroundView)
targetView.addSubview(customView)
customView.setNeedsLayout()
customView.setNeedsDisplay()
customView.layoutIfNeeded()
customView.layoutSubviews()
targetView.setNeedsLayout()
targetView.setNeedsDisplay()
targetView.layoutIfNeeded()
targetView.layoutSubviews()
backGroundView.setNeedsDisplay()
backGroundView.setNeedsLayout()
backGroundView.layoutIfNeeded()
customView.frame = CGRect(x: targetView.center.x, y: targetView.center.y, width: targetView.frame.size.width-80, height: 300)
UIView.animate(withDuration: 0.25, animations: {
backGroundView.alpha = 0.6
},completion: { done in
UIView.animate(withDuration: 0.25, animations: {
customView.center = targetView.center
})
})
}
}

UIView's background color keeps reverting back to original color upon completion

Is there any reason why the backgroundColor of a UIView would jump back to its original color after changing it's color property in a nested UIView.animate method? I set it to clear during the animation then it jumps back to white upon my last second to last completion.
I have tried converting over to animateWithKeyframes and I still have a similar condition.
Basically I am trying to use a view as a mask and animate it across a label. I have a darkModeBool that indicates if the user wants a dark theme. I want the label.textColor and the view.Background color to change accordingly to my set theme protocol when it hits that animation block if that darkModeBool is set to true.
func animateGraphic() {
firstMaskWidthConstraint.constant = 0
UIView.animate(withDuration: 1.2, delay: 1, options: .curveLinear, animations: {
self.view.layoutIfNeeded()
self.firstMaskView.backgroundColor = .clear
print("1")
}) { (_) in
self.secondMaskHeightConstraint.constant = 0
UIView.animate(withDuration: 0.8, delay: 0, options: .curveEaseIn, animations: {
self.view.layoutIfNeeded()
self.secondMaskView.backgroundColor = .clear
print("2")
}, completion: { (_) in
UIView.animate(withDuration: 1, delay: 0.8, options: .curveEaseInOut, animations: {
self.view.layoutIfNeeded()
self.view.backgroundColor = SproutTheme.current.backgroundColor.cgColor
self.sproutLabel.textColor = SproutTheme.current.textColor
}, completion: { (_) in
RunLoop.current.run(until: Date(timeIntervalSinceNow: 1.8))
self.popToNavigationStack()
})
})
}
}
When the view is supposed to change it's backgroundColor in the second to last completion, the firstMaskView and secondMaskView go back to white covering the text. Any input is greatly appreciated.

How to animate PieChart sector on highlight for the Charts library?

When I highlight a sector in a PieChartView, the sector changes to the dataSet's highlightColor + the selectionShift. However this happens immediately and I'd like to animate this transition.
Currently the only animate function I see is for ChartViewBase, which animates the entire chart (which is what I do not want).
Is there anyway to only animate a single (selected) sector?
I have the following code as a starting point, but I can't apply transform to the entry nor the highlight
func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
let translation1 = CGAffineTransform(scaleX: 1.5, y: 1.5)
let translation2 = CGAffineTransform(translationX: 1.0, y: 1.0)
UIView.animate(withDuration: 0.4, animations: { in
entry.transform = translation1
}) { didComplete in
UIView.animate(withDuration: 0.4, animations: {
entry.transform = translation2
})
}
}
have you tried below property for animation selected value ?
self.pieChart.highlightPerTapEnabled = true
Check this may be help to animate while highlighted.

Animate video UIView to go full screen like YouTube App

I have a view controller that has a UIView that I call playerView. In playerView, I use an AVLayer and AVPlayerLayer to show the user a video. Image the Youtube app when you first click on any video.
How do I manipulate the frame of this playerView so that it can take up the entire screen. (Go full screen)
This is the current frame:
//16 x 9 is the aspect ratio of all HD videos
let height = view.frame.width * 9 / 16
let playerFrame = CGRect(x: 0, y: 0, width: view.frame.width, height: height)
playerView.frame = videoPlayerFrame
I was testing around in the YouTube app and their app only supports Portrait orientation (just like mine) due to how the animation of a video going full screen looks. How can I do this at the the tap of a button and even further when the user holds the device horizontally?
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.playerView.frame = ?
}, completion: nil)
Edit: Tried this but it doesn't really work how I want it... it doesn't take up the whole screen
UIView.animate(withDuration: 0.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.playerView.frame = CGRect(x: 0, y: 0, width: self.view.frame.height, height: self.view.frame.width)
self.playerView.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi / 2))
}, completion: nil)
I figured it out.
I create a global variable called isExpanded that will be set to true when we're in full screen mode. Also, I create a CGPoint variable called videoPlayerViewCenter so I can save the center before going full screen so I can set it again when going back to small screen.
This is the code that gets called when the user wants to go full screen
func fullScreenTapped(sender: vVideoPlayer) {
if !isExpanded {
//Expand the video
UIView.animate(withDuration: 0.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.videoPlayerViewCenter = self.videoPlayerView.center
self.videoPlayerView.frame = CGRect(x: 0, y: 0, width: self.view.frame.height, height: self.view.frame.width)
self.videoPlayerView.center = self.view.center
self.videoPlayerView.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi / 2))
self.videoPlayerView.layoutSubviews()
}, completion: nil)
} else {
//Shrink the video again
UIView.animate(withDuration: 0.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
//16 x 9 is the aspect ratio of all HD videos
self.videoPlayerView.transform = CGAffineTransform.identity
self.videoPlayerView.center = self.videoPlayerViewCenter
let height = self.view.frame.width * 9 / 16
let videoPlayerFrame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: height)
self.videoPlayerView.frame = videoPlayerFrame
self.videoPlayerView.layoutSubviews()
}, completion: nil)
}
isExpanded = !isExpanded
}
To expand the video, I save the center in my global CGPoint variable and then set the frame. Then, I set the center and do a 90 degree turn using CGAffineTransform.
To shrink the video again, I basically set the settings to how they were before. (The order in which things are done is very important)
Another thing that's also very important is to override your layoutSubviews method in your videoPlayerView to be like this:
override func layoutSubviews() {
super.layoutSubviews()
self.playerLayer?.frame = self.bounds
}
This will make it so your playerLayer adjusts its frame as the view is getting bigger.
I know is too late but maybe someone else can find this code helpful.
I use to use Auto layout constraints in my views so animating must have a different approach.
func setMapFullScreen(_ fullscreen: Bool) {
if fullscreen {
// Set the full screen constraints
self.setFullScreenLayoutConstraints()
// Hide the navigation bar
self.navigationController?.setNavigationBarHidden(true, animated: true)
} else {
// Set small screen constraints
self.setSmallScreenLayoutConstraints()
// Show the navigation bar
self.navigationController?.setNavigationBarHidden(false, animated: true)
}
// Animate to full screen
UIView.animate(withDuration: 0.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
}) { (finished) in
// ...
}
In my case a have I MKMapView and I want to tap on it in order to see the map fullscreen (and back).
This is the function that toogle the state.
As you can see, in the UIView.animate call, I animate only the self.view.layoutIfNeeded()
I also hide the navigation bar cause I have one ☺
Here my setSmallScreenLayoutConstraints and setFullScreenLayoutConstraints functions using SnapKit framework
func setSmallScreenLayoutConstraints() {
self.mapView.snp.remakeConstraints { (make) -> Void in
make.top.equalTo(self.mapLabel.snp.bottom).offset(8)
make.left.equalTo(self.view).offset(0)
make.right.equalTo(self.view).offset(0)
make.height.equalTo(150)
}
}
func setFullScreenLayoutConstraints() {
self.mapView.snp.remakeConstraints { (make) -> Void in
make.top.equalTo(self.view).offset(0)
make.left.equalTo(self.view).offset(0)
make.right.equalTo(self.view).offset(0)
make.bottom.equalTo(self.view).offset(0)
}
}
This is the result
Enjoy!!
As I said it is not an answer for your question. It is an idea and hope it helps you:
var rectangleView:UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Tap Gesture Recognizer for growing the rectangleView
let tapForward = UITapGestureRecognizer.init(target: self, action: #selector(self.tapForward(tap:)))
tapForward.numberOfTapsRequired = 1
// Configure the rectangleView
self.rectangleView = UIView.init(frame: CGRect.init(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height))
self.rectangleView.transform = CGAffineTransform.init(scaleX: 0.65, y: 0.25)
self.rectangleView.backgroundColor = UIColor.red
self.rectangleView.addGestureRecognizer(tapForward)
self.view.addSubview(rectangleView)
}
And this going to be our tapForward(tap:) function:
func tapForward(tap:UITapGestureRecognizer) {
UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.8, options: .curveEaseInOut, animations: {
self.rectangleView.transform = CGAffineTransform.identity
}) { (completed:Bool) in
// Completion block
}
}

UIViewAnimationOptions.CurveEaseIn not working inside coordinated animation

I am in the middle of developing a tvOS application.
In my application I have a UICollectionView. On focus I am using a coordinated animation. Inside that animation I have this code:
UIView.animateWithDuration(1.0, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: {
self.bg.image = finalImage
self.bg.alpha = 1.0
}, completion: nil)
But it seems like its not using the curveEaseIn animation option.
Its changing the alpha bluntly, which is odd. Where I am going wrong?
Sorry. Forgot to post the answer.
I did animating the imageview in the completion of the coordinated animation like this
self.bg.alpha = 0.0
coordinator.addCoordinatedAnimations({ //code for coordinated animation}, completion: { _ in
UIView.animateWithDuration(1.0, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: {
self.bg.image = self.finalImage
self.bg.alpha = 1.0
}, completion: nil)})
What is the desired effect? Are you trying to cross fade bg.image with a new image? Have you tried changing the duration to something higher, for example 10.0, to see if the animation is perhaps happening too fast?
Here's an example of what you may be looking for:
let myImageView = UIImageView()
let myFinalImage = UIImage(named:"FinalImage.png")
// Animate alpha
UIView.animateWithDuration(1.0, delay: 0.0, options: .CurveEaseIn, animations: {
print("alpha animation started")
myImageView.alpha = 0.0
}) { (finished) in
print("alpha animation finished")
}
// Animate change of image
UIView.transitionWithView(myImageView, duration: 1.0, options: .TransitionCrossDissolve, animations: {
print("cross dissolve animation started")
myImageView.image = myFinalImage
}) { (finished) in
print("cross dissolve animation finished")
}
In Swift 4 or Swift 5 use: .curveEaseIn
UIView.animate(withDuration: 1.0, delay: 0.0, options: .curveEaseIn, animations: {
...
}) { (finished) in
...
}