Select a specify subview swift - ios

how can i select a subview and interact with it using swift and n subview. For now i have only 3 subviews and select 3 image with for.
But for example how can I remove the subview with tag 2 after i create it?
func addSubView() {
for index in 1...3 {
let image: UIImage = UIImage(named: String(index))!
imageView = UIImageView(image: image)
imageView.tag = index
imageView.isUserInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.removeSubview))
imageView.addGestureRecognizer(tapGesture)
imageView.frame = CGRect(x: randomNumber(range: 60...300), y: randomNumber(range: 60...400), width: 50, height: 50)
print(imageView)
self.backgroundImageView.addSubview(imageView)
}
}
func removeSubview() {
}

You could write a function removeSubviewWithTag(_:) that would take a tag number as a parameter:
func removeSubviewWithTag(_ tag: Int) {
if let viewWithTag2 = backgroundImageView.viewWithTag(tag) {
viewWithTag2.removeFromSuperview()
}
}
And then call it as desired:
removeSubviewWithTag(2)
If you want to know if the function was able to find and remove a subview, you could make it return a discardable Bool result:
#discardableResult func removeSubviewWithTag(_ tag: Int) {
if let viewWithTag2 = backgroundImageView.viewWithTag(tag) {
viewWithTag2.removeFromSuperview()
return true
} else {
return false
}
}
And call it as follows:
if removeSubviewWithTag(2) {
print("Removed view")
} else {
print("unable to remove view")
}

Maybe add them to an array? Using tags is rarely the best solution.
var imageViews = [UIImageView]()
func addSubView() {
for index in 1...3 {
let image: UIImage = UIImage(named: String(index))!
imageView = UIImageView(image: image)
imageView.tag = index
imageView.isUserInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.removeSubview))
imageView.addGestureRecognizer(tapGesture)
imageView.frame = CGRect(x: randomNumber(range: 60...300), y: randomNumber(range: 60...400), width: 50, height: 50)
print(imageView)
self.backgroundImageView.addSubview(imageView)
imageViews.append(imageView)
}
}
func removeSubview(at index: Int) {
imageViews[index].removeFromSuperview()
}

Related

Animate thru various images in Swift - Using customized Load View

