how does a UIGestureRecognizer get its locationInView inside a scrollView? - iphone

We had some consultants build some code for us and the way they have it laid out is there is a UIScrollView, and a UIView inside it.
There is another UIView icon that gets added as a subview to the scrollView based on a selection in a table. When this icon gets selected a popover is presented. In the present popover code, they use the gesture's view to calculate the frame and where to present the popover.
Now I'm tasked to present the popover with a selection in the table. When the zoom is = 1, that's pretty easy. I just grab the size of the UIScrollView, calculate where I add the icon, then present the view from that icon.
When I do it at a different zoom level though, my code falls apart since I don't know exactly where I am in the scrollView. I log the consultant's gesture from their method and they'll get origin.y position's of 5000. That's why I'm asking on how the locationInView works inside a scrollView to try to figure out where I am in the yPosition to present my popover from the right place. Any thoughts? Thanks.
- (void)handleSingleTap:(UIGestureRecognizer *)sender {
id targetView = [sender view];
CGPoint point = [sender locationInView:self.scrollView];
NSLog(#"point: %f %f", point.x, point.y);

Related

iPhone/iOS: How to implement Drag and Drop for subviews of a Scrollview?

I am having an horizontal scrollview in an UIViewController, where i have many images in small sizes. I am keeping the images in scrollview because the images are more, so user can scroll horizontally and choose images. But, the problem is, i have to select an image and drag and drop to that UIViewController view. But, since the images are in scrollview, drag and drop images into UIViewcontroller's view is not working, not detecting the touch events too.
Please NOTE: If i don't have scrollview but just keeping the images also into UIViewcontroller's view itself, drag and drop the images on the same screen, is working very well.
How can I resolve this when I need to have scrollview and drag and drop images, any advice/help please?
Hi Getsy,
I am not going to provide you code directly but give idea how to manage this.
You can manage this way, When you get touch on your object in scrollView at that time or when you move that object by draging at that time disable scroll by myScroll.scrollEnabled = NO;
Then When on endTouch you can enable Scroll by myScroll.scrollEnabled = YES; So by this you can manage you object moving in scroll hope you got logic.
Here is the demo code : Drag and Drop with ScrollView. which has same logic of Disabling scroll view on touchesMoved: and Enabling scroll view on touchesEnded:.
I did implement that behaviour before without any subclassing.
I used canCancelContentTouches = NO of the UIScrollView to make sure the subviews handle there touches on their own. If a subview (in your case an image) was touched, i moved the view out of the scrollview onto the superview and started tracking it's dragging. (You have to calculate the correct coordinates within the new superview, so it stays in place).
After dragging finishes, i checked if the target area was reached, otherwise I moved it back into the scrollview. If that's not detailed enough I could post some code.
Well here is my example code: Github: JDDroppableView
Getsy,
Try the code for drag and drop the objects :
-(void)dragAndDropWithGesture {
UILongPressGestureRecognizer *downwardGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(dragGestureChanged:)];
[scrollViewAlfabeto addGestureRecognizer:downwardGesture];
for (UIGestureRecognizer *gestureRecognizer in myscrollView.gestureRecognizers)
{
[gestureRecognizer requireGestureRecognizerToFail:downwardGesture];
}
}
- (void) dragGestureChanged:(UIPanGestureRecognizer*)gesture
{
CGPoint point = [gesture locationInView:scrollViewAlfabeto];
if (gesture.state == UIGestureRecognizerStateBegan)
{
[imageViewToMove removeFromSuperview];
[self.view addSubview:imageViewToMove];
UIView *draggedView = [myscrollView hitTest:point withEvent:nil];
if ([draggedView isKindOfClass:[UIImageView class]])
{
imageViewToMove = (UIImageView*)draggedView;
}
}
else if (gesture.state == UIGestureRecognizerStateChanged)
{
imageToMove.center = point;
}
else if (gesture.state == UIGestureRecognizerStateEnded ||
gesture.state == UIGestureRecognizerStateCancelled ||
gesture.state == UIGestureRecognizerStateFailed)
{
// Determine if dragged view is in an OK drop zone
// If so, then do the drop action, if not, return it to original location
NSLog(#"point.x final:%f", point.x);
NSLog(#"point.y final:%f", point.y);
if (CGRectContainsPoint(goal.frame, point)){
imageToMove.frame = CGRectMake(167, 159, 100, 100);
}
else{
[imageToMove removeFromSuperview];
[myscrollView addSubview:imageToMove];
[imageToMove setFrame:CGRectMake(12, 38, 100, 100)];
imageToMove = nil;
}
}
}
May this code will help you out.
For a similar problem, I made UIScrollView subclass like the following: PoliteScrollView passes touch messages to it's subviews when it determines that they are being dragged.
#interface PoliteScrollView : UIScrollView
// number of pixels perpendicular to the scroll views orientation to make a drag start counting as a subview drag
// defaults to 1/10 of the scroll view's width or height, whichever is smaller
#property(nonatomic,assign) CGFloat subviewDraggingThreshold;
// yes when a subview is being dragged
#property(nonatomic,assign) BOOL isDraggingSubview;
// the subview being dragged
#property(nonatomic,strong) UIView *draggingSubview;
#end
#protocol PoliteScrollViewDelegate <NSObject>
#optional
- (void)scrollView:(PoliteScrollView *)scrollView subviewTouchesBegan:(NSSet *)touches;
- (void)scrollView:(PoliteScrollView *)scrollView subviewTouchesMoved:(NSSet *)touches;
- (void)scrollView:(PoliteScrollView *)scrollView subviewTouchesEnded:(NSSet *)touches;
#end
The key design idea is that dragging in a scroll view is ambiguous. Is the user scrolling or dragging a subview? PoliteScroll view handles this by providing two things: (1) a notion of orientation (horizontal if it's longer than it is wide, vertical otherwise), and (2) a threshold distance for what constitutes a drag in the direction perpendicular to it's orientation. (defaults to 1/10 the width or height).
I pasted this and several other files are in a paste bin, containing the following:
PoliteScrollView .h and .m
DraggableImageView.h and .m - that changes it's position when it gets touch messages.
ViewController.m - that demonstrates thetwo in combination.
To combine these in a project, paste the paste bin into files appropriately named, add a storyboard with a PoliteScrollView (be sure to set it's delegate), add in some images (the ViewController tries to add puppy0.jpeg to puppy4.jpeg.
I created an example which illustrates how to drag and drop between two or more views:
http://www.ancientprogramming.com/2012/04/05/drag-and-drop-between-multiple-uiviews-in-ios/
I found it a good idea to register the gesture recognizer to a different view than the actual views being dragged. This will make sure the gestures continue even though the dragged view changes its 'parent' view.
Maybe it can give some inspiration

How do I get the position of a txtfield inside a popoverview with respect to ipad screen

I have a UITextfield in a tableview in a view controller, and I am displaying this view in a UIPopOverView. I wanted to know how can I get to know the position of the textfield with respect to IPAD screen...so that i can move my tableview upwards on Textfield editingDidBegan
Try using the convertPoint:toView: or convertRect:toView: methods of UIView.
So for example, to get the textField's bounds relative to the window, say
CGRect *bounds = [textField convertRect:textField.bounds toView:window];

how to get the position of an object within a UIView, within a UIScrollView

so lets say I have a UIScrollView, within it are 3 UIViews, within those there is a UISlider in each one. they are positioned vertically in the UIScrollView.
I now have a 4th UIView also in the UIScrollView which I wish to move around depending on the position of the slider which has been used.
so within my sliderChanged method which i pass the sender, i get the position of the slider, and adjust the position of the 4th UIWindow to its y. This works great on the first UIView, but once on another UIView which has forced me to scroll down, using the slider moves the 4th UIView but stays at the beginning of the UIScrollView
I am using:
[4thView setCenter:CGPointMake([4thView center].x, [slider center].y+10)];
what I need is to get the position of the slider relative to the content of the scrollView and not relative to its UIView, so that I may set the 4th view again relative to the scrollView content.
You can convert the points by UIView's instance methods.
- (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view
- (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view
For example, I want to convert a ponint on the viewA to the scrollViewB's coordinates.
CGPoint aPtInScrollView = [viewA convertPoint:aPoint toView:scrollViewB];
Or, I want to know the position of viewA in scrollViewB.
CGPoint aPosViewA = [scrollViewB convertPoint:CGPointZero fromView:viewA];
Using the previous answer I took it a bit further to solve the issue I was having.
If you have multiple UITextView's within multiple UIView's all inside a single UIScrollView: this will animate and scroll to them.
This could be also be applied to UITextField's as well.
-(void)textViewDidBeginEditing:(UITextView *)textView {
[self.theScrollView setContentOffset:[self.theScrollView convertPoint:CGPointMake(textView.frame.origin.x, textView.frame.origin.y) fromView:textView.superview] animated:YES];
}
If you have labels above your textviews, just offset the x or y by that amount.

get frame of UITextField in UITableView for displaying UIPopover

I need to present a UIPopover from dynamically generated UITextFields in a UITableView. They are all tagged uniquely but when I try and use this code the popover just show up in the upper left hand corner:
[self.numbersPopover presentPopoverFromRect:[self.childSkusTable viewWithTag:aTag].frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
EDIT:
I see I am finding the frame for that tagged item but it is relavant to it's parent cell, in this case the frame of that tagged items is 0,0 for the x,y. How do I get it's position in the main window view?
Answering this just incase someone else needs it.
You have to get you UiTextFields position in the UIWindow like so:
UIView *v = [self.view viewWithTag:aTag];
CGPoint pos = [v.superview convertPoint:v.frame.origin toView:nil];
Then I just did this:
[self.numbersPopover presentPopoverFromRect:CGRectMake(pos.x, pos.y, 35, 10) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
The finding positioning code form above came from this questions and answer: iPhone - Get Position of UIView within entire UIWindow

How to know the present visible view's tag in iphone

i have an scroll view and i am adding few views to that
when the user scrolls how to get the current visible view's tag.
then i can add some thing to that view...
its just like getting the indexpathrow in table view..
how to do that..?
Thanks
You basically want to check if the frame of the subviews inside the UIScrollView intersect the scrollview's frame (if you only want to determine partial visibility), or if the frame is contained in the other frame (if you want to determine full visibility).
However, in order to check if the subview's frame intersects and/or is contained in the scrollview's frame you need to translate it from the local coords inside the scrollview to the global coordinates outside the scrollview.
That is probably pretty confusing, so here is some code. This will loop through all the subviews of a scrollview and print out whether it is fully visibile or partially visible:
for (UIView *subview in scrollView)
{
CGRect globalRect = CGRectOffset(subview.frame, -scrollView.contentOffset.x, -scrollView.contentOffset.y);
CGRect scrollViewBounds = CGRectMake(0.0f, 0.0f, scrollView.bounds.size.width, scrollView.bounds.size.height);
if (CGRectContainsRect(scrollViewBounds, globalRect)) {
NSLog(#"FULLY VISIBLE");
} else if (CGRectIntersectsRect(scrollViewBounds, globalRect)) {
NSLog(#"PARTIALLY VISIBLE");
}
}
You could put this in a UIScrollViewDelegate method to do these checks while the user is scrolling the content around.