I have implemented something that does the following:
I am showing a full-screen UICollectionView with different items. Underneath this view (out of sight) is a "detail" view for one of the items.
When a user long-presses one of the UICollectionView items, I would like to hide the UICollectionView to reveal the "detail" view behind.
I will then instantiate a new UIView which is hovering over this view and is draggable. The user can then drag and drop this new UIView into position on the "detail" screen.
The only part which I am having trouble with is the syncing of the long-press with the draggable view. I would like the user to long-press on the UICollectionView, and then be immediately dragging the draggable view.
How do I connect these two actions?
At the moment the UICollectionView calls a delegate on the lower view, which instantiates the draggable view:
- (void)contactAlgorithm:(ContactAlgorithmViewController *)contactFlowViewController didLongPressContact:(CDContact *)contact {
DraggableContactView *draggableView= [[DraggableContactView alloc] initWithContact:contact];
[self.view addSubview:draggableView.view];
}
But how do I make this draggable view the view which is being dragged by the long.press?
First get the frame of the item which was long pressed.
Add the draggable view at exactly that frame.
Now, add pan gesture recogniser to that view and set delegate of that gesture to viewController , and whenever move occurs delegate method will be called.
There change the frame of draggable view to follow touch.
Instead of adding pan gesture, you can use touchesMoved method of viewController.
CODE:
using below code, you can drag the view without using pan gesture.
//have a class property of DraggableContactView
#implementation ViewController{
DraggableContactView *dragableView;
}
Selector method of longPressGestureRecogniser
-(void)longPress:(UILongPressGestureRecognizer *)ges{
if(dragableView==nil){
dragableView=[[DraggableContactView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
dragableView.backgroundColor =[UIColor greenColor];
[self.view addSubview:dragableView];
}
CGPoint p =[ges locationInView:self.view];
[dragableView setCenter:p];
}
Related
So I have a homepage view that people see when they first boot up the app, it has several different options. Yesterday I added a tutorial overlay, so the first time they open the app I have a view that is 0.5 alpha black and is fullscreen over the other view, this view has white text and arrows pointing to functions on the page. I attached a tap gesture recognizer to this view and its action is to call the next tutorial screen ( 3 in total). Afterwords they all are hidden and the app acts as normal. This all works, except even though my view is full screen, with User Interaction Enabled checked and a gesture tap recognizer, the gestures / touches on the sub view still work. So if I just tap some white space on the app the tutorial and tap gesture work as expected, cycle me through the pages etc and works. However if I accidentally press a sub view button or do a gesture from the subview it will do the action (take you to a new page or w/e)
So basically as far as I can tell my view despite being on top of the other and having a tap gesture recognizer attached to the view the sub views are still getting pressed, any ideas?
Check the tap event view before doing any operation..
- (IBAction)yourTapEvent:(UITapGestureRecognizer *)gestureRecognizer
{
UIView *piece = [gestureRecognizer view];
if(piece == (view on which you have added gesture))
{
//Do your necessary operation
}
}
try this it would help you to disable gesture on its subviews
- (void)tapAction:(UITapGestureRecognizer *) gestureRecognizer{
UIView *v = [gestureRecognizer view];// Guesture added view
NSArray *temp = [self.view subviews];
for (int i = 0; i<temp.count; i++) {
if([temp objectAtIndex:i]== v){
// Do your swipe tap action here
}
}
}
I have been having trouble trying to drag a UIView that has a UIScrollView within it. The UIView drags up from the bottom of the screen, when it has hit the top you can use the UIScrollView inside it. When the user scrolls to the top of the UIScrollView, the UIView should drag down with their finger.
It should work like the Google Maps popup when you click a pin.
Update: I can get the dragging up of the UIView working (touchesMoved) that changes the Y value. The main functionality I am having problems with is the dragging down of the UIView when the user touches inside the UIScrollView. I want the user to still be able to drag the scrollview as normal until it reaches the top at which point the dragging action should then move the parent UIView down off the screen.
Update 2: This is the code you suggested to turn off the user interaction:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
if(scrollView.contentOffset.y<=0){
scrollView.userInteractionEnabled = NO;
}else{
scrollView.userInteractionEnabled = YES;
}
}
Most apps handle this scenario by using the UIScrollViewDelegate method scrollViewDidScroll.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
// check the scrollView.contentOffset.y to see if you
// have reached the top of the scroll view.
}
You can then check the contentOffset and continue with your dragging code the way you want.
I have a delete button that shows up when I swipe left on a table view's row.
I want to be able to hide this button if the user taps anywhere else in the view. How do I do that? I tried putting a giant button on bottom of all views but the tap outside is not being detected by the button.
In the viewDidLoad, I added the view controller as a target:
[self.backgroundButton addTarget:self action:#selector(backgroundButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
And in the callback I just have a message:
- (IBAction)backgroundButtonTapped:(id)sender {
NSLog(#"BACKGROUND VIEW TOUCHED");
}
But when I tap outside in a general area, I do not see the message.
I resolved the issue as follows:
. Created a view TopView subclassed from UIView
. Changed class of my top level view to this class.
. Within my logic at the proper place, stored the subview that needs to be hidden in the top view
self.view.mySubview = subview;
. Overrode hitTest:withEvent in top view. Here I detect the tap outside that of the subview and hide the subview as required.
I have UIViewController on my simple storyboard IPad project which contains UIScrollView which is placed over entire surface (1024 x 768). I have created 3 XIB files which are UIViews which my application loads on start in viewDidLoad and add them into UIScrollView. Each of these 3 XIB files contains only one UIButton.
This is hierarchy:
~ UIViewController (UIViewControllerClass is class for this
UIViewController)
~~ UIScrollView (contains 3 identical UIViews)
~~~ UIView (UIViewClass is File's Owner for this XIB file)
~~~~ UIButton
I would like that my UIViewControllerClass becomes aware of both: touch anywhere on UIScrollView component AND if UIScrollView is touched, if UIButton inside of UIView in UIScrollView is touched, to have information that exactly that button is touched.
I made IBAction inside UIViewClass for touch on UIButton inside UIView in UIScrollView and when I set User Interaction Enabled = YES on all elements (UIViewController, UIView and UIScrollView) this method is called as it should.
But at this point my UIViewControllerClass isn't aware that touch occurred inside UIScrollView on that UIButton. I made touch recognizer like this:
UITapGestureRecognizer *touch = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTouch)];
touch.numberOfTouchesRequired = 1;
and added it to UIScrollView component. In this way I am able to detect touch event on UIScrollView component in UIViewControllerClass, but touch event handler for UIButton in UIView which is inside UIScrollView isn't called anymore.
So, I need to have these two informations in UIViewControllerClass:
Touch on UIScrollView component was made
Touch on UIButton in UIView which is inside UIScrollView (if this button was touched) was made
I suppose that attaching touch event recognizer to entire UIScrollView component isn't solution, since it disables all touch event handlers I wrote inside UIViewClass.
I think solution is that somehow touches which are made on components in UIView inside UIScrollView should be sent up to UIViewControllerClass, but I didn't found a way to do this.
If anyone can help me, I'd be very grateful. Thanks in advance.
[edit #1: ANSWER by Zheng]
Tap gesture must have cancelsTouchesInView option set to NO!
For my case above, this line solves everything:
touch.cancelsTouchesInView = NO;
Many thanks to Zheng.
I don't know if this works for you or not, but I've given an answer about touch events for views inside scrollview here:
Dismissing the keyboard in a UIScrollView
The idea is to tell the scrollView not to swallow up all tap gestures within the scroll view area.
I'll paste the code here anyways, hopefully it fixes your problem:
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(hideKeyboard)];
// prevents the scroll view from swallowing up the touch event of child buttons
tapGesture.cancelsTouchesInView = NO;
[pageScrollView addGestureRecognizer:tapGesture];
[tapGesture release];
...
// method to hide keyboard when user taps on a scrollview
-(void)hideKeyboard
{
[myTextFieldInScrollView resignFirstResponder];
}
You can subclass your UIScrollView and override the method - hitTest:withEvent: which is called by the system to determine which view will handle the event. Whenever it is called, you can assume that a touch event occurred inside the scroll view, and by calling the super implementation, you can get the view which would normally process the event.
you can capture any kind of gestures in the UIscrollView. Make sure you also handle some of the default properties as well like set cancelsTouchesInView property to false, it is true by default. Also give some tag nos to your sub views to distinguish in selectors. & also enable their User interaction to true.
let tap = UITapGestureRecognizer(target: self, action:
selector(didTapByUser(_:)))
I have two UIScrollViews on my screen and I need to be able to drag a UIView from one scrollview to the other.
At the moment, I have a UILongGestureRecognizer on the UIView that I want to move, such that when the user starts dragging it, I make the view follow the touch:
- (void)dragChild:(UILongPressGestureRecognizer *)longPress {
[[longPress view] setCenter:[longPress locationInView:[[longPress view] superview]]];
}
But when I get the boundary of the starting UIScrollView, the view disappears because it's locked into that scrollview's bounds.
Is there a way to "pop" it out of the scrollview when I start dragging such that I can carry it over to the other scrollview?
Also, how do I test for the "drop" location? I want to know if it's been dropped over a certain other view.
Or am I going about this all the wrong way?
Thanks guys
If you will need to drag it from a scroll view to another do the following (pseudo code)
when you start dragging do the following
//scrollView1 is the scroll view that currently contains the view
//Your view is the view you want to move
[scrollView1.superView addSubView:yourView];
now when dropping the view, you will need to know if it is inside the other scrollview
//scrollView2 is the second scroll view that you want to move it too
//Your view is the view you want to move
CGPoint point = yourView.center;
CGRect rect = scrollView2.frame;
if(CGRectContainsPoint(rect, point))
{
//Yes Point is inside add it to the new scroll view
[scrollView2 addSubView:yourView];
}
else
{
//Point is outside, return it to the original view
[scrollView1 addSubView:yourView];
}
Here is an untested idea:
When the drag begins, move the dragging-view out of the scroll view (as a subview) and into the mutual superview of both scroll views.
When the drag ends, move the dragging-view out of the superview and into the new scroll view.
You'll probably have to be careful with coordinate systems, using things like [UIView convertPoint:toView:] to convert between the views' different perspectives when moving things around.