Changing frame of a UIView is not working fine - ios

I have a small problem which I am not able to get why this is happening.
I have a customised NavigationView. My requirement is to change the frame of this NavigationView when tap on google map. I mean I have to show and hide (toggle) the frame with animation.
Below is my code :-
func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
if false == boolTapOnNavigationView {
UIView.animate(withDuration: 0.5, animations: {
self.viewNavigation.frame = CGRect(x: 0, y: -100, width: self.view.frame.width, height: 60)
//self.viewNavigation.isHidden = true
})
boolTapOnNavigationView = true
}
else {
UIView.animate(withDuration: 0.5, animations: {
//self.viewNavigation.isHidden = false
self.viewNavigation.frame = CGRect(x: 0, y: 20, width: self.view.frame.width, height: 60)
})
boolTapOnNavigationView = false
}
}
In my code you can see I have a flag called 'boolTapOnNavigationView'.
That code is working fine if I will tap on google map but when I will tap on any other button in same ViewController then frame of that NavigationView is reflecting automatically.

You should change center not frame
func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
if false == boolTapOnNavigationView {
UIView.animate(withDuration: 0.5, animations: {
self.viewNavigation.centre.y = self.viewNavigation.centre.y - 100
//self.viewNavigation.isHidden = true
})
boolTapOnNavigationView = true
}
else {
UIView.animate(withDuration: 0.5, animations: {
//self.viewNavigation.isHidden = false
self.viewNavigation.centre.y = self.viewNavigation.centre.y + 20
})
boolTapOnNavigationView = false
}
}

Related

Swift remove UIview immediately and show animation duration 1sec at another place

i want to remove UIView from superview immediately and show that view at another place by animation
i try this
mView.removeFromSuperview()
mView.frame = CGRect.init(x: 0, y: 0, width: 121, height: 58)
self.view.addSubview(mView)
UIView.transition(with: self.view, duration: 1, options: [.transitionCrossDissolve], animations: {
self.mView.alpha = 1
}, completion: nil)
this code will remove mView and add mView at the same time duration 1 sec
but i need remove mView immediately
maybe i need update my self.view after mView.removeFromSuperview() ?
thanks
i tried this
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
self.infoWindow.alpha = 0
self.view.layoutIfNeeded()
let data = marker.userData as! [String : Any]
let location = CLLocationCoordinate2D(latitude: (data["latitude"] as! Double), longitude: (data["longitude"] as! Double))
self.infoWindow = CustomGMSInfoWindow(frame: CGRect.init(x: 0, y: 0, width: 121, height: 58))
self.infoWindow.center = mapView.projection.point(for: location)
self.infoWindow.center.y = (infoWindow.center.y) - 65
self.infoWindow.frame = CGRect(infoWindow.frame.origin.x, infoWindow.frame.origin.y, infoWindow.frame.width, infoWindow.frame.height)
UIView.animate(withDuration: 1.0) {
self.infoWindow.alpha = 1.0
}
return false
}
There's no reason to remove / re-add mView. All you need to do is set its .alpha to Zero, change its frame, and then animate the .alpha back to 1 (will cause it to "fade in".
// set alpha to Zero (invisible)
self.mView.alpha = 0.0
// set its new frame
self.mView.frame = CGRect(x: 0, y: 0, width: 121, height: 58)
// "fade in"
UIView.animate(withDuration: 1.0) {
self.mView.alpha = 1.0
}
Here's a complete example. Each time you tap, the red mView will disappear and then "fade in" at a random location:
class ViewController: UIViewController {
let mView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
mView.backgroundColor = .red
mView.frame = CGRect(x: 100, y: 200, width: 121, height: 58)
view.addSubview(mView)
let tap = UITapGestureRecognizer(target: self, action: #selector(self.doAnim))
view.addGestureRecognizer(tap)
}
#objc func doAnim() -> Void {
let x = CGFloat.random(in: 0...(view.frame.size.width - 121))
let y = CGFloat.random(in: 0...(view.frame.size.height - 58))
// set alpha to Zero (invisible)
self.mView.alpha = 0.0
// set its new frame
self.mView.frame = CGRect(x: x, y: y, width: 121, height: 58)
// "fade in"
UIView.animate(withDuration: 1.0) {
self.mView.alpha = 1.0
}
}
}
Edit: the original question posted was not the actual question
Here is your posted code, with a couple changes. Read through the comments:
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
// (1) - if you are creating a NEW view at (3),
// remove this view first
//self.infoWindow.alpha = 0
self.infoWindow.removeFromSuperview()
// (2) - not needed
//self.view.layoutIfNeeded()
let data = marker.userData as! [String : Any]
let location = CLLocationCoordinate2D(latitude: (data["latitude"] as! Double), longitude: (data["longitude"] as! Double))
// (3) - create a NEW view
self.infoWindow = CustomGMSInfoWindow(frame: CGRect.init(x: 0, y: 0, width: 121, height: 58))
self.infoWindow.center = mapView.projection.point(for: location)
self.infoWindow.center.y = (infoWindow.center.y) - 65
// (4) - this is setting the frame to itself - you don't need this
self.infoWindow.frame = CGRect(infoWindow.frame.origin.x, infoWindow.frame.origin.y, infoWindow.frame.width, infoWindow.frame.height)
// (5) - you created a NEW view, so you need to set its alpha here
self.infoWindow.alpha = 0.0
// (6) - and you need to add it as a subview... I'm assuming it needs to be added to the mapView
mapView.addSubview(self.infoWindow)
// (7) if this doesn't fade in the new view...
UIView.animate(withDuration: 1.0) {
self.infoWindow.alpha = 1.0
}
// (8) try it like this - wait 5/100ths of a second before starting the fade-in
UIView.animate(withDuration: 1.0, delay: 0.05, animations: {
self.infoWindow.alpha = 1.0
})
return false
}
Run after your animation:
self.view.layoutIfNeeded()

