Unable to use All UITableViews after adding a subview to the UIApplication Window - ios

Strange issue i'm running into that is honestly really frustrating. I've created a side menu bar for my app that I insert using this function:
- (void)insertMenunOnView:(UIView*)view atPosition:(CGPoint)position
{
_menuButton.frame = CGRectMake(position.x, position.y, _menuButton.frame.size.width, _menuButton.frame.size.height);
[view addSubview:_menuButton];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(dismissMenu)];
[view addGestureRecognizer:singleTap];
view.userInteractionEnabled = true;
for (UIButton *button in _buttonList)
{
[_backgroundMenuView addSubview:button];
}
_backgroundMenuView.frame = CGRectMake(view.frame.size.width, 0, 150, view.frame.size.height);
_backgroundMenuView.backgroundColor = [UIColor colorWithRed:0.09 green:0.15 blue:0.18 alpha:0.7f];
[view addSubview:_backgroundMenuView];
}
it is implemented here in my UITableViewController viewDidAppear method:
override func viewDidAppear(animated: Bool) {
sideBar.insertMenuOnView(self.view, atPosition: CGPointMake(100, 200))
}
If I do this, it renders my TableView useless. I can select the cells if I tap rapidly back and forth between multiple cells. After about ten seconds of doing this, the cell being tapped will initiate the appropriate segue.
No I tried this hoping I'd be able to get over this problem by changing the function to
- (void)insertMenunOnView:(UIWindow*)view atPosition:(CGPoint)position
{ //// do stuff
}
Guess what!? Now every single tableView in my entire app is behaving the same as the first! Takes about thirty to forty taps until the cell finally calls didSelectRowAtIndexPath
What on earth is going on?

Disable tap gesture on view when side menu is closed and enable it when side menu is open.
At present your tap gesture is overriding tap gesture of table view.

The issue is-
When you call sideBar.insertMenuOnView(self.view, atPosition: CGPointMake(100, 200))
this method is called
- (void)insertMenunOnView:(UIView*)view atPosition:(CGPoint)position
inside your dismissMenu event handler you should remove gesture recognizer
inside above method you are adding a gesture recognizer on the current view, when you are done with this view, then you are dismissing it, but the tap gesture still exists and is added over the current view. Now when you try to select any row of the table the touch is not passed to the table as it is intercepted by the layer above it (which of-course is tap gesture recognizer added over the current view.)
To resolve this issue you should remove the tap gesture recognizer from the current view inside your dismissMenu method. Doing so will pass your touches to the corresponding row of the tableView.

Related

UICollectionView within UIScrollView: Long Press

I have added a UILongPressGestureRecognizer to my UICollectionView that is within a subclass of UIScrollView. (The UIScrollView is paged so there are 3 horizontally stacked UIViewControllers).
My code to add the UILongPressGestureRecognizer:
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPress:)];
longPress.delegate = self;
longPress.minimumPressDuration = 0.5;
longPress.delaysTouchesBegan = YES;
[self.collectionView addGestureRecognizer:longPress];
And an NSLog in my handleLongPress: method. Currently I hold down on a UICollectionViewCell, it highlights, but the long press is not activated. I believe my UIScrollView subclass is consuming the long press and not passing along to the UICollectionView. When I lift my finger, the didSelectItemAtIndexPath: method is called.
In my UIScrollView subclass, the only customization I have is the following:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(nonnull UIGestureRecognizer *)otherGestureRecognizer {
// This line enables the swipe to delete in the Messaging VC.
return ([otherGestureRecognizer.view.superview isKindOfClass:[UITableView class]]);
}
This was done to enable cell swiping in my UITableView, which is one of the pages of my UIScrollView. The swiping works no problem, and I have tried a number of similar checks for UICollectionView and UICollectionViewCell here but have not gotten the long press to register yet. Any advice appreciated.
Edit: I have added the long press on another UICollectionView and it is functional, but the cell never shows highlighted/selected status. I guess that is a clue as to why I can't get this long press gesture to fire.
My issue was that I was adding the gesture recognizer in the -init method. That did not work. Simply moving the code to -viewDidLoad fixed the problem.

How can I add multiple taps to a button or a UIView?

I want one of my screens to be accessed only if the user taps three times on a button within a second. eg. if there's a button on View controller A, a user should tap 3 times within a second on that button to get to View Controller B.
Any help is appreciated!
Buttons are not set up to respond to multiple taps. You'll have to simulate that yourself.
As others have said, you can create a tap gesture recognizer and attach it to any view. For some views you'll need to set the userInteractionEnabled flag to true before it will respond though.
If you want a button to handle double-taps you'll need to have the button with no action installed but a 2 click gesture recognizer attached.
You need to add tap gesture recogniser to your custom View.
-(void)handleTapGesture:(UITapGestureRecognizer *)tapGestureRecognizer{
NSLog(#"3 tapped");
//add code to present another View Controller
}
-(void)buttonView{
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTapGesture:)];
tapGestureRecognizer.numberOfTapsRequired=3;
[self.customButtonView addGestureRecognizer:tapGestureRecognizer];
}
Swift:
func handleTapGesture(tapGestureRecognizer: UITapGestureRecognizer) {
NSLog("3 tapped")
//add code to present another View Controller
}
func buttonView() {
var tapGestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "handleTapGesture:")
tapGestureRecognizer.numberOfTapsRequired = 3
self.customButtonView.addGestureRecognizer(tapGestureRecognizer)
}
You can call this method in viewDidAppear.

