Single Tapping not being detected on dynamically created uibuttons - ios

It was necessary to create a subclass of UIButton, lets call it subButton. These subButtons are instantiated one by one and dynamically added to an UIScrollView object.
Unfortunately the subButtons aren't reacting as expected. After scrolling away from the first dynamic generated subButtons and then returning back to them. They loose their reactivity to single tapping. I can not explain this behaviour. Can somebody explain why its behaving this way?
Many thanks.
Source code
self.subButton = [[SubButton alloc]initWithFrame:CGRectMake(69.5, y, 201, 114)];
[self.subButton setBackgroundColor:[UIColor blueColor]];
self.subButton.imageData = imageData;
self.subButton.videoPath = videoPath;
self.subButton.vidIndex = _indexVideo +1;
[self.subButton drawVidPreview];
[self.subButton setTag:(_indexVideo +1)];
[self.subButton addTarget:self action:#selector(handleSingleTap:) forControlEvents:UIControlEventTouchUpInside];
[self.videoScroll addSubview:self.subButton];
[_videoPreviews addObject:self.subButton];
The subButton method drawVidPreview adds some subviews to itself.

Do the buttons not respond at all, or just not to single-tap? That might help us help you.
If they don't respond at all, I would check your view hierarchy to make sure no other view (perhaps invisible) are sitting above your buttons. Or, perhaps are the buttons not being added to the parent view you think?

Please make sure you are not adding the same UIGestureRecognizer instance to all of the UIButtons, instead for each UIButton you need to add a separate instance, however all gesture instance can point to the same target.

At last, i could solve the problem. The reason why the first subButtons did not respond to single tapping with UIControlEventTouchDown is because the uiScrollview content offset was set to a negative y value. This first of all was not necessary and was done out of pure laziness. I corrected it by giving it a positive value.
So my conclusion is, if you do not set the content offset or content size of the scrollView correctly, some dynamically added buttons to the scrollView might not respond to tapping appropriately. This is even the case if all Buttons are placed completely on a uiScrollview object.
This I could confirm by playing around with the content size of the uiScrollview instance too. I changed size of the y value of uiScrollviews instance just by few points and then some of the last buttons did not respond to tapping anymore.
Just by increasing the content size of the y value again, made the buttons responsive again.

Related

How to bring subview to front in interface builder without changing its position

I want to ask a simple question how can I temporary bring a subview to front to view its element without changing its position by dragging and dropping. The problem i face all the time is i forgot to put the views back to there position and that causes lot of trouble specially if you are working on the view that have large number of subviews.
Question : Is there any shortcut or any functionality that can show the view temporary without dragging, changing its frame or making any changes in its hierarchy.
For a view controller like this :-
FYI, for those who are wondering, the view closest to the bottom of the list (on the left) will show in the front. So in the case below, view 'a' will be in front of 'b' and 'b' will be in front of 'c'
XIB:
If you need your views to be readily accessible for viewing/editing without having to rearrange them, I would actually recommend breaking them out into their own view and then stitching them together in the correct order in your code. This will ensure that all elements will be put in the proper order and will always be easily editable. Something like this:
And then in your code, in somewhere like viewDidLoad:
[self.view addSubview:view2];
[self.view addSubview:view3];

UIGestureRecognizer not called after setting UIViews frame inside UIScrollView

i am having some very strange issue. Basically i am implementing a drag and drop view with a snap to the horizontal 1D grid. Well, so when i drag a view and its center coordinate X is bigger or smaller then a different view, the non-dragged view should be animated to the left or right of its original position.
This works fine most of the time. But in some special cases its not working. In some situations specific situations the view does not receive any gesture callbacks anymore. I can reproduce this issue and have found out that when i remove the code that applies the animation, everything its working fine.
Basically this is the code that is called when the dragged view is at a position where the view below should be moved to the left or right
/**
* Animate element to its saved position
*/
- (void)switchElement:(unsigned int)draggedIndex with:(unsigned int)otherIndex
{
// first animate
UIView *view = views[draggedIndex];
UIView *otherView = views[otherIndex];
// IF I COMMENT THIS OUT, EVERYTHING WORKS FINE
otherView.frame = [self getImageRectForIndex:draggedIndex];
// now switch internally
if(draggedIndex != otherIndex)
{
// switch views
views[draggedIndex] = otherView;
views[otherIndex] = view;
}
}
Any idea if there is something to have in mind if i animate UIViews and have gesture recognizers attached to them?
If somebody is willing, i can paste the whole class here to test it.
SOLUTION
I am having some "highlight" views in my design. And i have moved the relevant views behind those transparent background views by accident. So now i am not using addSubview: but insertSubview:atIndex: instead.
But marking #Anthonin C. answers as the right one. Because it pointed me in the correct direction (I found it out by overriding the hitTest: method)
Would you please track the otherView.bounds property to verify that your touch isn't out of bounds. I faced this issue recently and Apple documentation provide solution here : Delivering touch events to a view outside the bounds of its parent view
Sorry, I don't have enough reputation to comment your answer.

How do I show and/or hide a subview using swift

So I've created a ViewControl in my storyboard that has 3 subviews. Each one represents a different view I want to show depending on which table row was selected on the previous screen (NavControl). I start with all of the subviews hidden via the Attributes Inspector's 'hidden' attribute being checked. All of the objects within each of these views are NOT hidden, but are being hidden because the subview itself is hidden (obviously). Thinking I could use the tag attribute I've given each of the three subviews a tag (0, 1 and 2), but can't figure out how to use that either (just in case this is useful as providing me with an option of how to do this I wanted to mention it here).
So, how the heck do I show and then hide any of these subviews? I don't want to go through each object in a subview and toggle its hidden property to true/false I feel like I should just be able to 'show/hide' the entire subview. thus achieving the same result, but much more succinctly.
I can't find anything that will help me via web searches or stackoverflow searches.
My code is very simple. I capture the row that was selected in the previous screen and pass it to a variable on the details screen that contains the subviews. I know this is working because I've set up println()'s on the details screens viewDidLoad function. So now all I have to do is going into each of these conditions and tell it which subview to show and/or hide.
Thanks I appreciate all of this communities help! I'd be lost without it.
Use this to hide a view in swift
viewVar.isHidden = true
You should create IBOutlets for each of the three subviews. Then you can show/hide each of them directly from those references. If you hide a view, it will automatically hide its subviews.
Once you have an outlet for the view, you can do this:
viewYouWantToHide.isHidden = true
If you have tags for each view you can hide and display them using:
Objective C
For Hiding:
[[self.view viewWithTag:1] setHidden:YES];
Showing:
[[self.view viewWithTag:1] setHidden:NO];
In Swift:
Hiding:
self.view.viewWithTag(1)?.isHidden = true
Showing:
self.view.viewWithTag(1)?.isHidden = false
NOTE: Replace 1 with your tag value.
however the fact that isHidden is a naming convention for checking the status and is a getter method
but despite that fact in swift we use it as setter and getter property
view.isHidden = true

How to force scrollRectToVisible: animated:

I want to make the scrollRectToVisible:animated: work even when the contentSize is only set to 1 page size.
The reason: I have multiple pages in the UIScrollView but want to maintain the hard-drag provided by the UIScrollView when it is on the edges. If I set the contentSize accordingly to the number of pages I actually have, that hard-drag will be lost.
How I wish it worked:
I keep track of which page to go to in "- (void)scrollViewDidScroll:(UIScrollView*)scrollView"
I then call "[self.scrollView scrollRectToVisible:frame animated:YES];" in "- (void)scrollViewDidEndDragging:(UIScrollView*)scrollView willDecelerate:(BOOL)decelerate" if the next page number is different than the current one.
What happens: Nothing, the scrollRectToVisible:frame animated:YES does nothing because the contentSize is set to only 1 page width&height. I have tried to set the contentSize to be 2*height before calling the scrollRectToVisible method, and it sort of works, but scrolls back to the current page number.
So my question is, how can I force the UIScrollView to scroll to a certain position or at least emulate that behaviour?
I've solved the issue using another method. I keep track of the position in "scrollViewDidScroll" and animate all the UIViews position accordingly. If anyone wants more information about this let me know, but I think it's pretty straight forward and way more simple than what I was trying to achieve before.

How can I create a dynamic overlay for a UIButton?

My application has a few portions that have really big buttons (640x130, 230x150, etc.) What I need is to have a way to update different portions of the button, with different text. Initially, I assumed that in my code I could create various UILabels and then add them as subviews to my button. However, as soon as I try to add a UILabel to the button as a sub-view, my app crashes.
What is the easiest way to create an overlay for a button, that I can completely layout myself, without preventing button taps from being interested using overlay controls?
I imagine there are multiple ways to solve this problem. However, the best solution for my case should use the fewest lines of code (I have quite a few of these types of buttons) and I'd like to be able to continue using some form of configurable button within IB.
I'm not opposed to subclassing UIButton but, if I do, I would like to be able to use it in IB. I've never created a custom UIView for such a circumstance, so I'd need help defining that type of subclass so that it will work correctly in IB.
You need to add the subview to the containing view - not the button. To ensure that is doesn't interfere with button presses, be sure to set it to:
[myCustomTextOverlay setUserInteractionEnabled:NO];

Resources