didTapAtCoordinate not showing selected Marker - Google Maps IOS

I want to change the icon of my selected marker to a deselected one if the user taps on the map. I am using the following delegate method :
internal func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
print("\(map.selectedMarker) ===> Selected Marker")
}
however map.selectedMarker always comes nil. Even when the documentation says This is called before deselecting any currently selected marker (the implicit action for tapping on the map)
so I was expecting to be able to see my selected marker.
This is the code I am running when a marker gets tapped
internal func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
if map.selectedMarker == marker {
return true
}
if let selectedMarker = map.selectedMarker {
deselectActiveMarker(currentSelectedMarker: selectedMarker)
}
selectMarker(marker: marker)
return true
}
the selectMarker(marker: marker) method is the following one:
private func selectMarker(marker: GMSMarker) {
marker.iconView?.setAnchorPoint(anchorPoint: CGPoint(x: 0.5, y: 0))
if let cluster = marker.userData as? GMUCluster {
let count = "\(cluster.count)" as NSString
if let icon = UIImage(named: "clusterSelected") {
marker.iconView = UIImageView(image: createIconWithCount(drawText: count, inImage: icon, isSelected: true))
}
}
else {
if let icon = UIImage(named: "pinSelected") {
marker.iconView = UIImageView(image: icon)
}
}
marker.iconView?.transform = CGAffineTransform(scaleX: 0, y: 0)
UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 5, options: .curveEaseIn, animations: {
marker.iconView?.transform = CGAffineTransform(scaleX: 1, y: 1)
}, completion: {
[weak self = self]
_ in
guard let instance = self else { return }
instance.map.selectedMarker = marker
})
}
Hopefully you can help me. Thanks

UIGestureTap to dismiss view

