How can I get CGRect of tapped rectangle in ScrollView? [duplicate] - swift

This question already has answers here:
How to get local tap position in onTapGesture?
(2 answers)
Closed 11 months ago.
Hello, I want to know the CGRect(coordinates and width/height) of dynamic size rectangle which user tapped in ScrollView.
Is there any way to get this?

If you have added UITapGestureRecognizer in every view then you can get the tapped view frame as -
#objc func tapFunction(gesture: UITapGestureRecognizer) {
let viewFrame = gesture.view.frame
let height = viewFrame.height //for height
}
You need to add gesture in every view with a parameter.
let tap = UITapGestureRecognizer(target: self, action: #selector(tapFunction(gesture:)))
yourView.addGestureRecognizer(tap)

Related

copying label text to clipboard when clicked [duplicate]

This question already has answers here:
How to make a UILabel clickable?
(12 answers)
Closed 3 years ago.
first I have to make UILabel clickable and when it clicked it should copy its text to clipboard. I am using Xcode 10 with swift 5.1.
so firstly I am expecting label to be clickable and after that, this click action copy its text to clipboard. this is a basic level program.
To make the label "clickable" :
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(labelDidGetTapped:))
yourLabel.userInteractionEnabled = true
yourLabel.addGestureRecognizer(tapGesture)
Then, to retrieve the text from the label and copy it to the clipboard :
#objc
func labelDidGetTapped(sender: UITapGestureRecognizer) {
guard let label = sender.view as? UILabel else {
return
}
UIPasteboard.general.string = label.text
}
Note that there won't be any effect when tapping the text, it would be best to present some kind of feedback to the user, by animating the label's alpha for example
Part one of the answer can be followed as -
#IBOutlet weak var clickAble: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// this code is for making label clickable.
clickAble.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer.init(target: self, action: #selector(tapFunction))
tap.numberOfTapsRequired = 1
clickAble.addGestureRecognizer(tap)
}
Part 2nd of answer is as-
#objc func tapFunction(sender:UITapGestureRecognizer)
{
// this is for copying label text to clipboard.
let labeltext = clickAble.text
UIPasteboard.general.string = labeltext
}
}
Try making user interaction enabled. For example:
yourLabel.isUserInteractionEnabled = true
Check this previous thread. This question has already been answered.
How to make a UILabel clickable?
For copying text to your clipBoard.
UIPasteboard.general.string = yourLabel.text

How to call a function when the Compass Button of a mapView is pressed

I have developed an app showing a map view with a compass button. The natural function when pressing this compass button is that the map is being oriented to north.
Now I want to call a function when pressing this compass button.
A view of the app with a map can be found there (compass button is visible in the upper right corner)
http://aceingolf.com/wp-content/uploads/2018/12/0.jpg
The code below is working fine. It is just shown to give a complete view.
#IBOutlet weak var mapView: MKMapView!
let compassButton = MKCompassButton(mapView: mapView)
compassButton.compassVisibility = .visible
mapView.addSubview(compassButton)
I am looking for a way to create an action when the user presses the compass button on the map view.
I believe MKCompassButton inherits from UIView, So you can just add a UITapGestureRecognizer to the compassButton with an action like following:
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleCompassTap))
compassButton.addGestureRecognizer(tapGestureRecognizer)
#objc func handleCompassTap() {
// Implement your feature when the compass button tapped.
}
Take emrepuns code
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleCompassTap))
compassButton.addGestureRecognizer(tapGestureRecognizer)
#objc func handleCompassTap() {
// Implement your feature when the compass button tapped.
}
and add this line
tapGestureRecognizer.numberOfTouchesRequired = 1
or
tapGestureRecognizer.numberOfTapsRequired = 1

UIButton action is not triggered after constraint layouts changed