PanGestureRecognizer fails to fire on UIScrollView when SWRevealController is being used

I am using the SWRevealViewController project by John Lluch for my application and I have run into one minor issue that I can't seem to get straight.
I am using the SWRevealViewController to access my apps options menu from anywhere in my app just by swiping to the right and the main view slides to reveal the menu behind it.
This is handled by a swipe gesture recognizer that is added to the main view. To improve UX, I create a button to cover the main view when it gets swiped out of the way so all the user has to do to close the menu is tap the small part of the view that is showing or grab the view and pull it back.
It works great except on one of my views in which the majority of the view is a UIScrollView. To get it to work I have to add the gesture recognizer to the UIScrollView as well as the super view. But for some reason, once the view is swiped out of the way, the swipe gesture recognizer stops responding. But this only happen on the view where the majority of the screen is a scroll view thus, what the user grabs to pull the screen back is the scroll view.
Hopefully that was understandable. Any light that you guys can shine on this will be very helpful.
-(void)viewDidAppear:(BOOL)animated {
// so the user can tap the button to show the menu
[menuButton addTarget:self.revealViewController action:#selector(revealToggle:) forControlEvents:UIControlEventTouchUpInside];
// so the user can swipe to show the menu
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
// so the user can swipe the scrollview to show the menu
[mainScrollView addGestureRecognizer:self.revealViewController.panGestureRecognizer];
self.revealViewController.delegate = self;
}
- (void)revealController:(SWRevealViewController *)revealController willMoveToPosition:(FrontViewPosition)position {
if (position == FrontViewPositionRight) {
//create the button so the use can tap to close the menu
returnButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
[returnButton addTarget:self.revealViewController action:#selector(revealToggle:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:returnButton];
} else {
[returnButton removeFromSuperview];
returnButton = nil;
}
}
So I just discovered that this issue has already been addressed within the SWRevealViewController Project. This post pointed me in the right direction. They have added a tap gesture recognizer that has the behaviour I was creating with the dynamically created button.
Adding
[self.view addGestureRecognizer:self.revealViewController.tapGestureRecognizer];
removes the need for the button, thus allowing the view to respond to both recognizers.

Hide UITableView on touches outside the tableview

I have a small UITableView that is hidden when the view is loaded. When i click on "SHOW" UIButton, the UITableView is made visible by myTableView.hidden=NO;
I want to hide UITableView when a user touches outside its frame. Thanks for any help!
Best Approach
Simple.Before show up the UITable View add one more grayed out/Transparent view then add tap gesture recogniser on it to hide it . That's it.
Show Overlay View first - alpha will be 0.5f and background color should be clear color.
show the table view.
NOTE: over lay view should have tap recogniser which will hide the overlay and table view
in View did load
UITapGestureRecognizer *tapRecog = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(overlayDidTap:)];
[myOverLayView addGestureRecognizer:tapRecog];
- (void)overlayDidTap:(UITapGestureRecognizer *)gesture
{
//hide both overlay and table view here
}
Bad Approach
We should not add tap recogniser on main view itself. Because it may have lots of
controls inside of it. so when user tap on it. it will perform its operation. So to avoid
it we can simulate the same behaviour by above approach
You can get touch position by this:
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureCaptured:)];
[self.view addGestureRecognizer:singleTap];
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
CGPoint touchPoint=[gesture locationInView:self.View];
}
Then just check if the point is in tableview frame. If not then hide the tableview. Hope this help. :)
Subclass UITableView, override pointInside:withEvent:. It is templated for this reason.
Something like:
-(BOOL)pointInside:(CGPoint) point withEvent:(UIEvent*) event
{
BOOL pointIsInsideTableView = [super pointInside:point withEvent:event];
BOOL pointIsOutsideTableView = // Some test
return pointIsInsideTableView || pointIsOutsideTableView;
}
So you can catch the touch in table view implementation, where it belongs logically in this case.

Removing UIImageView if the user taps on any point outside the UIImageView

My app shows an UIView which contains four UIButtons, one of them removes the UIView, but I also need is to remove the UIView, including all containing buttons when the user taps outside it.
This is how I remove the UIView using a button action:
-(IBAction)closeSideTasks: (id)sender
{
UIView * backgroundView = (UIView *)[self.view viewWithTag:7];
[backgroundView removeFromSuperview];
}
Any help or advice is welcome.
MORE INFORMATION:
This is the scenario: there is a table view. If the user swipes from left to right on a row, then the UIView appears on the right side of the view. The UIView *newView is removed after tapping on each of the buttons inside it and executing each button action. But may be the user does not tap on any of the buttons, and the UIView remains on the view. Then, what I want to achieve is a way that the UIView *newView gets removed if the user taps anywhere outside it, to prevent that it remains always on the view...
Check out UITapGestureRecognizer.
Example:
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] init];
tapGesture.delegate = self;
tapGesture.numberOfTapsRequired = 1;
tapGesture.numberOfTouchesRequired = 1;
[tapGesture addTarget:self action:#selector(tapChangeImage)];
[self.profileImageView addGestureRecognizer:tapGesture];
Now add the action method:
#pragma tap gestures
-(void)tapChangeImage{
// Remove view from superview!
}
Put a large button, full screen, with no graphics, no text, and a clear background. Have its action also remove the background

Resources