I am trying to enable UIGestureTap on a custom view. I have a view controller, and in that view controller, when I press a button, a custom view pops up.
var transparentBackground = UIView()
#IBAction func UserViewImage(_ sender: UIButton) -> Void {
self.transparentBackground = UIView(frame: UIScreen.main.bounds)
self.transparentBackground.backgroundColor = UIColor(white: 0.0, alpha: 0.4)
UIApplication.shared.keyWindow!.addSubview(self.transparentBackground)
self.opaqueView = self.setupOpaqueView()
self.transparentBackground.addSubview(opaqueView)
UIApplication.shared.keyWindow!.bringSubview(toFront: self.transparentBackground)
self.view.bringSubview(toFront: transparentBackground)
}
I want to be able to tap on the transparentBackground view and dismiss it. So I have a dismiss function called removeAnimate()
func removeAnimate()
{
UIView.animate(withDuration: 0.25, animations: {
self.transparentBackground.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
self.transparentBackground.alpha = 0.0;
}, completion:{(finished : Bool) in
if (finished)
{
self.transparentBackground.removeFromSuperview()
}
});
}
So, in viewdidload I enabled the UITapGesture:
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(removeAnimate))
self.transparentBackground.addGestureRecognizer(gestureRecognizer)
self.transparentBackground.isUserInteractionEnabled = true
I know the function removeAnimate works because I used it on a button in the transparentBackground view and it works perfectly. But when I tap on the transparentBackground view it does not dismiss and I am not sure what I am doing wrong
func setupOpaqueView() -> UIView{
let mainView = UIView(frame: CGRect(x: 16, y: 132, width: Int(UIScreen.main.bounds.width-32), height: 403))
mainView.backgroundColor = UIColor.clear
mainView.layer.cornerRadius = 6
self.imageView = UIImageView(frame: CGRect(x: 29, y: 18, width: 274, height: 350))
mainView.addSubview(OKbutton)
mainView.addSubview(self.imageView)
OKbutton.addTarget(self, action: #selector(ThirdWheelViewController.handleOKButtonTapped(_:)), for: .touchUpInside)
return mainView
}
This is an example and hope it helps you:
First of all create a variable:
var customView:UIView!
This is going to be our function for adding a custom view:
#IBAction func customAction(_ sender: AnyObject) {
self.customView = UIView.init(frame: CGRect.init(x: self.view.bounds.width / 2, y: self.view.bounds.height / 2, width: 100, height: 100))
self.customView.backgroundColor = UIColor.red
self.view.addSubview(self.customView)
let tap = UITapGestureRecognizer.init(target: self, action: #selector(self.removeFromSuperView))
tap.numberOfTapsRequired = 1
self.customView.addGestureRecognizer(tap)
}
And finally:
func removeFromSuperView() {
self.customView.alpha = 1.0
self.customView.transform = .identity
UIView.animate(withDuration: 0.3, animations: {
self.customView.alpha = 0.0
self.customView.transform = .init(scaleX: 1.5, y: 1.5)
}) { (finished) in
if !finished {
} else {
self.customView.removeFromSuperview()
}
}
}

Swift UITabBarController hide with animation

I'm trying to add animation to my tabBarController when hidden. Im able to accomplish this effect with the navigationBarController by using self.navigationController?.isNavigationBarHidden = true. I'm able to hide the tabBar by using self.tabBarController?.tabBar.isHidden = true but i do not get the animation how can I do this thank you in advance.
You could change the tab bar's frame inside an animation, so something like:
func hideTabBar() {
var frame = self.tabBarController?.tabBar.frame
frame?.origin.y = self.view.frame.size.height + (frame?.size.height)!
UIView.animate(withDuration: 0.5, animations: {
self.tabBarController?.tabBar.frame = frame!
})
}
func showTabBar() {
var frame = self.tabBarController?.tabBar.frame
frame?.origin.y = self.view.frame.size.height - (frame?.size.height)!
UIView.animate(withDuration: 0.5, animations: {
self.tabBarController?.tabBar.frame = frame!
})
}
Which sets the tab bar just below the visible screen, so that it slides up/down from the bottom.
I've developed a util extension for UIViewController
Swift 4 compatible:
extension UIViewController {
func setTabBarHidden(_ hidden: Bool, animated: Bool = true, duration: TimeInterval = 0.3) {
if animated {
if let frame = self.tabBarController?.tabBar.frame {
let factor: CGFloat = hidden ? 1 : -1
let y = frame.origin.y + (frame.size.height * factor)
UIView.animate(withDuration: duration, animations: {
self.tabBarController?.tabBar.frame = CGRect(x: frame.origin.x, y: y, width: frame.width, height: frame.height)
})
return
}
}
self.tabBarController?.tabBar.isHidden = hidden
}
}
Improvement of the response of #Luca Davanzo. If the bar is already hidden, it will continue hiding it and moving it lower. Also get rid of the return, so the state of the tabbar.hidden changes when the animation happens.
So I added a check:
extension UIViewController {
func setTabBarHidden(_ hidden: Bool, animated: Bool = true, duration: TimeInterval = 0.5) {
if self.tabBarController?.tabBar.isHidden != hidden{
if animated {
//Show the tabbar before the animation in case it has to appear
if (self.tabBarController?.tabBar.isHidden)!{
self.tabBarController?.tabBar.isHidden = hidden
}
if let frame = self.tabBarController?.tabBar.frame {
let factor: CGFloat = hidden ? 1 : -1
let y = frame.origin.y + (frame.size.height * factor)
UIView.animate(withDuration: duration, animations: {
self.tabBarController?.tabBar.frame = CGRect(x: frame.origin.x, y: y, width: frame.width, height: frame.height)
}) { (bool) in
//hide the tabbar after the animation in case ti has to be hidden
if (!(self.tabBarController?.tabBar.isHidden)!){
self.tabBarController?.tabBar.isHidden = hidden
}
}
}
}
}
}
}
In case if you need to toggle it from hide to visible and vice versa:
func toggleTabbar() {
guard var frame = tabBarController?.tabBar.frame else { return }
let hidden = frame.origin.y == view.frame.size.height
frame.origin.y = hidden ? view.frame.size.height - frame.size.height : view.frame.size.height
UIView.animate(withDuration: 0.3) {
self.tabBarController?.tabBar.frame = frame
}
}
Swift 4 solution:
tabBarController?.tabBar.isHidden = true
UIView.transition(with: tabBarController!.view, duration: 0.35, options: .transitionCrossDissolve, animations: nil)
Here is a simple extension :
func setTabBar(hidden:Bool) {
guard let frame = self.tabBarController?.tabBar.frame else {return }
if hidden {
UIView.animate(withDuration: 0.3, animations: {
self.tabBarController?.tabBar.frame = CGRect(x: frame.origin.x, y: frame.origin.y + frame.height, width: frame.width, height: frame.height)
})
}else {
UIView.animate(withDuration: 0.3, animations: {
self.tabBarController?.tabBar.frame = UITabBarController().tabBar.frame
})
}
}
So I've been playing around for 3 days with this now, finding out that the one that worked for me in my code was Adriana's post from 14th Sept 2018. But I was not sure how to use the coding once copied into my Project. So, after much experimenting I found that the way I could use this func was to put the following into into the respective swipe actions.
setTabBarHidden(false)
setTabBarHidden(true)
My next step is to try to get the swipe actions working while using UIScrollView in the same UIView at the same time.
You have to add UIView transitionWithView class func
Swift 2
func hideTabBarWithAnimation() -> () {
UIView.transitionWithView(tableView, duration: 1.0, options: .TransitionCrossDissolve, animations: { () -> Void in
self.tabBarController?.tabBar.hidden = true
}, completion: nil)
}
Swift 3, 4, 5
func hideTabBarWithAnimation() -> () {
UIView.transition(with: tableView, duration: 1.0, options: .transitionCrossDissolve, animations: { () -> Void in
self.tabBarController?.tabBar.isHidden = true
}, completion: nil)
}

Vanishing popup alert view

I'd like to popup a view with a single label in it that disappears slowly within one second to inform the user about a choice he made, an update occurred or whatever.
I use animatewithduration, but because they may be many different alerts, I'd like to create a class to avoid creating view, label and func in any UIViewController that may display that kind of alert ... Kind of :
let doneAlert = PopUpAlert(parentView : self, textAlert : "You're done")
where parentView in the view where I want the textAlert to be displayed and then when needed:
doneAlert.display()
Here's the class I wrote :
class PopUpAlert: UIView {
convenience init(parentView : UIView,textAlert : String) {
self.init(frame: CGRect(x: 0, y: 0, width: 200, height: 150))
self.alpha = 0
self.center = parentView.center
let popUpLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 150))
popUpLabel.center = self.center
popUpLabel.text = textAlert
self.addSubview(popUpLabel)
parentView.addSubview(self)
}
func display() {
PopUpAlert.animateWithDuration(0.5, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
self.alpha = 1.0
}, completion: nil)
PopUpAlert.animateWithDuration(1.0, delay: 0.5, options: UIViewAnimationOptions.CurveEaseIn, animations: {
self.alpha = 0.0
}, completion: nil)
}
}
And here's the way I use it :
class CarteVC: UIViewController {
var daddy : RootViewController?
var goAlert : PopUpAlert?
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
goAlert = PopUpAlert(parentView: mapView, textAlert: "On the way ....")
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let bb = UIBarButtonItem(title: "< List", style: .Plain, target: papa!, action: "pred")
bb.tintColor = UIColor.lightGrayColor()
daddy!.navigationItem.leftBarButtonItem = bb
daddy!.navigationItem.rightBarButtonItem = nil
goAlert!.display()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Navigation
Nothing is displayed.
If you want to just alert user and disappear in one second than i would suggest you to use Toast Swift
https://github.com/scalessec/Toast-Swift
Here is how you make the toast
self.view.makeToast("Testing Toast")
// specific duration and position
self.view.makeToast("Testing Toast with duration and position", duration: 3.0, position: .Top)
// toast with image and all possible
self.view.makeToast("testing toast image and all possible ", duration: 2.0, position: CGPoint(x: 110.0, y: 110.0), title: "Toast Title", image: UIImage(named: "toast.png"), style:nil) { (didTap: Bool) -> Void in
if didTap {
print("with tap")
} else {
print("without tap")
}
}
The pb came from centering the label inside the view ... Here's the class and works perfectly fine !!! :
class PopUpAlert: UIView {
convenience init(parentView : UIView,textAlert : String) {
self.init(parentView: parentView,textAlert: textAlert,background: UIColor.darkGrayColor(),foreground: UIColor.whiteColor())
}
convenience init(parentView : UIView,textAlert : String, background : UIColor) {
self.init(parentView: parentView,textAlert: textAlert,background: background,foreground: UIColor.whiteColor())
}
convenience init(parentView : UIView,textAlert : String, foreground : UIColor) {
self.init(parentView: parentView,textAlert: textAlert,background: UIColor.darkGrayColor(),foreground: foreground)
}
convenience init(parentView : UIView,textAlert : String, background : UIColor, foreground : UIColor) {
self.init(frame: CGRect(x: 0, y: 0, width: 150, height: 40))
self.alpha = 0
self.backgroundColor = background
self.layer.cornerRadius = 5
self.layer.masksToBounds = true
self.center = (parentView.superview ?? parentView).center
let popUpLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 150, height: 40))
popUpLabel.textAlignment = .Center
popUpLabel.textColor = foreground
popUpLabel.text = textAlert
self.addSubview(popUpLabel)
parentView.addSubview(self)
}
deinit {
self.removeFromSuperview()
}
func display() {
PopUpAlert.animateWithDuration(0.5, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
self.alpha = 0.85
}, completion: nil)
PopUpAlert.animateWithDuration(1.0, delay: 0.7, options: UIViewAnimationOptions.CurveEaseIn, animations: {
self.alpha = 0.0
}, completion: nil)
}

Resources