I have got an UIButton on a storyboard ViewController. When I load data into the form and the layout is significantly changing the button does not recognise the touch action.
I have figured out that when button is visible on the scrollview right after it if filled with data, the touch action works.
If the data too long and the button is not visible at first, just when it is scrolled into the display, the touch action does not work.
I was checking if something is above the button, but nothing. I have tried to change the zPosition of the button, not solved the problem.
What can be the issue?
I have made custom classes from the UIScrollView and the UIButton to check how the touches event triggered. It is showing the same behaviour, which is obvious. If the button is visible right at the beginning, the UIButton's touchesBegan event is triggered. If the button moves down and not visible at the beginning, it is never triggered, but the scrollview's touchesBegan is called instead.
Depending on the size of the data I load into the page sometimes the button is visible at the beginning, but the form can be still scrolled a bit. In this case the button still work, so it seems that this behaviour is not depending on if the scrollview is scrolled before or not, just on the initial visibility of the button.
Is there any layout or display refresh function which should be called to set back the behaviour to the button?
The code portion which ensures that the contentview is resized for the scroll if the filled data requires bigger space.
func fillFormWithData() {
dispDescription.text = jSonData[0]["advdescription"]
dispLongDescription.text = jSonData[0]["advlongdesc"]
priceandcurrency.text = jSonData[0]["advprice"]! + " " + jSonData[0]["advpricecur"]!
validitydate.text = jSonData[0]["advdate"]!
contentview.layoutIfNeeded()
let contentRect = CGRect(x: 0, y: 0, width: scrollview.frame.width, height: uzenetbutton.frame.origin.y+uzenetbutton.frame.height+50)
contentview.frame.size.height = contentRect.size.height
scrollview.contentSize = contentview.bounds.size
}
Ok, so another update. I have coloured the contentview background to blue and the scrollview background to white. When I load the data and resize the layout constraints, the contentview is resizing as expected, however now the scrollview is going to the bottom. After I scroll the view it is resizing to the original size which fits the screen. Now the button is only recognised when I touch the are which is blue behind. With the white background it is not recognised anymore, so it seems that the scrollview is hiding the button.
Let me get this clear the button is added in storyboard and it is a spritekit project?? If you are using zPosition?? Why don’t u connect the UIButton via the assistant editor as an IBAction then the action is always tied to the button.
You can also do it differently
Create an SKLabelNode and put it on the screen where you want to have the button and then set a name to it as myButton
override func touchesBegan(_ touches: Set<UITouch>, with event:
UIEvent?) {
if let touch = touches.first {
let location = touch.location(in: self)
let tappedNodes = nodes(at: location)
for node in tappedNodes {
if node.name == "myButton" {
// call your action here
}
}
}
}
EDIT 1:
You could also try auto resizing your scrollView.content this works also if you are adding any views via the app or programmatically
private func resizeScrollView(){
print("RESIZING THE SCROLLVIEW from \(scrollView.contentSize)")
for view in scrollView.subviews {
contentRect = contentRect.union(view.frame)
}
scrollView.contentSize = CGSize(width: contentRect.size.width, height: contentRect.size.height + 150)
print("THE CONTENT SIZE AFTER RESIZING IS: \(scrollView.contentSize)")
}
EDIT 2: I think I found the issue with your project. You need to move the MessageButton(UzenetButton) above DispDescription label in the object inspector in that way it will always be above your message textView.
At the moment the UzeneButton is at the very far back in your view hierarchy so if your textView is resizing whilst editing it covers the button that is why you cannot click on it.
See #Endre Olah,
To make situation more clear do one more thing, set clipToBound property of contentview to true.
you will notice that after loading of data your button not fully visible, it means it is shifting out of bound of its parentView (ContentView)
And that's why button is not taking your touch. However, if you carefully touch upper part of button it still do its job. Because upper part is still in bound of ContentView
Solution :
After loading of data you have to make sure that you increase height of ContentView such that button should never go out of bound of its parentView(ContentView).
FOR EXAMPLE
#IBOutlet var heightConstraintOfContentView : NSLayoutConstraint!
After loading of data
let contentRect = CGRect(x: 0, y: 0, width: scrollview.frame.width, height: uzenetbutton.frame.origin.y+uzenetbutton.frame.height+50)
heightConstraintOfContentView.constant = contentRect.size.height
contentView.layoutIfNeeded()
I use following steps when I need to use scrollview with dynamic content:
1) Firstly add a scrollView with top, bottom, trailing and leading is 0 to super view.
2) Add a view to scrollView and view's trailing, leading bottom and top space to scrollView can be set to 0 (or you can add margin optionally).
3) Now, you should add UI elements like buttons, labels with appropriate top, bottom, trailing and leading margins to each other.
4) Lastly, add equal height and equal width constraint to view with Safe Area:
and change equal height priority of view to 250:
It should solve your problem with UIScrollView.
Finally, I have found the solution in another chain, once it became clear that the scrollview's contentview is resizing on scroll event to the original size. (Not clear why this is like this, but that is the fact.)
So I had to add a height constraint to the contentview in the storyboard and create an outlet to it and adjust this constraint when the content size is changing, like this:
#IBOutlet weak var ContentViewHeight: NSLayoutConstraint!
func fillFormWithData() {
dispDescription.text = jSonData[0]["advdescription"]
dispLongDescription.text = jSonData[0]["advlongdesc"]
priceandcurrency.text = jSonData[0]["advprice"]! + " " + jSonData[0]["advpricecur"]!
validitydate.text = jSonData[0]["advdate"]!
contentview.layoutIfNeeded()
let contentRect = CGRect(x: 0, y: 0, width: scrollview.frame.width, height: uzenetbutton.frame.origin.y+uzenetbutton.frame.height+50)
contentview.bounds = contentRect
scrollview.contentSize = contentRect.size
----------- This is the key line to the success ----------
ContentViewHeight.constant = contentRect.size.height
----------------------------------------------------------
}
After this is added, it works perfectly.

