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()
}
}
}
Related
I want to make SideMenu.
my code of HomeViewController:
lazy var sideMenu: SideMenuViewController = {
let menu = SideMenuViewController()
menu.stayViewObj = self
return menu
}()
Menu button's Action:
#objc func handleMenuBtn () {
sideMenu.openMenu()
}
SideMenu's viewDidLoad :
override func viewDidLoad(){
constraintLeadingPropertiesView.constant = -viewSelectProperties.frame.width
}
SideMenu's openMenu method:
func openMenu() {
debugPrint(">>>>openMenu")
let statusBarHeight = UIApplication.shared.statusBarFrame.height
let yCoordinate: CGFloat = statusBarHeight + 44.0
guard let window = UIApplication.shared.keyWindow else { return }
view.backgroundColor = UIColor(white: 0, alpha: 0.5)
view.alpha = 0
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(closeMenu)))
view.frame = window.frame
startFrame = CGRect(x: 0, y: yCoordinate, width: 0, height: window.frame.height - yCoordinate)
view.frame = startFrame!
window.addSubview(view)
UIView.animate(withDuration: 0.7, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.view.alpha = 1
self.view.frame = CGRect(x: 0, y: yCoordinate, width: window.frame.width - 80, height: window.frame.height - yCoordinate)
}, completion: nil)
}
Now, I am getting constraintLeadingPropertiesView=nil and all other properties of SideMenuController are also nil accepting stayViewObj.
so get crash on viewDidLoad.
how to solve this... any suggestion also helpful for me..
Thanks!
need to instantiateInitialViewController instead of create object via lazy Var.
let menu = UIStoryboard.init(name: "Main", bundle: nil).instantiateInitialViewController() as? SideMenuViewController
I have this code. I'm using the GestureRecognizer to call another method but when testing it on my iPhone the TapGestureRecognizer sends nothing. I thought it was a problem with the handleSettingsDismiss so I changed it to print something to know if it was recognizing the tap. But it did nothing and I get nothing on console. I don't know what is wrong.
func showSettingsMenu() {
if let window = UIApplication.shared.keyWindow {
blackView.isUserInteractionEnabled = true
blackView.backgroundColor = UIColor(white: 0, alpha: 0.5)
blackView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.handleSettingsDismiss)))
}
#objc func handleSettingsDismiss(){
UIView.animate(withDuration: 0.5){
self.blackView.alpha = 0
if let window = UIApplication.shared.keyWindow{
self.collectionView.frame = CGRect(x: 0, y: window.frame.height, width: self.collectionView.frame.width, height: self.collectionView.frame.height)
}
}
}
All I want to do is rotating the UIBarButtonItem when it is clicked.
I followed this post Rotate UIBarButtonItem Swift, but it is not working.
The difference is:
1- I set the image on runtime when view is loaded:
showHideBtn.image = showHeaderimage
2- I have two buttons in my right Bar button items:
Here is my code:
#IBAction func rotateAction(_ sender: Any) {
if(!self.isVertical)
{
UIView.animate(withDuration: 0.2, animations: {
self.navigationItem.rightBarButtonItem?.customView?.transform = CGAffineTransform(rotationAngle: 90 * .pi / 180)
}, completion: { (finished) in
self.isVertical = true
})
}else{
UIView.animate(withDuration: 0.2, animations: {
self.navigationItem.rightBarButtonItem?.customView?.transform = CGAffineTransform.identity
}, completion: { (finished) in
self.isVertical = false
})
}
}
What am I doing wrong?
Updated code:
DispatchQueue.main.async {
if(!self.isVertical) {
UIView.animate(withDuration: 0.2, animations: {
self.navigationItem.rightBarButtonItem?.customView?.transform = CGAffineTransform(rotationAngle: 90 * .pi / 180)
}, completion: { (finished) in
self.isVertical = true
})
}else {
UIView.animate(withDuration: 0.2, animations: {
self.navigationItem.rightBarButtonItem?.customView?.transform = CGAffineTransform(rotationAngle: 90 * .pi / 180)
}, completion: { (finished) in
self.isVertical = false
})
} }
Show button property:
It could be how you've set the custom view in the bar item. Maybe this self.navigationItem.rightBarButtonItem?.customView?. is returning nil. Anyway, here is a working version:
Creating the custom UIBarButtonItem:
let button1: UIButton = UIButton(frame: CGRect(x: 0, y: 0, width: 60, height: 30))
let button2: UIButton = UIButton(frame: CGRect(x: 70, y: 0, width: 60, height: 30))
override func viewDidLoad(_ animated: Bool) {
super.viewDidLoad(animated)
button1.backgroundColor = .gray
button1.setTitle("CustomButton", for: .normal)
button1.addTarget(self, action: #selector(rotateAction(_:)), for: .touchUpInside)
let barItem1: UIBarButtonItem = UIBarButtonItem(customView: button1)
button2.backgroundColor = .gray
button2.setTitle("CustomButton", for: .normal)
button2.addTarget(self, action: #selector(rotateAction(_:)), for: .touchUpInside)
let barItem2: UIBarButtonItem = UIBarButtonItem(customView: button1)
navigationItem.setRightBarButtonItems([barItem1, barItem2], animated: true)
}
Animate the tapped button:
#objc func rotateAction(_ sender: UIButton) {
let customView = sender
let transform: CGAffineTransform = isVertical ? .identity : CGAffineTransform(rotationAngle: 90 * .pi / 180)
UIView.animate(withDuration: 0.2, animations: {
customView.transform = transform
}, completion: { (finished) in
self.isVertical = !self.isVertical
})
}
To avoid replacing the bar button item/items set from storyboard, get those button items and create an array of bar button item including those with the ones you created in code:
let existingBarItems: [UIBarButtonItem] = navigationItem.rightBarButtonItems ?? []
let rightBarItems = existingBarItems = [yourCustomButtonItem]
navigationItem.setRightBarButtonItems(rightBarItems, animated: true)
And make sure your custom bar button item's frame doesn't intersect with existing buttons.
#IBAction func popView(_ sender: UIButton) {
let popView = PopView()
popView.setVisible()
popView.animateView(view: popView.contentView)
}
popView is a viewcontroller which has some views in it,popView use setup() in its init() to set these views.
func setup(){
view.frame = UIScreen.main.bounds
baseView.frame = view.frame
baseView.backgroundColor = UIColor.black
//baseView.alpha = appearence.backgroundAlpha
view.addSubview(baseView)
contentView.backgroundColor = UIColor.white
contentView.layer.cornerRadius = appearence.cornerRadius
contentView.frame = CGRect(x: 10, y: 10, width: appearence.width, height: appearence.height)
contentView.layer.masksToBounds = true
contentView.center = CGPoint(x: self.view.bounds.midX , y: self.view.bounds.midY )
baseView.addSubview(contentView)
headView.frame = CGRect(x: 0, y: 0, width: contentView.bounds.width, height: contentView.bounds.height / 2)
headView.backgroundColor = UIColorFromRGB(0xE64D4D)
contentView.addSubview(headView)
headImageView.image = UIImage(named: headImage)
headImageView.contentMode = .center
headImageView.frame.size = headImageView.image!.size
headImageView.center = CGPoint(x: headView.bounds.midX, y: headView.bounds.midY)
headView.addSubview(headImageView)
let recognizer = UITapGestureRecognizer(target: self, action: #selector(self.hide(_: )))
recognizer.numberOfTapsRequired = 1
contentView.addGestureRecognizer(recognizer)
print(String(describing: contentView.gestureRecognizers))
}
contentView has a tapgesturerecognizer but when I tap it doesn't work
func hide(_ recognizer: UITapGestureRecognizer){
self.view.removeFromSuperview()
}
popView is created by the code below in ViewController class
#IBAction func popView(_ sender: UIButton) {
let popView = PopView()
popView.setVisible()
popView.animateView(view: popView.contentView)
}
func setVisible(){
let rootView = UIApplication.shared.keyWindow! as UIWindow
rootView.addSubview(self.view)
}
func animateView(view: UIView){
view.center = CGPoint(x: self.view.bounds.midX, y: self.view.bounds.minY - view.bounds.midY)
UIView.animate(withDuration: 0.2, animations: {
view.center = CGPoint(x: self.view.bounds.midX , y: self.view.bounds.midY + 50)
}, completion: {(finished) -> Void in
UIView.animate(withDuration: 0.1, animations: {
view.center = CGPoint(x: self.view.bounds.midX , y: self.view.bounds.midY )
})
})
}
the popView appears correctly but contentView doesn't respond to the tap gesture. why??please help me~
Add tap gesture on popView's view controller instead of contentview. It will work as below.
let recognizer = UITapGestureRecognizer(target: self, action: #selector(self.hide(_: )))
recognizer.numberOfTapsRequired = 1
popView.view.addGestureRecognizer(recognizer)
print(String(describing: popView.view.gestureRecognizers))
Also move your hide function into button action class. Do Hide and showing into that class itself as below.
func hide(_ recognizer: UITapGestureRecognizer){
self.popView.view.removeFromSuperview()
let rootView = UIApplication.shared.keyWindow! as UIWindow
rootView.addSubview(self.view)
}
I hope this will help.
Below are my PopView class code:
import UIKit
class PopView: UIViewController {
var baseView: UIView = UIView()
var contentView: UIView = UIView()
var headView: UIView = UIView()
var headImageView: UIImageView = UIImageView()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.setup()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func setup(){
view.frame = UIScreen.main.bounds
baseView.frame = view.frame
baseView.backgroundColor = UIColor.black
//baseView.alpha = appearence.backgroundAlpha
view.addSubview(baseView)
contentView.backgroundColor = UIColor.white
contentView.layer.cornerRadius = 0.5
contentView.frame = CGRect(x: 10, y: 10, width: 200, height: 200)
contentView.layer.masksToBounds = true
contentView.center = CGPoint(x: self.view.bounds.midX , y: self.view.bounds.midY )
baseView.addSubview(contentView)
headView.frame = CGRect(x: 0, y: 0, width: contentView.bounds.width, height: contentView.bounds.height / 2)
headView.backgroundColor = UIColor.yellow
contentView.addSubview(headView)
headImageView.image = UIImage(named: "patternsPlaceholder")
headImageView.contentMode = .center
headImageView.frame.size = headImageView.image!.size
headImageView.center = CGPoint(x: headView.bounds.midX, y: headView.bounds.midY)
headView.addSubview(headImageView)
}
func setVisible(){
let rootView = UIApplication.shared.keyWindow! as UIWindow
rootView.addSubview(self.view)
}
func animateView(view: UIView){
view.center = CGPoint(x: self.view.bounds.midX, y: self.view.bounds.minY - view.bounds.midY)
UIView.animate(withDuration: 0.2, animations: {
view.center = CGPoint(x: self.view.bounds.midX , y: self.view.bounds.midY + 50)
}, completion: {(finished) -> Void in
UIView.animate(withDuration: 0.1, animations: {
view.center = CGPoint(x: self.view.bounds.midX , y: self.view.bounds.midY )
})
})
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
And below is the my baseviewController code.
import UIKit
class ViewController: UIViewController {
var popView = PopView()
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 popViewButtonAction(_ sender: Any) {
// let popView = PopView()
popView.setVisible()
popView.animateView(view: popView.contentView)
let recognizer = UITapGestureRecognizer(target: self, action: #selector(self.hide(_: )))
recognizer.numberOfTapsRequired = 1
popView.view.addGestureRecognizer(recognizer)
print(String(describing: popView.view.gestureRecognizers))
}
func hide(_ recognizer: UITapGestureRecognizer){
self.popView.view.removeFromSuperview()
let rootView = UIApplication.shared.keyWindow! as UIWindow
rootView.addSubview(self.view)
}
}
I hope it will give you Idea.
Thanks,
Shankar
I added a custom button to the sceneKit view. When it is touched, it plays an animation, indicating that it was clicked. The problem I'm facing is the delay between user touch and start of animation. My scene has 28.1K triangles and 84.4K vertices. Is that to much or do I need to implement buttons differently. The scene renders with 60fps. I added the button via sceneView.addSubview: Thanks for answers
viewDidLoad(){
// relevant code
starButton = UIButton(type: UIButtonType.Custom)
starButton.frame = CGRectMake(100, 100, 50, 50)
starButton.setImage(UIImage(named: "yellowstar.png"), forState: UIControlState.Normal)
sceneView.addSubview(starButton)
starButton.addTarget(self, action: "starButtonClicked", forControlEvents: UIControlEvents.TouchUpInside)
starButton.adjustsImageWhenHighlighted = false
}
func starButtonClicked(){
animateScaleDown()
}
func animateScaleDown(){
UIView.animateWithDuration(0.1, animations: {
self.starButton.transform = CGAffineTransformMakeScale(0.8, 0.8)
}, completion: { _ in
self.wait()
})
}
func wait(){
UIView.animateWithDuration(0.2, animations: {}, completion: { _ in
UIView.animateWithDuration(0.2, animations: {
self.starButton.transform = CGAffineTransformMakeScale(1, 1)
})
})
}
Okay I solved it. The problematic piece of code is
starButton.addTarget(self, action: "starButtonClicked", forControlEvents: UIControlEvents.TouchUpInside)
UIControlEvent.TouchUpInside gives the illusion of lag. Changing it to .TouchDown is much better.
For Swift 5
var starButton = UIButton()
func a () {
starButton = UIButton(type: UIButton.ButtonType.custom)
starButton.frame = CGRect(x: 100, y: 100, width: 50, height: 50)
starButton.backgroundColor = .blue
SpielFenster.addSubview(starButton)
starButton.addTarget(self, action: #selector(starButtonClicked), for: UIControl.Event.touchDown)
starButton.adjustsImageWhenHighlighted = false
}
#objc func starButtonClicked(){
animateScaleDown()
}
func animateScaleDown(){
UIView.animate(withDuration: 0.1, animations: {
self.starButton.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
}, completion: { _ in
self.wait()
})
}
func wait(){
UIView.animate(withDuration: 0.2, animations: {}, completion: { _ in
UIView.animate(withDuration: 0.2, animations: {
self.starButton.transform = CGAffineTransform(scaleX: 1, y: 1)
})
})
}