Change View Alpha on Pan Gesture or Dragging - ios

I want to a UIView to drag to bottom of the screen on Pan Gesture but also the view alpha should scale down to "zero", when it reaches to the bottom of the screen.
And vise versa, when I will drag the view upwards then the UIView alpha should scale down to "1"
But the problem is that the view's alpha is scaling down to "Zero" on panning half of the screen or sometimes when I drag the view slower.
Initially I have made the UIView background color to Black.
I need to scale down the alpha of the view gradually , any idea or suggestion will be helpful.
UIPanGestureRecognizer * panner = nil;
panner = [[UIPanGestureRecognizer alloc] initWithTarget: self action:#selector(handlePanGesture:)];
[self.view addGestureRecognizer:panner ];
[panner setDelegate:self];
[panner release];
CGRect frame = CGRectMake(0, 0, 320, 460);
self.dimmer = [[UIView alloc] initWithFrame:frame];
[self.dimmer setBackgroundColor:[UIColor blackColor]];
[self.view addSubview:dimmer];
-(IBAction) handlePanGesture:(UIPanGestureRecognizer *) sender {
static CGPoint lastPosition = {0};
CGPoint nowPosition; float alpha = 0.0;
float new_alpha = 0.0;
nowPosition = [sender translationInView: [self view]];
alpha = [dimmer alpha] -0.0037;
dimmer.alpha -=alpha;
}

I would look at the point on the screen you are currently at inside your handlePanGesture: find the percentage you are at on the view CGFloat percentage = nowPosition.y/self.view.frame.size.height; then set the alpha to that dimmer.alpha = 1.0 - percentage;. This way no matter where you are moving, you are setting the alpha to how close to the bottom you are.

You aren't scaling relative to your gesture; you're setting dimmer.alpha = 0.0037 every time handlePanGesture: executes, regardless of pan direction or distance.
-(IBAction) handlePanGesture:(UIPanGestureRecognizer *) sender {
static CGPoint lastPosition = {0};
CGPoint nowPosition;
float alpha = 0.0;
float new_alpha = 0.0; // Unused!!
nowPosition = [sender translationInView: [self view]]; // Unused!!
alpha = [dimmer alpha] - 0.0037;
dimmer.alpha -= alpha; // === dimmer.alpha = dimmer.alpha - (dimmer.alpha - 0.0037)
// === dimmer.alpha = 0.0037 !!!
}
A better implementation might look something like this:
-(IBAction) handlePanGesture:(UIPanGestureRecognizer *) sender {
CGPoint nowPosition = [sender translationInView: [self view]];
CGFloat alpha = dimmer.alpha - ([sender translationInView: [self view]].y)/320.0;
dimmer.alpha = MAX(0, MIN(1, alpha));
}

Related

UISlider thumb moving without touching thumb

I am using UISlider in my project. Normally, thumb should move as soon as we touch and drag the thumb. But, in my case, thumb moved while I touched on the edge of it without touching it. Like this:
Here is my code:
self.slider = [[UISlider alloc] initWithFrame:CGRectMake(30, [UIScreen mainScreen].bounds.size.height - 200, [UIScreen mainScreen].bounds.size.width-30, 30)];
[self.view addSubview:self.slider];
Why the thumb moved and how to deal with it? My target is that, thumb will move only if I thouch and drag it, and will not move when I touched on the edge of it.
Try to add following code :
- (void)viewDidLoad
{
UITapGestureRecognizer *tapGest = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(sliderTapped:)];
[slider addGestureRecognizer:tapGest];
}
- (void)sliderTapped:(UIGestureRecognizer *)tapGest
{
UISlider* slider = (UISlider*)tapGest.view;
if (slider.highlighted)
return; // tap on thumb, let slider deal with it
CGPoint pt = [tapGest locationInView: slider];
CGFloat percentage = pt.x / slider.bounds.size.width;
CGFloat delta = percentage * (slider.maximumValue - slider.minimumValue);
CGFloat value = slider.minimumValue + delta;
[slider setValue:value animated:YES];
}
For that you need to use taoGesture with UISlider, so first add UITapGestureRecognizer in your slider object then set its value in action method of selector of gestureRecognizer.
Add following code after you have added slider in your View.
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(onSliderTap:)];
[self.slider addGestureRecognizer:tapGestureRecognizer];
Now in onSliderTap you can get the location point then update the value of the slider
- (void)onSliderTap:(UITapGestureRecognizer *)recognizer {
float width = self.slider.frame.size.width;
CGPoint point = [recognizer locationInView:recognizer.view];
CGFloat sliderX = self.slider.frame.origin.x;
float newValue = ((point.x - sliderX) * self.slider.maximumValue) / width;
[self.slider setValue:newValue];
}