TapGestureRecognizer not firing in swift

Hi I'm having no cards to used to fixed this. Here we go.
I have this five imageview this is the declaration of first imageview but basically they have same declaration
#IBOutlet weak var first: UIImageView!{
didSet{
first.tag = 1
first.addGestureRecognizer(tapGesture())
}
}
and Then the tapGesture() method is this
private func tapGesture() -> UITapGestureRecognizer {
let tapGesture = UITapGestureRecognizer(target: self, action: Selector("iconTapped:"))
tapGesture.numberOfTapsRequired = 1
tapGesture.numberOfTouchesRequired = 1
return tapGesture
}
the action when the imageview is tapped the iconTapped() method is called, this is the code
func iconTapped(sender:UITapGestureRecognizer){
if let tag = sender.view?.tag{
processGesture(tag)
}
}
I have put all imageview userInteractionEnable to true but still not firing. Could anyone help me?
Some factor may or may not help, inside the viewdidload I update constraints and do some animation to imageview, but I'm not adding any subview programmatically
after trying so many things, I look on my view hierarchy and figure out that the parent view where my UIImageView rest userInteractionEnable is set to false(unchecked) in storyboard.
in this case the parentview is my superview, to fixed that I need to add this in viewDidLoad()
self.view.userInteractionEnabled = true
or
click the parentView in storyboard and in attributes inspector check the User Interaction Enable.
ps. sorry for silly mistake but I'll keep this question posted there might be other encountering same problem.

How can I find button tag after implementing gesture recogniser in swift?

I want an action to be done once when someone swipes within a button.
My current code is as follows:
let recogniser = UISwipeGestureRecognizer(target: self, action: "didTapButton2:")
recogniser.direction = .Up
button.addGestureRecognizer(recogniser)
func didTapButton2(sender: UIGestureRecognizer!) {
//Here I want to be able to recognise which button this was sent from (they are all tagged)
let button = sender. as UIButton //Gives an error
I need to use gesture recognisers as opposed to UIControlEvents as I need the event to only fire once. Using this makes the event fire loads of times - just need it to go once:
button.addTarget(self, action: "didTapButton2:", forControlEvents: .TouchDragInside)
Does anyone have a solution? Thanks
A UIGestureRecognizer has a property called view which is the view that it is attached to. View is declared as an optional, so you need to unwrap it:
if let button = sender.view as? UIButton {
// use button
if button.tag == 10 {
// handle button tagged with 10
}
}