I want to enable scrolling of UIScrollView only when i swipe from screen boundaries. I am using swipe gesture recognizer.
here is my code
-(void)swipeHandlerLeft:(UISwipeGestureRecognizer *)swipeRecognizer
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
point = [swipeRecognizer locationInView:self.view];
if(swipeRecognizer.direction == UISwipeGestureRecognizerDirectionLeft)
{
if (point.x > screenWidth - 10)
{
NSLog(#"Swipped Left");
_scrollView.scrollEnabled = YES;
}
else
{
_scrollView.scrollEnabled = NO;
}
}
}
-(void)swipeHandlerRight:(UISwipeGestureRecognizer *)swipeRecognizer
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
point = [swipeRecognizer locationInView:self.view];
if(swipeRecognizer.direction == UISwipeGestureRecognizerDirectionRight)
{
if (point.x < 10)
{
NSLog(#"Swipped Right");
_scrollView.scrollEnabled = YES;
}
else
{
_scrollView.scrollEnabled = NO;
}
}
}
Problem with above code is it works until scrollview is not enabled,but once it is enabled this methods are not getting called and i think the reason for that is as i've added scrollview inside of my UIView.
any help will be appreciated.
UIScrollView already has UIGestureRecognizer inside of it.
I think you would need to connect your code to those gestureRecognizers. You can access them by myScrollView.panGestureRecognizer and myScrollView.pinchGestureRecognizer.
Your scrollview catches your touch before your swipe view, and I suppose the swipe gesture recognizer is on the superview of the scroll view.
You must create a dependency by calling requireGestureRecognizerToFail(_:)
on your scrollView pan gesture recognizer, and passing your swipe gesture.
Related
I have a UITableView that is at the bottom of my main UIViewController, it currently only shows the top two rows. To show the rest I don't want it to scroll, I want the user to be able to "pull" the view up to reveal the additional 4 rows (can then swipe down on it to "push" it back into its original place), and I want the "pull" to be similar to how control center works in iOS. The spring that it has is really great.
Looks like I can add a UIPanGestureRecognizer to do the pull:
UIPanGestureRecognizer * pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(pan:)];
pan.maximumNumberOfTouches = pan.minimumNumberOfTouches = 1;
[self addGestureRecognizer:pan];
- (void)pan:(UIPanGestureRecognizer *)aPan; {
CGPoint currentPoint = [aPan locationInView:self];
[UIView animateWithDuration:0.01f
animations:^{
CGRect oldFrame = _viewToChange.frame;
_viewToChange.frame = CGRectMake(oldFrame.origin.x, currentPoint.y, oldFrame.size.width, ([UIScreen mainScreen].bounds.size.height - currentPoint.y));
}];
}
Ref this question.
Doing this does sort of work, but my UITableView flashes as you pull it up and it eventually disappears.
There is also no spring, and no way to set a "max" so that you can't pull up the view past a certain point.
Does anyone have ideas on how this can be achieved?
this is how i write the pan:. t is tableView(initially user interaction is disabled). 40 in code is for more realistic look in pan. 200 is max value i used and 60 is min value. i directly add t to tableview with height 60 and increased the height with animation.
- (void)pan:(UIPanGestureRecognizer *)aPan; {
CGPoint currentPoint = [aPan locationInView:self.view];
CGRect fr = t.frame;
if ((currentPoint.y - fr.origin.y) < 40 && (fr.size.height <= 200) )
{
float nh = (currentPoint.y >= self.view.frame.size.height - 200) ? self.view.frame.size.height-currentPoint.y : 200;
if (nh < 60) {
nh = 60;
}
[UIView animateWithDuration:0.01f animations:^{
[t setFrame:CGRectMake(0, self.view.frame.size.height-nh, t.frame.size.width, nh)];
}];
if (nh == 200) {
[t setUserInteractionEnabled:YES];
}
else
{
[t setUserInteractionEnabled:NO];
}
}
}
or without pan; with using tableview's scrollview delegate methods, when tableview begin dragging in closed state, opening the large mode and when tableview scroll to top sliding down
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
NSLog(#"scroll");
if (scrollView.contentOffset.y == 0) {
[UIView animateWithDuration:0.2f animations:^{
[scrollView setFrame:CGRectMake(0, self.view.frame.size.height-200, t.frame.size.width, 200)];
}];
}
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView.contentOffset.y == 0) {
[UIView animateWithDuration:0.2f animations:^{
[scrollView setFrame:CGRectMake(0, self.view.frame.size.height-60, t.frame.size.width, 60)];
}];
}
}
I have an UIView(0,0,1000,1000) within an UIScrollView(0,0,500,500) as the UIScrollView's
content, here's my code:
//ScrollView setting
ScrollView.minimumZoomScale = 0.5;
ScrollView.maximumZoomScale = 1.0;
ScrollView.contentSize = View.frame.size
ScrollView.delegate = self;
//Get the tapped point & Place a mark on it
//already add an UITapGestureRecognizer on View
CGPoint tapped = [tapRecognizer locationInView:View];
UIView mark = [[UIView alloc] initWithFrame:CGRectMake(tapped.x-25,tapped.y-25,50,50)];
[View addSubview:mark];
//Centering the tapped point (1.0x)
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGPoint screenCenter = CGPointMake(screenRect.size.width/2,screenRect.size.height/2);
[ScrollView setContentOffset:(tapped-screenCenter.x, tapped-screenCenter.y) animated:YES];
This works fine when the UIScrollView zoom scale is 1.0x, but when I zoom it to 0.5x with code modified as below:
//Get zoom scale
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale{
CGfloat zoomScale = scale;
}
//Centering the tapped point (0.5x)
[ScrollView setContentOffSet:(tapped-screenCenter.x/zoomScale, tapped-screenCenter.y/zoomScale) animated:YES];
It didn't work as I expected, please help me figure it out.
[View setContentOffSet:(tapped-screenCenter.x * zoomScale, tapped-screenCenter.y * zoomScale) animated:YES];
You multiply by scale, not divide.
i add a UIPanGestureRecognizer to my imageview then Gesture Recognizer is added but my imageview image is panned in to my view i want only image is panned inside of the imageview on in the view how it is possible?
i write a code for that on viewdidload
UIPanGestureRecognizer *pangesture=[[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(panGestureDetected:)];
[pangesture setDelegate:self];
[self.zoomImage addGestureRecognizer:pangesture];
and method for that is
- (void)panGestureDetected:(UIPanGestureRecognizer *)recognizer
{
UIGestureRecognizerState state = [recognizer state];
if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
{
CGPoint translation = [recognizer translationInView:recognizer.view];
[recognizer.view setTransform:CGAffineTransformTranslate(recognizer.view.transform, translation.x, translation.y)];
[recognizer setTranslation:CGPointZero inView:recognizer.view];
}
}
then imageView image is panned in my View but i want image Panned only inside of imageview if it possible then give me solution.
here my original imageview Size is like as
and when i added UIPanGEstureRecognizer then it look like as
image are panned in View but i want to zoom it inside of imageview size please give me solution for that.
take UIScrollView and add UIImageView inside the scrollview and pangesture on scrollview ..
set delegate for scrollview and do the code
- (UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView {
// Return the view that we want to zoom
return self.zoomImage;
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
// The scroll view has zoomed, so we need to re-center the contents
[self centerScrollViewContents];
}
- (void)centerScrollViewContents {
CGSize boundsSize = scrollView.bounds.size;
CGRect contentsFrame = self.zoomImage.frame;
if (contentsFrame.size.width < boundsSize.width) {
contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2.0f;
} else {
contentsFrame.origin.x = 0.0f;
}
if (contentsFrame.size.height < boundsSize.height) {
contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0f;
} else {
contentsFrame.origin.y = 0.0f;
}
self.zoomImage.frame = contentsFrame;
}
- (void)scrollViewDoubleTapped:(UITapGestureRecognizer*)recognizer {
// Get the location within the image view where we tapped
CGPoint pointInView = [recognizer locationInView:imageView];
// Get a zoom scale that's zoomed in slightly, capped at the maximum zoom scale specified by the scroll view
CGFloat newZoomScale = scrollView.zoomScale * 1.5f;
newZoomScale = MIN(newZoomScale, scrollView.maximumZoomScale);
// Figure out the rect we want to zoom to, then zoom to it
CGSize scrollViewSize = scrollView.bounds.size;
CGFloat w = scrollViewSize.width / newZoomScale;
CGFloat h = scrollViewSize.height / newZoomScale;
CGFloat x = pointInView.x - (w / 2.0f);
CGFloat y = pointInView.y - (h / 2.0f);
CGRect rectToZoomTo = CGRectMake(x, y, w, h);
[scrollView zoomToRect:rectToZoomTo animated:YES];
}
- (void)scrollViewTwoFingerTapped:(UITapGestureRecognizer*)recognizer {
// Zoom out slightly, capping at the minimum zoom scale specified by the scroll view
CGFloat newZoomScale = scrollView.zoomScale / 1.5f;
newZoomScale = MAX(newZoomScale, scrollView.minimumZoomScale);
[scrollView setZoomScale:newZoomScale animated:YES];
}
UIImage object's userInteractEnable is NO by default, so you can't interact with it. Try self.zoomImage.userInteractEnable = YES
Try this:
Add another UIView under the imageView, make its size exactly the same as your imageView. Then set your imageView as this UIView's subview by drag and drop the imageView on top of this UIView (Assuming you are using StoryBoard or xib).
After that, if you are using StoryBoard or xib, then go to Attributes Inspector, select this UIView, tick Click Subviews. If not, just set view.clipsToBounds = YES;
note : this is how i have added this gesture to my imageview
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(handlePinch:)];
pinchGesture.delegate=self;
[self.editPictureImageView addGestureRecognizer:pinchGesture];
note : this is my method that handles pinch transformation
mcurrentscale and mlastscale are of float type
-(void)handlePinch:(UIPinchGestureRecognizer*)sender {
mCurrentScale += [sender scale] - mLastScale;
mLastScale = [sender scale];
if (sender.state == UIGestureRecognizerStateEnded)
{
mLastScale = 1.0;
}
if (mCurrentScale < 1)
{
mCurrentScale = 1.0;
}
CGAffineTransform currentTransform = CGAffineTransformIdentity;
CGAffineTransform newTransform = CGAffineTransformScale(currentTransform, mCurrentScale, mCurrentScale);
self.editPictureImageView.transform = newTransform;
}
plzz help
This is probably a more awkward way to do it.
I would re-think your approach like so:
Add the UIImageView to a UIScrollView. The frame of the imageView should be the bounds of the scrollView, by which I mean at it's default position it the imageView should sit in the scrollView just like it did whilst it was sitting in a normal view.
Set up the UIScrollView (IB or code):
self.scrollView.delegate = self;
// example values
self.scrollView.minimumZoomScale = 0.4f;
self.scrolLView.maximumZoomScale = 3.0f;
Adopt this method:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
// allow zooming of our image view
return self.imageView;
}
I've been a long journey trying to drag and drop UIImageViews from a UITableView to another view.
I have everything working to a point. I subclass UIPanGestureRecognizer and attach this custom recognizer to all the UIImageViews I load into the table view.
I then override the recognizer's touchesMoved method to, among other things, add a temporary view onto the applications key window, then add a copy of the selected UIImageView onto this temporary view, as follows:
UIView *dragAndDropView = [[UIView alloc] initWithFrame: [[UIScreen mainScreen] applicationFrame]];
dragAndDropView.backgroundColor = [UIColor whiteColor];
[[UIApplication sharedApplication].keyWindow addSubview: dragAndDropView];
ElementImageView * sourceImageView = (ElementImageView*)self.view;
ElementImageView *newImageView = [[ElementImageView alloc] initWithImage:sourceImageView.image];
newImageView.userInteractionEnabled = YES;
newImageView.frame = [self.view convertRect:sourceImageView.frame toView:dragAndDropView];
[dragAndDropView addSubview:newImageView];
As a result of this code, I do indeed get a copy of the source image view on top of my dragAndDropView (I can tell because I set the backgroundcolor of the dragAndDropView to white). And if I lift my finger and touch the copied image view again, I can of course drag it around the screen as I wish. But I can't find a way to seamlessly transfer the existing touch to the new object.
Any ideas?
I think you could do the following on your UIPanGestureRecognizer handler:
-(void) handlePan:(UIPanGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateBegan) {
// the initial position
initialPanPositionX = self.transform.tx;
initialPanPositionY = self.transform.ty;
// create a copy of the imageview
panImage = [[UIImageView alloc] initWithImage:imageView.image];
panImage.frame = imageView.frame;
[self.view addSubview:panImage];
}
else if (recognizer.state == UIGestureRecognizerStateChanged) {
if (!startedMoving) {
startedMoving = YES;
[UIView beginAnimations:nil context:NULL]; {
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationDuration:0.2f];
// an effect to increase a copy a little bit when start dragging
CGAffineTransform zt = CGAffineTransformScale(CGAffineTransformIdentity, 1.2, 1.2);
panImage.bounds = CGRectApplyAffineTransform(panImage.bounds, zt);
}
[UIView commitAnimations];
}
// translation
CGPoint point = [recognizer translationInView:self];
panImage.transform = CGAffineTransformMakeTranslation(initialPanPositionX + point.x, initialPanPositionY + point.y);
}
else if (recognizer.state == UIGestureRecognizerStateEnded ) {
startedMoving = NO;
// drop the imageView if it's inside the droppable view
[panImage release], panImage = nil;
}
}
Hope it helps.