My goal is simple. When a button is clicked, the button should fade out and so should another image on the screen. I am using Swift Playgrounds. I have already got the button to fade out when clicked working. The main problem is getting the image on the screen to fade out once the button is clicked.
import PlaygroundSupport
import AVFoundation
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let title = UIImage(named: "Picture1")
let imageView = UIImageView(image: title) //this is the image I want to fade out when the button is clicked
imageView.image = title
imageView.frame.size.width = 570
imageView.frame.size.height = 140
imageView.frame.origin.x = 100
imageView.frame.origin.y = 0
imageView.alpha = 0
let button = UIButton(type: UIButton.ButtonType.custom) as UIButton
let image = UIImage(named: "startbutton4.png") as UIImage?
button.frame = CGRect(x: 265, y: 300, width: 249, height: 85)
button.setImage(image, for: [])
button.contentMode = .center
button.imageView?.contentMode = .scaleAspectFit
button.imageView?.contentMode = .scaleAspectFit
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
self.view.addSubview(button)
view.addSubview(imageView)
}
#objc func buttonAction(sender: UIButton) {
sender.isHighlighted = false
UIView.animate(withDuration: 1, delay: 1, options: .curveEaseOut, animations: {
sender.alpha = 0
}, completion: nil) // <--- this right here is the button fading out
}
}
let master = MyViewController()
PlaygroundPage.current.liveView = master
If anyone has any idea how to do this, please let me know.
What i understand is you want to hide button ... once button is hidden you want to show image .. here is the code for that.. i hope it will help
func buttonAction(sender: UIButton) {
sender.isHighlighted = false
UIView.animate(withDuration: 1, delay: 1, options: .curveEaseOut, animations: {
sender.alpha = 0
}, completion: { success in
if success {
UIView.animate(withDuration: 1, delay: 1, options: .curveEaseOut, animations: {
imageView.alpha = 1
})
}
})
}
Related
There is a UIImage inside the MainViewController as seen in the picture. There is also a button in TabBarViewController. When I press the button, I want the impulse animation I wrote for the UIView to start and stop.When i click to play button animation is not started. How can I do this?
Thanks.
enter image description here
Here is my code;
class MainViewObject: UIView {
//Center Image View Container
lazy var centerContainerView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.layer.cornerRadius = 113
view.backgroundColor = Colors.lightOrangeColor
return view
}()
}
class TabbarViewController: UITabBarController {
var object: MainViewObject!
//Create Play Button
let middleButton: UIButton = {
let btn = UIButton(frame: CGRect(x: (UIScreen.main.bounds.width / 2) - 32, y: -8, width: 65, height: 65))
btn.setImage(UIImage(named: "play"), for: UIControl.State.normal)
btn.layer.shadowColor = UIColor.black.cgColor
btn.layer.shadowOpacity = 0.1
btn.layer.shadowOffset = CGSize(width: 4, height: 4)
btn.backgroundColor = Colors.mainColor
btn.layer.cornerRadius = 32
btn.tintColor = UIColor.clear
btn .addTarget(self, action:#selector(menuButtonAction), for: .touchUpInside
return btn
}()
//Play Pause Button Function
#objc func menuButtonAction(sender: UIButton) {
sender.isSelected = !sender.isSelected
if sender.isSelected {
middleButton.setImage(UIImage(named: "pause"), for: UIControl.State.normal)
playRadio()
pulseAnimationStart()
}else{
middleButton.setImage(UIImage(named: "play"), for: UIControl.State.normal)
player!.pause()
pulseAnimationStop()
}
}
}
extension TabbarViewController {
//Main Page Main Image Pulse Animation Start
func pulseAnimationStart() {
let fadingAnimation = CABasicAnimation(keyPath: "opacity")
fadingAnimation.fromValue = 1
fadingAnimation.toValue = 0
let expandingAnimation = CABasicAnimation(keyPath: "transform.scale")
expandingAnimation.fromValue = 1
expandingAnimation.toValue = 1.1
let animationGroup = CAAnimationGroup()
animationGroup.animations = [expandingAnimation,
fadingAnimation]
animationGroup.duration = 1.5
animationGroup.repeatCount = .infinity
self.object.centerContainerView.layer.add(animationGroup, forKey: "pulse")
}
//Main Page Main Image Pulse Animation Stop
func pulseAnimationStop() {
UIView.animate(withDuration: 0.0) {
self.object.centerContainerView.layer.removeAllAnimations()
}
}
}
I need some help to translate the rightBarButtonItem in the UINavigationBar. I have followed this and also found similar questions which lead me to add the button as a customView of a UIBarButtonItem, however the code is still not working.
I have created a UIBarButtonItem and set a UIButton as its custom view.
let button: UIButton = {
let b = UIButton(type: .system)
b.setTitle("Test", for: .normal)
return b
}()
lazy var barButton = UIBarButtonItem(customView: button)
This method is called from viewDidLoad
func configNavBar() {
navigationItem.rightBarButtonItem = barButton
}
To animate the bar button when some action occurs:
func animateRightBarButton() {
UIView.animate(withDuration: 0.25,
delay: 0,
usingSpringWithDamping: 0.8,
initialSpringVelocity: 1.5,
options: .curveEaseInOut,
animations: {
guard let customView = self.barButton.customView else {return}
var x: CGFloat = customView.transform.tx == 0 ? 100 : 0
customView.transform = CGAffineTransform(scaleX: x, y: 0)
}, completion: nil)
}
The bar button appears as expect when the view has loaded. I want the button to slide off screen but i have noticed a couple of problems.
The button disappears from the view with no animation when this function is called.
If I print(x) (the translate x value) it remains at 100.0 and does not change back to 0 using the ternary operator. Any help appreciated to get this working, thanks.
use this code:
let bell = UIImage(named: "gift")!
let button = UIButton(type: .custom)
button.translatesAutoresizingMaskIntoConstraints = false
button.setBackgroundImage(bell, for: .normal)
button.addTarget(self, action: #selector(self.showAdd), for: .touchUpInside)
let bellButton = UIBarButtonItem(customView: button)
self.navigationItem.leftBarButtonItem = bellButton
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
if let bell = self.navigationItem.leftBarButtonItem?.customView {
let animation = CAKeyframeAnimation(keyPath: "transform.translation.x")
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
animation.duration = 0.6
animation.values = [-8.0, 8.0, -8.0, 8.0, -4.0, 4.0, -4.0, 4.0, 0.0 ]
bell.layer.add(animation, forKey: "shake")
}
}
Thanx to #KMI
I improved usability by carrying out the functionality of #KMI 's method in separate helper:
Swift 5
UIBarButtonItem+Helper.swift
extension UIBarButtonItem {
typealias AnimationClosure = (_ customView: UIView)->()
private var uniqueCustomViewAnimationKey: String {
"customViewAnimation"
}
func animate(with animation: CAAnimation, delay: TimeInterval = 0.5) {
DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in
guard let `self` = self else { return }
self.customView?.layer.add(animation, forKey: self.uniqueCustomViewAnimationKey)
}
}
}
And usage in some class:
func bellItem() -> UIBarButtonItem {
let button = UIButton(type: .custom)
button.translatesAutoresizingMaskIntoConstraints = false
button.setBackgroundImage(UIImage(named: "bell"), for: .normal)
button.addTarget(self, action: #selector(bellItemPressed), for: .touchUpInside)
let item = UIBarButtonItem(customView: button)
// create custom animation
let animation = CAKeyframeAnimation(keyPath: "transform.translation.x")
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
animation.duration = 0.6
animation.values = [-8.0, 7.0, -6.0, 5.0, -4.0, 3.0, -2.0, 1.0, 0.0 ]
// applying the animation
item.animate(with: animation)
return item
}
#objc private func bellItemPressed() {
// do some stuff when item pressed
}
I have an UIBarButton in navigation bar, while clicking on back button (first tap) i need to display toast (like warning), on double tap i need to exit from the page in swift,
Following codes used for displaying toast, its working fine,
let toastLabel = UILabel(frame: CGRect(x: 20, y: self.view.frame.size.height-100, width: 350, height: 35))
toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.6)
toastLabel.textColor = UIColor.white
toastLabel.textAlignment = .center;
toastLabel.font = UIFont(name: "Montserrat-Light", size: 12.0)
toastLabel.text = "demo"
toastLabel.alpha = 1.0
toastLabel.layer.cornerRadius = 10;
toastLabel.clipsToBounds = true
self.view.addSubview(toastLabel)
UIView.animate(withDuration: 2.0, delay: 0.1, options: .curveEaseOut, animations: {
toastLabel.alpha = 0.0
}, completion: {(isCompleted) in
toastLabel.removeFromSuperview()
})
please guide me to acheive this task.
Add an target-action on UIButton for the control event UIControlEventTouchDownRepeat, and do action only when the touch's tapCount is 2. Like below in Swift 3
button.addTarget(self, action: #selector(multipleTap(_:event:)), for: UIControlEvents.touchDownRepeat)
And Then add selector as below
func multipleTap(_ sender: UIButton, event: UIEvent) {
let touch: UITouch = event.allTouches!.first!
if (touch.tapCount == 2) {
// do action.
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.hidesBackButton = true
let button = UIButton(type: .system)
button.frame = CGRect(x: 0, y: 0, width: 80, height: 40)
button.setTitle("Back", for: .normal)
//Gesture Recognizer
let singleTap = UITapGestureRecognizer(target: self, action: #selector(handleSingleTap))
singleTap.numberOfTapsRequired = 1
let doubleTap = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap))
doubleTap.numberOfTapsRequired = 2
button.addGestureRecognizer(singleTap)
button.addGestureRecognizer(doubleTap)
singleTap.require(toFail: doubleTap)
let barButton = UIBarButtonItem(customView: button)
self.navigationItem.leftBarButtonItem = barButton
}
#objc func handleSingleTap(sender: UITapGestureRecognizer? = nil) {
let toastLabel = UILabel(frame: CGRect(x: 20, y: self.view.frame.size.height-100, width: 350, height: 35))
toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.6)
toastLabel.textColor = UIColor.white
toastLabel.textAlignment = .center;
toastLabel.font = UIFont(name: "Montserrat-Light", size: 12.0)
toastLabel.text = "demo"
toastLabel.alpha = 1.0
toastLabel.layer.cornerRadius = 10;
toastLabel.clipsToBounds = true
self.view.addSubview(toastLabel)
UIView.animate(withDuration: 2.0, delay: 0.1, options: .curveEaseOut, animations: {
toastLabel.alpha = 0.0
}, completion: {(isCompleted) in
toastLabel.removeFromSuperview()
})
print("Single Tap detected")
}
#objc func handleDoubleTap(sender: UITapGestureRecognizer? = nil) {
print("Double Tap detected")
}
Use UIControlEventTouchDownRepeat event, and do action when tapCount is 2.
I a have an overlay with a table in and I'd like to add a Tap gesture recogniser to the background to dismiss the view and also addTarget to a button within the overlay which does the same thing.
The overlay displays fine as expected, however whenever I tap the black background or the cancel button, nothing happens. I've searched for an answer here but nothing found has worked. My code is as follows, followed by a screenshot of the overlay:
class importedFileView: NSObject {
let blackView = UIView()
let importedFileContainerView: UIView = {
let importedFileContainerView = UIView(frame: .zero)
importedFileContainerView.backgroundColor = .white
importedFileContainerView.layer.cornerRadius = 10
importedFileContainerView.layer.masksToBounds = true
return importedFileContainerView
}()
let headerLabel: UILabel = {
let headerLabel = UILabel()
headerLabel.translatesAutoresizingMaskIntoConstraints = false
headerLabel.font = UIFont(name: "HelveticaNeue-Thin" , size: 24)
headerLabel.text = "Attach file"
headerLabel.textColor = .darkGray
headerLabel.adjustsFontSizeToFitWidth = true
return headerLabel
}()
let fileTableView: UITableView = {
let fileTableView = UITableView()
return fileTableView
}()
let updateDetailsButton: UIButton = {
let updateDetailsButton = UIButton()
updateDetailsButton.translatesAutoresizingMaskIntoConstraints = false
updateDetailsButton.backgroundColor = UIColor(r:40, g:86, b:131)
updateDetailsButton.setTitleColor(UIColor.white, for: .normal)
updateDetailsButton.setTitle("Attach selected files", for: .normal)
updateDetailsButton.titleLabel!.font = UIFont(name: "HelveticaNeue-Light" , size: 18)
updateDetailsButton.layer.cornerRadius = 2
return updateDetailsButton
}()
let cancelButton: UIButton = {
let cancelButton = UIButton()
cancelButton.translatesAutoresizingMaskIntoConstraints = false
cancelButton.backgroundColor = UIColor.white
cancelButton.setTitleColor(UIColor(r:40, g:86, b:131), for: .normal)
cancelButton.setTitle("Cancel", for: .normal)
cancelButton.titleLabel!.font = UIFont(name: "HelveticaNeue-Light" , size: 18)
cancelButton.layer.cornerRadius = 2
return cancelButton
}()
let frameHeight: CGFloat = 450
func showFormView(){
if let window = UIApplication.shared.keyWindow {
blackView.backgroundColor = UIColor(white: 0, alpha: 0.5)
window.addSubview(blackView)
window.addSubview(importedFileContainerView)
importedFileContainerView.addSubview(headerLabel)
importedFileContainerView.addSubview(fileTableView)
importedFileContainerView.addSubview(updateDetailsButton)
importedFileContainerView.addSubview(cancelButton)
cancelButton.addTarget(self, action: #selector(handleDismiss), for: .touchUpInside)
blackView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleDismiss)))
layoutViews()
fileTableView.frame = CGRect(x: 30, y: window.frame.height, width: window.frame.width - 60, height: 230)
let frameY = (window.frame.height - frameHeight) / 2
importedFileContainerView.frame = CGRect(x: 20, y: window.frame.height, width: window.frame.width - 40, height: self.frameHeight)
blackView.frame = window.frame
blackView.alpha = 0
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.blackView.alpha = 1
self.importedFileContainerView.frame = CGRect(x: 20, y: frameY, width: window.frame.width - 40, height: self.frameHeight)
}, completion: nil
)
}
}
func layoutViews(){
let views = ["v0" : headerLabel, "v1": fileTableView, "v2": updateDetailsButton, "v3": cancelButton]
let leftSpace = NSLayoutConstraint.constraints(withVisualFormat: "H:|-20.0-[v0]-20.0-|", options: NSLayoutFormatOptions(), metrics: nil, views: views)
let leftSpace1 = NSLayoutConstraint.constraints(withVisualFormat: "H:|-20.0-[v1]-20.0-|", options: NSLayoutFormatOptions(), metrics: nil, views: views)
let leftSpace2 = NSLayoutConstraint.constraints(withVisualFormat: "H:|-20.0-[v2]-20.0-|", options: NSLayoutFormatOptions(), metrics: nil, views: views)
let leftSpace3 = NSLayoutConstraint.constraints(withVisualFormat: "H:|-20.0-[v3]-20.0-|", options: NSLayoutFormatOptions(), metrics: nil, views: views)
let topSpacing = NSLayoutConstraint.constraints(withVisualFormat: "V:|-20.0-[v0(40)]-20.0-[v1(230)]-20.0-[v2(50)]-10.0-[v3(50)]-10.0-|", options: NSLayoutFormatOptions(), metrics: nil, views: views)
importedFileContainerView.addConstraints(topSpacing)
importedFileContainerView.addConstraints(leftSpace)
importedFileContainerView.addConstraints(leftSpace1)
importedFileContainerView.addConstraints(leftSpace2)
importedFileContainerView.addConstraints(leftSpace3)
}
func handleDismiss() {
UIView.animate(withDuration: 0.5,
delay: 0.0,
options: .curveEaseInOut,
animations: {
self.blackView.alpha = 0
if let window = UIApplication.shared.keyWindow {
self.importedFileContainerView.frame = CGRect(x: 20, y: window.frame.height, width: window.frame.width - 40, height: self.frameHeight)
}
},
completion: { [weak self] finished in
self?.blackView.removeFromSuperview()
self?.importedFileContainerView.removeFromSuperview()
})
}
override init() {
super.init()
}
}
self.blackView.isUserInteractionEnabled = true;
is all you need to add to the blackView (UIView).
Without that, the view doesn't have any interactions enabled and so the gesture recognizer's target/action isn't triggered.
Events are ignored.
https://developer.apple.com/reference/uikit/uiview/1622577-isuserinteractionenabled
You might also want to disable it during animations.
Are you keeping a strong reference to the instance of your importedFileView while your overlays are visible? As far as I tested, all actions are silently ignored when the target is lost.
For example, this does not work:
#IBAction func someAction(_ sender: Any) {
let ifv = importedFileView()
ifv.showFormView()
//`ifv` is released at the end of this method, then your overlays are shown...
}
This works:
let ifv = importedFileView() //keep the instance as a property of your ViewController.
#IBAction func someAction(_ sender: Any) {
ifv.showFormView()
}
Programmatically generated UIViews isUserInteractionEnabled is default to true. You have no need to explicitly set it to true.
By the way, you'd better not name your non-UIView class as ...View, and better make your type names start with capital letter, which makes your code more readable to experienced Swift programmers.
I have dynamically created buttons on a dynamic view and later I add that dynamic view to main view.
Everything is working well except that the selector method of UIButton is not called.
var baseView:UIView?
override func viewDidLoad() {
super.viewDidLoad()
randomizeButtons()}
func randomizeButtons(){
baseView = UIView(frame:CGRectMake(view.bounds.origin.x + 10, view.bounds.origin.y + 50, view.bounds.size.width, view.bounds.size.height-20))
let viewWidth = baseView.bounds.size.width;
let viewHeight = baseView.bounds.size.height;
baseView.userInteractionEnabled = true
let i = GlobalArrayofUsers.count
var loopCount = 0
while loopCount < i{
let userBaseView = UIView(frame: CGRectMake(abs(CGFloat(arc4random()) % viewWidth - 90) , abs(CGFloat(arc4random()) % viewHeight - 120), 90, 90))
print(userBaseView.frame)
userBaseView.backgroundColor = UIColor.redColor()
userBaseView.userInteractionEnabled = true
userBaseView.layer.cornerRadius = 45
userBaseView.clipsToBounds = true
let button = UIButton(frame: userBaseView.bounds)
button.backgroundColor = UIColor.greenColor()
button.showsTouchWhenHighlighted = true
button.addTarget(self, action: #selector(ViewController.handleTapEventofBtn(_:)), forControlEvents: .TouchUpInside)
button.setTitle("hello", forState: .Normal)
button.userInteractionEnabled = true
userBaseView.addSubview(button)
baseView.addSubview(userBaseView)
print("button frame is\(button.frame)")
baseView.bringSubviewToFront(userBaseView)
loopCount += 1
}
}
baseView.subviews.forEach { (users) in
UIView.animateWithDuration(1, delay: 0, options: [.Autoreverse,.Repeat], animations: {
users.center.y += 10
}, completion: nil)
}
view.insertSubview(baseView, atIndex: view.subviews.count)
}
func handleTapEventofBtn(sender: UIButton!) {
// handling code
}
Any idea why my selector method is not called? It is due to animation. How can i handle it.
SOLUTION: Allow userinteraction in UIAnimationOptions
The problem is that you are trying to click an object that is being animated. From the docs:
During an animation, user interactions are temporarily disabled for
the views being animated. (Prior to iOS 5, user interactions are
disabled for the entire application.)
But worry not, the solution is very easy, just call your animation with the option .AllowUserInteraction. For example (with your code):
UIView.animateWithDuration(1, delay: 0, options: [.Autoreverse,.Repeat,.AllowUserInteraction], animations: {
users.center.y += 10
}, completion: nil)
Have you tried this way:
for _ in 0...5{
// generate new view
let userBaseView = UIView(frame: CGRectMake(abs(CGFloat(arc4random()) % viewWidth - 90) , abs(CGFloat(arc4random()) % viewHeight - 120), 90, 90))
userBaseView.backgroundColor = UIColor.redColor()
// add button to view
let button = UIButton(frame: userBaseView.bounds)
button.backgroundColor = UIColor.yellowColor()
button.showsTouchWhenHighlighted = true
button.addTarget(self, action: #selector(self.handleTapEventofBtn(_:)), forControlEvents: .TouchUpInside)
button.setTitle("hello", forState: .Normal)
userBaseView.addSubview(button)
}
self.view.addSubview(userBaseView)
All you need is to create userBaseView before cycle, then create buttons in cycle and add them to userBaseView, after that just add userBaseView to self.view or where you need to add it. In your example you create userBaseView in every iteration of the loop.
I think the problem could be here:
userBaseView.addSubview(button)
// add new view containing button to self.view
self.view.addSubview(userBaseView)
}
userBaseView.addSubview(button)
baseView.addSubview(userBaseView)
First you add userBaseView to self.view in the loop:
// add new view containing button to self.view
self.view.addSubview(userBaseView)
then add it to baseView:
baseView.addSubview(userBaseView)
Can you post how it looks like in IB?
The action has a parameter so the selector signature is actually takeActionBtn:
(note the colon at the end).
You need to change that or the button will try to call a version of the function with no parameter which doesn't exist.
button.addTarget(self, action: "button:",forControlEvents: UIControlEvents.TouchUpInside)
func button(sender: UIButton!) {
// handling code
print("1")
}
// hi. your problem is in the selector line. try this:
for _ in 0...5 {
// generate new view
let userBaseView = UIView(frame: CGRectMake(abs(CGFloat(arc4random()) % self.view.frame.size.width - 90) , abs(CGFloat(arc4random()) % self.view.frame.size.height - 120), 90, 90))
userBaseView.backgroundColor = UIColor.redColor()
// add button to view
let button = UIButton(frame: userBaseView.bounds)
button.backgroundColor = UIColor.yellowColor()
button.showsTouchWhenHighlighted = true
button.addTarget(self, action: "buttonAction", forControlEvents: UIControlEvents.TouchUpInside)
button.setTitle("hello", forState: .Normal)
userBaseView.addSubview(button)
self.view.addSubview(userBaseView)
}
// tested with xcode 7.2
func buttonAction() {
print("working")
}