I have a customLoader which I would like to call anytime a user logs in. I want to animate thru all seven photos in gifArray.
import UIKit
class CustomLoader: UIView {
static let instance = CustomLoader()
let gifArray: [UIImage] = [UIImage(named: "beer1")!,UIImage(named: "beer2")!,UIImage(named: "beer3")!,UIImage(named: "beer4")!,UIImage(named: "beer5")!,UIImage(named: "beer6")!,UIImage(named: "beer7")!]
lazy var transparentView:UIView = {
let transparentView = UIView(frame: UIScreen.main.bounds)
transparentView.backgroundColor = UIColor.black.withAlphaComponent(0.7)
transparentView.isUserInteractionEnabled = false
return transparentView
} ()
lazy var gifImage: UIImageView = {
var gifImage = UIImageView(frame: CGRect(x: 0, y: 0, width: 200.00, height: 100))
gifImage.contentMode = .scaleAspectFit
gifImage.center = transparentView.center
gifImage.isUserInteractionEnabled = false
return gifImage
} ()
func animate() {
for image in gifArray {
gifImage.image = image
gifImage.animationRepeatCount = 1
gifImage.startAnimating()
}
}
func showLoader() {
self.addSubview(transparentView)
self.transparentView.addSubview(gifImage)
self.transparentView.bringSubviewToFront(self.gifImage)
animate()
}
func hideLoader() {
self.transparentView.removeFromSuperview()
}
}
I call it when the user logs in
In ViewDidLoad:
CustomLoader.instance.showLoader()
view.addSubview(CustomLoader.instance.transparentView)
view.bringSubviewToFront(CustomLoader.instance.transparentView)
Problem: It unfortunately just shows the last image. How do i fix this?
The for loop here sets the last image
for image in gifArray {
instead you need
gifImage.isUserInteractionEnabled = false
gifImage.animationImages = gifArray
Then
func animate() {
gifImage.startAnimating()
}

Tapping a UIImage while it's being animated

I've been trying to be able to tap a UIImage as it animates to the top of my screen and print("Image Tapped"), yet to no success.
override func viewDidLoad() {
super.viewDidLoad()
redBalloon.image = UIImage(named: "redBalloon")
redBalloon.contentMode = .scaleAspectFit
redBalloon.frame = CGRect(x: Int(xOrigin), y: 667, width: Int(redBalloon.frame.size.width), height: Int(redBalloon.frame.size.height))
UIView.animate(withDuration: 5, delay: 0, options: UIImageView.AnimationOptions.allowUserInteraction, animations: {
self.redBalloon.frame = CGRect(x: Int(self.xEnding), y: -192, width: 166, height: 192)
}, completion: {(finished:Bool) in
self.endGame()
})
let imageTap = UITapGestureRecognizer(target: self, action: #selector(imageTapped))
redBalloon.isUserInteractionEnabled = true
redBalloon.addGestureRecognizer(imageTap)
}
#objc func imageTapped(_ sender: UITapGestureRecognizer) {
// do something when image tapped
print("image tapped")
}
The problem is that the image view is not in the spot where you see it during animation (it's at the endpoint of the animation). So you are not tapping on the image view at the point where it is, and thus the tap is not detected.
Therefore, either you must hit-test the presentation layer or, if you don't want to do that, you must use a UIViewPropertyAnimator instead of calling UIView.animate.
As an example of the first approach, I'll subclass UIImageView. Make your UIImageView an instance of this subclass:
class TouchableImageView : UIImageView {
override func hitTest(_ point: CGPoint, with e: UIEvent?) -> UIView? {
let pres = self.layer.presentation()!
let suppt = self.convert(point, to: self.superview!)
let prespt = self.superview!.layer.convert(suppt, to: pres)
return super.hitTest(prespt, with: e)
}
}
However, personally I think it's a lot simpler to use UIViewPropertyAnimator. In that case, do not make your UIImageView a TouchableImageView! You don't want to do extra hit-test munging. Just let the property animator do all the work:
redBalloon.image = UIImage(named: "redBalloon")
redBalloon.contentMode = .scaleAspectFit
redBalloon.frame = CGRect(x: Int(xOrigin), y: 667, width: Int(redBalloon.frame.size.width), height: Int(redBalloon.frame.size.height))
let anim = UIViewPropertyAnimator(duration: 5, timingParameters: UICubicTimingParameters(animationCurve: .easeInOut))
anim.addAnimations {
self.redBalloon.frame = CGRect(x: Int(xEnding), y: -192, width: 166, height: 192)
}
anim.addCompletion { _ in
self.endGame()
}
let imageTap = UITapGestureRecognizer(target: self, action: #selector(imageTapped))
redBalloon.isUserInteractionEnabled = true
redBalloon.addGestureRecognizer(imageTap)
anim.startAnimation()

Detect intersection of 2 UIImageView in Swift

Can you help me please to figure out why my code is not working when I try to make a colission between 2 UIImageViews ?
Here is my code:
// Creating falling objects
#objc func creating(_ timer: Timer) {
for (index, imageView) in images.enumerated() {
if imageView == nil {
let fallingObjectImageView = UIImageView(image: #imageLiteral(resourceName: "PoundImage"))
fallingObjectImageView.contentMode = .scaleAspectFill
fallingObjectImageView.clipsToBounds = true
let randomX = CGFloat(drand48()) * view.frame.maxX
fallingObjectImageView.frame = CGRect(x: randomX, y: -30, width: 50, height: 50)
view.addSubview(fallingObjectImageView)
images[index] = fallingObjectImageView
// This IF is not working (I dont know why)
if (fallingObjectImageView.frame.intersects(playerImageView.frame)) {
print("HIT HIT !")
}
break
}
}
}
And a photo:
Thanks !

Swift Radio Buttons Not Clickable

I am using the DLRadioButton library through Cocoa Pods found here
Below is my code, essentially the radio buttons appear however I am only able to click 1 of them in the group and I am unsure why. Note that I am populating the Radio Buttons based on an Int in Firebase that indicates how many to populate:
` override func viewDidLoad() {
super.viewDidLoad()
ref = FIRDatabase.database().reference()
pollRef = ref.child("Polls").child(pass)
passLabel.text = pass
pollImage.sd_setImage(with: URL(string: passedImageURL), placeholderImage: UIImage(named: "test"))
pollRef.observe(FIRDataEventType.value, with: {(snapshot) in
self.numberOfChildren = Int(snapshot.childSnapshot(forPath: "answers").childrenCount)
self.passLabel.text = String(self.numberOfChildren)
print(self.numberOfChildren)
var buttons = [DLRadioButton]()
for x in 0..<self.numberOfChildren {
let answerLabel = snapshot.childSnapshot(forPath:
"answers").childSnapshot(forPath:
String(x+1)).childSnapshot(forPath: "answer").value
let firstRadioButton = self.createRadioButton(frame: CGRect(x:
CGFloat(x)*32, y:self.view.center.y , width: 40.0, height: 20.0),
title: answerLabel as! String, color: UIColor.black)
// firstRadioButton.translatesAutore sizingMaskIntoConstraints = false
let screenSize: CGRect = UIScreen.main.bounds
firstRadioButton.frame = CGRect(x: 0, y: 0, width: 50, height: screenSize.height * 0.2)
firstRadioButton.tag = x
buttons.append(firstRadioButton)
self.view.addSubview(firstRadioButton);
}
let groupButtons = DLRadioButton()
groupButtons.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(groupButtons)
let margins = self.view.layoutMarginsGuide
groupButtons.bottomAnchor.constraint(equalTo: margins.bottomAnchor, constant: 0).isActive = true
groupButtons.otherButtons = buttons
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
private func createRadioButton(frame : CGRect, title : String, color : UIColor) -> DLRadioButton {
let radioButton = DLRadioButton(frame: frame);
radioButton.titleLabel!.font = UIFont.systemFont(ofSize: 14);
radioButton.setTitle(title, for: UIControlState.normal);
radioButton.setTitleColor(color, for: UIControlState.normal);
radioButton.iconColor = color;
radioButton.indicatorColor = color;
radioButton.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left;
radioButton.addTarget(self, action: #selector(self.logSelectedButton(_:)), for: UIControlEvents.touchUpInside);
return radioButton;
}
#IBAction func logSelectedButton(_ radioButton: DLRadioButton) {
if radioButton.isMultipleSelectionEnabled {
for button: DLRadioButton in radioButton.selected() {
print("\(button.titleLabel?.text) is selected.\n")
}
}
else {
print("\(radioButton.selected()?.titleLabel?.text) is selected.\n")
}
}
`
You need to selector method of button
let firstRadioButton = self.createRadioButton(frame: CGRect(x: self.view.center.x, y: CGFloat(x)*32, width: 100.0, height: 120.0), title: answerLabel as! String, color: UIColor.green)
firstRadioButton.tag = x
firstRadioButton.addTarget(self, action: #selector(self.logSelectedButton), for: .touchUpInside)
buttons.append(firstRadioButton)
Selector method : you can change as per needs
#IBAction func logSelectedButton(_ radioButton: DLRadioButton) {
if radioButton.isMultipleSelectionEnabled {
for button: DLRadioButton in radioButton.selectedButtons {
print("\(button.titleLabel?.text) is selected.\n")
}
}
else {
print("\(radioButton.selectedButton.titleLabel?.text) is selected.\n")
}
}

UIButton works normally, but not in popoverPresentationController

I have a parent container UIView that has three subviews: 1 UITextView, and 2 buttons (the buttons are on top of the UITextView, but contained as subviews of the container UIView). When I present the parent UIView on screen normally, simply inside of a UIViewController, the buttons trigger their associated action methods perfectly and function correctly. However, when I present the UIView inside a view controller that becomes a popover, the view hierarchy shows up properly, but the buttons don't trigger their associated action methods and nothing happens. Is there something about UIPopoverPresentationControllers and buttons that I don't understand?
Adding the buttons to the parent UIView
func layoutButtons(in parent: UIView) {
let speechButton = UIButton(type: .custom)
speechButton.frame = CGRect(x: parent.frame.width - 35, y: parent.frame.height - 35, width: 30, height: 30)
speechButton.setImage(UIImage(named: "sound_icon"), for: .normal)
speechButton.addTarget(self, action: #selector(Textual.textToSpeech), for: UIControlEvents.touchUpInside)
parent.addSubview(speechButton)
let fontSizeButton = UIButton(type: .custom)
fontSizeButton.frame = CGRect(x: textView.frame.width - 75, y: textView.frame.height - 35, width: 30, height: 30)
fontSizeButton.setImage(UIImage(named: "font_size_icon"), for: .normal)
fontSizeButton.addTarget(self, action: #selector(Textual.toggleFontSize), for: UIControlEvents.touchUpInside)
parent.addSubview(fontSizeButton)
// wrap text around the bottom buttons
let excludeSpeechButton = UIBezierPath(rect: speechButton.frame)
let excludeFontSizeButton = UIBezierPath(rect: fontSizeButton.frame)
self.textView.textContainer.exclusionPaths = [excludeSpeechButton, excludeFontSizeButton]
}
#objc func textToSpeech() {
if synth.isPaused {
synth.continueSpeaking()
} else if synth.isSpeaking {
synth.pauseSpeaking(at: .immediate)
} else {
let speechUtterance = AVSpeechUtterance(string: attributedText.string)
speechUtterance.rate = 0.5
synth.speak(speechUtterance)
}
}
#objc func toggleFontSize() {
if self.smallFontSizeMode == true {
self.smallFontSizeMode = false
} else {
self.smallFontSizeMode = true
}
// for each character, multiply the current font size by fontSizeModifier
// http://stackoverflow.com/questions/19386849/looping-through-nsattributedstring-attributes-to-increase-font-size
self.attributedText.beginEditing()
self.attributedText.enumerateAttribute(NSFontAttributeName, in: NSMakeRange(0, self.attributedText.length), options: NSAttributedString.EnumerationOptions.reverse, using: { (value, range, stop) in
if let oldFont = value as? UIFont {
var newFont: UIFont?
if self.smallFontSizeMode == true { // was big and now toggling to small
newFont = oldFont.withSize(oldFont.pointSize / 2)
} else { // was small and now toggling to big
newFont = oldFont.withSize(oldFont.pointSize * 2)
}
attributedText.removeAttribute(NSFontAttributeName, range: range)
attributedText.addAttribute(NSFontAttributeName, value: newFont!, range: range)
}
})
self.attributedText.endEditing()
self.textView.attributedText = self.attributedText
}
Presenting the UIViewController
func present(viewController: UIViewController, at location: CGRect) {
viewController.modalPresentationStyle = .popover
parentViewController.present(viewController, animated: true, completion: nil)
let popController = viewController.popoverPresentationController
popController?.permittedArrowDirections = .any
popController?.sourceView = parentView
popController?.sourceRect = location
}
UPDATE - I've added popController?.delegate = viewController as the last line of func present(viewController:at:) and below I've added extension UIViewController: UIPopoverPresentationControllerDelegate { }
To answer your question, you will need to tell your presenting view controller who to delegate, so add this below and let me know if it works:
popController?.delegate = viewController

Resources