Resetting the Zoom on a UIPageViewController

I am building up a simple application that is made up of a UITableViewController with languages and when a specific cell is clicked, a UIPageViewController is brought up to represent the images for that selected language. The user can scroll through the images and everything works as desired. The next step was to build a zooming capability into the UIPageViewController so the user could zoom into the images with a pinch gesture.
I have achieved this with the following code:
- (void)viewDidLoad
{
[super viewDidLoad];
self.leafletImages = [NSMutableArray arrayWithObjects:[[ImageModel alloc] initWithImageName:#"3facts-chinese-page1.jpg"], [[ImageModel alloc] initWithImageName:#"3facts-chinese-page2.jpg"], [[ImageModel alloc] initWithImageName:#"3facts-chinese-page3.jpg"], [[ImageModel alloc] initWithImageName:#"3facts-chinese-page4.jpg"], [[ImageModel alloc] initWithImageName:#"3facts-chinese-page5.jpg"], [[ImageModel alloc] initWithImageName:#"3facts-chinese-page6.jpg"], nil];
// Lots of code for the building up of the UIPageViewController
LeafletImageSizeViewController *imageViewController = [[LeafletImageSizeViewController alloc] init];
imageViewController.model = [_modelArray objectAtIndex:0];
NSArray *viewControllers = [NSArray arrayWithObject:imageViewController];
[self.pageViewController setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
// Gesture
UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(pinchDetected:)];
[self.view addGestureRecognizer:pinchRecognizer];
pinchRecognizer.delegate=self;
}
The class creating the image and the size is:
- (void)useThreeFactsSize
CGRect insetFrame;
insetFrame = CGRectMake(310, 70, self.view.frame.size.width-615, self.view.frame.size.height-85);
_imageView = [[UIImageView alloc] initWithFrame:insetFrame];
[_imageView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[_imageView setImage:[UIImage imageNamed:_model.imageName]];
[[self view] addSubview:_imageView];
[self.view setBackgroundColor:[UIColor clearColor]];
}
The pinchDetection method is:
-(void)pinchDetected:(UIPinchGestureRecognizer *)pinchRecognizer
{
CGFloat scale = pinchRecognizer.scale;
self.pageViewController.view.transform = CGAffineTransformScale(self.pageViewController.view.transform, scale, scale);
pinchRecognizer.scale = 1.0;
}
Now, I can zoom into the images of the UIPageViewController without any issues and it works really well.
What I want to do however is two things:
Not allow the image to be zoomed out beyond the original scale
Create a double tap gesture to bring the image back to it's original scale
With feature 1, the user can zoom into the image, but also completely zoom out of the image which shrinks the image and the UIPageViewController pageIndicators. There's no reason the user should be able to zoom out of the image, so I'd like to allow the user to zoom in to any scale, but not to zoom out beyond what the original size of the image on screen in the UIPageViewController.
With feature 2, I'd like to implement a gesture to double tap the screen and for the zoomed image to go back to it's original scale (like the Photos.app).
Update
With reference to the answer, I have updated the question to reflect how I'm going about doing the images. With point 2 and the double tap gesture, the following code almost works:
- (void)scrollViewTwoFingerTapped:(UITapGestureRecognizer *)recognizer
{
NSLog(#"Double Tap");
self.pageViewController.view.transform = CGAffineTransformIdentity;
}
What it's currently doing is if I zoom in with a pinch and pan around, and then double tap, it centres the image to the point of where I tapped, so sometimes the borders are being shown, etc, rather than making the image centre to where it's supposed to be.
For point 1:
if (pinchRecognizer.scale > 1) {
CGFloat scale = pinchRecognizer.scale;
self.pageViewController.view.transform = CGAffineTransformScale(self.pageViewController.view.transform, scale, scale);
pinchRecognizer.scale = 1.0;
}
If I have self.imageview, it doesn't work because it's nil and even if I make a call to the class setting the size, it's nil as well.
I suspect I have a number of things wrong with my code!
For reference, I have panning working with:
- (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];
}
else if(state==UIGestureRecognizerStateEnded){
UIView *imageView = recognizer.view;
UIView *container = imageView.superview;
CGFloat targetX = CGRectGetMinX(imageView.frame);
CGFloat targetY = CGRectGetMinY(imageView.frame);
if(targetX>0){
// targetX = 0;
}else if(CGRectGetMaxX(imageView.frame)<CGRectGetWidth(container.bounds)){
targetX = CGRectGetWidth(container.bounds)-CGRectGetWidth(imageView.frame);
}
if(targetY>0){
// targetY = 0;
}else if(CGRectGetMaxY(imageView.frame)<CGRectGetHeight(container.bounds)){
// targetY = CGRectGetHeight(container.bounds)-CGRectGetHeight(imageView.frame);
}
// imageView.frame = CGRectMake(targetX, targetY, CGRectGetWidth(imageView.frame), CGRectGetHeight(imageView.frame));
[UIView animateWithDuration:0.3 animations:^{
imageView.frame = CGRectMake(targetX, targetY, CGRectGetWidth(imageView.frame), CGRectGetHeight(imageView.frame));
}];
}
}
That's working very well at the moment, but there's definitely a conflict with everything else.
I'd really appreciate any guidance in the right direction on this.
1.) To not allow the image to be zoomed out beyond it's original scale you first just need to check if the scale you're about to set it to is greater than 1 or not. If it's less than one, you don't want to rescale your image as that would mean it gets smaller. So...
#IBAction func doPinch(sender: UIPinchGestureRecognizer) {
if sender.scale > 1 {
let transform = CGAffineTransformMakeScale(sender.scale, sender.scale)
imageView.transform = transform
}
}
2.) You seem to be changing the view's frame to try and change it's scale, but you never adjusted the view's frame yourself in the first place. You're adjusting the view's transform. That means in order to return it to it's original size you must remove whatever transform you put on it. To do this you put it back to it's identity. So...
#IBAction func doDoubleTap(sender: UITapGestureRecognizer) {
imageView.transform = CGAffineTransformIdentity
}
My code samples are in Swift but you should be able to adjust it to Objective-C yourself. Also, you seem to be adjusting the transform/scale of the entire page view itself. I would suggest you change the scale of only the image view. That makes more sense as that's actually what you're trying to zoom into.

iOS moving tapped point on View within ScrollView to the center of screen

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.

when i zoom imageview , and then click on image image goes off ios

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;
}

Rotating rectangle around circumference of a circle (iOS)?

I am trying to rotate the rectangle around the circle. So far after putting together some code I found in various places (mainly here: https://stackoverflow.com/a/4657476/861181) , I am able to rotate rectangle around it's center axis.
How can I make it rotate around the circle?
Here is what I have:
OverlaySelectionView.h
#import <QuartzCore/QuartzCore.h>
#interface OverlaySelectionView : UIView {
#private
UIView* dragArea;
CGRect dragAreaBounds;
UIView* vectorArea;
UITouch *currentTouch;
CGPoint touchLocationpoint;
CGPoint PrevioustouchLocationpoint;
}
#property CGRect vectorBounds;
#end
OverlaySelectionView.m
#import "OverlaySelectionView.h"
#interface OverlaySelectionView()
#property (nonatomic, retain) UIView* vectorArea;
#end
#implementation OverlaySelectionView
#synthesize vectorArea, vectorBounds;
#synthesize delegate;
- (void) initialize {
self.userInteractionEnabled = YES;
self.multipleTouchEnabled = NO;
self.backgroundColor = [UIColor clearColor];
self.opaque = NO;
self.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(rotateVector:)];
panRecognizer.maximumNumberOfTouches = 1;
[self addGestureRecognizer:panRecognizer];
}
- (id) initWithCoder: (NSCoder*) coder {
self = [super initWithCoder: coder];
if (self != nil) {
[self initialize];
}
return self;
}
- (id) initWithFrame: (CGRect) frame {
self = [super initWithFrame: frame];
if (self != nil) {
[self initialize];
}
return self;
}
- (void)drawRect:(CGRect)rect {
if (vectorBounds.origin.x){
UIView* area = [[UIView alloc] initWithFrame: vectorBounds];
area.backgroundColor = [UIColor grayColor];
area.opaque = YES;
area.userInteractionEnabled = NO;
vectorArea = area;
[self addSubview: vectorArea];
}
}
- (void)rotateVector: (UIPanGestureRecognizer *)panRecognizer{
if (touchLocationpoint.x){
PrevioustouchLocationpoint = touchLocationpoint;
}
if ([panRecognizer numberOfTouches] >= 1){
touchLocationpoint = [panRecognizer locationOfTouch:0 inView:self];
}
CGPoint origin;
origin.x=240;
origin.y=160;
CGPoint previousDifference = [self vectorFromPoint:origin toPoint:PrevioustouchLocationpoint];
CGAffineTransform newTransform =CGAffineTransformScale(vectorArea.transform, 1, 1);
CGFloat previousRotation = atan2(previousDifference.y, previousDifference.x);
CGPoint currentDifference = [self vectorFromPoint:origin toPoint:touchLocationpoint];
CGFloat currentRotation = atan2(currentDifference.y, currentDifference.x);
CGFloat newAngle = currentRotation- previousRotation;
newTransform = CGAffineTransformRotate(newTransform, newAngle);
[self animateView:vectorArea toPosition:newTransform];
}
-(CGPoint)vectorFromPoint:(CGPoint)firstPoint toPoint:(CGPoint)secondPoint
{
CGPoint result;
CGFloat x = secondPoint.x-firstPoint.x;
CGFloat y = secondPoint.y-firstPoint.y;
result = CGPointMake(x, y);
return result;
}
-(void)animateView:(UIView *)theView toPosition:(CGAffineTransform) newTransform
{
[UIView setAnimationsEnabled:YES];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.0750];
vectorArea.transform = newTransform;
[UIView commitAnimations];
}
#end
here is attempt to clarify. I am creating the rectangle from a coordinates on a map. Here is the function that creates that rectangle in the main view. Essentially it is the middle of the screen:
overlay is the view created with the above code.
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
if (!circle){
circle = [MKCircle circleWithCenterCoordinate: userLocation.coordinate radius:100];
[mainMapView addOverlay:circle];
CGPoint centerPoint = [mapView convertCoordinate:userLocation.coordinate toPointToView:self.view];
CGPoint upPoint = CGPointMake(centerPoint.x, centerPoint.y - 100);
overlay = [[OverlaySelectionView alloc] initWithFrame: self.view.frame];
overlay.vectorBounds = CGRectMake(upPoint.x, upPoint.y, 30, 100);
[self.view addSubview: overlay];
}
}
Here is the sketch of what I am trying to achieve:
Introduction
A rotation is always done around (0,0).
What you already know:
To rotate around the center of the rectangle you translate the rect to origin, rotate and translate back.
Now for your question:
to rotate around a center point of a circle, simply move the center of the rectangle such that the circle is at (0,0) then rotate, and move back.
start positioning the rectangle at 12 o clock, with the center line at 12.
1) as explained you always rotate around 0,0, so move the center of the circle to 0,0
CGAffineTransform trans1 = CGAffineTransformTranslation(-circ.x, -circ.y);
2) rotate by angle
CGAffineTransform transRot = CGAffineTransformRotation(angle); // or -angle try out.
3) Move back
CGAffineTransform transBack = CGAffineTransformTranslation(circ.x, circ.y);
Concat these 3 rotation matrices to one combibed matrix, and apply it to the rectangle.
CGAffineTransformation tCombo = CGAffineTransformConcat(trans1, transRot);
tCombo = CGTransformationConcat(tCombo, transback);
Apply
rectangle.transform = tCombo;
You probably should also read the chapter about Transformation matrices in Quartz docu.
This code is written with a text editor only, so expect slighly different function names.

Resources