Problem:
I got a Tableview with dynamically many cells. The cells contain PKDrawings with the PencilKit Framework. So its like a book...
I would like to do 2 things:
1. Zoom in so i am closer to the cells-content so the drawings seem bigger.
(But when I say cells-content I mean all cells so I am talking about the Tableview. I don't want to zoom into a specific cell)
2. Zoom out so I start seeing more and more pages (cells) above and below the one that was "in my focus" when not zooming out or in.
If that's not possible as the Cells are Hidden and its hard to tell them while zooming out when to load again its fine if the maximal zoom-out is the point when I haven't zoomed in.
As a Tableview is already a subclass of the UIScrollview I can access its min & max Zoomscale. However setting this doesn't change anything. The ScrollViewDidZoom won't get triggered either.
Scrolling works fine though...
I think that this should all be possible if I somehow manage it to put my Tableview into another View/Scrollview and just zoom in/out on that but I don't know how to do that...
Thanks in advance for any help!
For zooming UITableview cell u can use CGAffineTransform. You can manage the scale value as per requirement
// For Zoom in
CGAffineTransform trans = CGAffineTransformScale(cell.contentView.transform, 100, 100);
view.transform = trans;
// For Zoom Out
CGAffineTransform trans = CGAffineTransformScale(cell.contentView.transform, 0.01, 0.01);
view.transform = trans;
To zoom complete UItableView you can apply affine transform to tableview
// For Zoom in
CGAffineTransform trans = CGAffineTransformScale(tableView.transform, 100, 100);
view.transform = trans;
// For Zoom Out
CGAffineTransform trans = CGAffineTransformScale(tableView.transform, 0.01, 0.01);
view.transform = trans;
For pinch gesture u can use following gestures well documented by apple developer documentation https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/handling_uikit_gestures/handling_pinch_gestures
Related
I have a horizontal scrollview with an image which I need to rotate as the user scrolls left or right. It needs to rotate as the user moves the scroll across the screen. So if the user scrolls half way and stops the image should rotate halfway etc. I have looked at few examples but nothing seems to be giving me the correct result. Can some one please help.
Thanks in advance
Vertical scrolling and Swift 5:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let topOffset = scrollView.contentOffset.y
let angle = -topOffset * 2 * CGFloat(Double.pi / 180)
self.myImageView.transform = CGAffineTransform(rotationAngle: angle)
}
Don't forget to do this in viewDidLoad:
self.scrollView.delegate = self
You'll need to implement the scrollViewDidScroll method and then apply a rotation matrix to the image. To rotate a UIIMage you can do what they outline here. How to Rotate a UIImage 90 degrees?
However, this would be better accomplished in a pan gesture recognizer. The pan gesture will give you information about how far the user panned, and then you can rotate the image based on that distance.
To rotate image is not good for performance. You'd better set image view's rotate transform as user scrolls. Like this:
imageView.transform = CGAffineTransformMakeRotation(CGFloat(M_PI_2))
This is what I currently have:
func handlePinching(recognizer : UIPinchGestureRecognizer) {
self.layer.transform = CATransform3DMakeAffineTransform(CGAffineTransformScale(self.transform, recognizer.scale, recognizer.scale));
recognizer.scale = 1.0;
}
Using self.view.transform for that also makes it bigger. I want to make it zoom "internally" (I really don't know how to explain it).
So I'm not 100% sure to understand the question but I guess I get it.
For example you want to zoom on an image without zooming the other element of the UI (NavBar, Buttons, ...) right?
So I guess in you're example you're in a viewController, which means, when you change the scale of self.view you'll zoom everything. You have to apply the scale on the specific view that you want to zoom in.
In the example below, to zoom on the image, the image is inside of an UIImageView, and this imageView is subView of self.view. And you will just apply a transform on this imageView.
Moreover I think you get a little bit confused on how to zoom, considering the view you want to zoom is imageView you just need to do
imageView.transform = CGAffineTransformMakeScale(recognizer.scale,recognizer.scale)
I hope this answer your question, let me know if something is not clear.
I have an animation which is kicked off when a gesture recogniser (double tap) fires:
[UIView animateWithDuration:0.3 animations:^{
_scrollView.contentOffset = CGPointMake(x, y);
_scrollViewContentView.frame = someFrame;
_scrollViewContentView.layer.transform =
CATransform3DMakeScale(1.f/_zoomScale, 1.f/_zoomScale, 1.f);
}];
It's working nice except in one case : if scrollViewWillBeginDecelerating delegate method is not called before animation execution (just by dragging hardly my scrollview).
I just have scrollViewDidEndDragging method called.I can wait 20 sec and then play my animation. It'll play correctly except for my contentOffset.
The delegate methods themselves do nothing, they were only added to see where the problem might be.
I have no idea why.
Edit : here's a video of my problem. Phase 1 : scroll with deceleration and phase 2 without. Look a the final position. Phase 1 is correct but not phase
try:
[_scrollView setContentOffSet:CGPointMake(x, y) animated:YES];
outside of the animation block. I don't believe contentOffSet is animatable through UIView's animation block.
Edit:
Instead of:
_scrollview.contentOffSet = CGPointMake(x, y);
try:
_scrollview.bounds = CGRectMake(x, y, CGRectGetWidth(scrollview.bounds), CGRectGetHeight(scrollview.bounds));
I suspect that x in this line may be causing the effect that you see:
_scrollView.contentOffset = CGPointMake(x, y);
What's it's value? I think you should try replacing that by CGPointMake(0, y) and see if that causes the white margin to appear every time.
My reasoning is the following:
1) to create bouncing effect that doesn't go outside the scope of the image (doesn't show white background), you must have set _scrollView's contentSize.width less than the actual image size.
2) to allow some scrolling you have set the contentSize.width greater than the width of the _scrollView
3) you have centered the image within the _scrollView relatively to the size of it's contentSize
4) when animating you are probably setting frame with pre-calculated x coordinate to position the image on the left size because without that CATransform3DMakeScale would just leave the image in the center (by the way, why use CATransform3DMakeScale, when you could just change the size in the frame?)
5) in the video, when running the animation the first time, you have contentOffset.x to it's maximum value (because you drag to the left therefore increasing the content offset and scrollview bounces back to it's max content offset that doesn't go beyond content size limits)
6) in the video when running the animation for the second time, you have contentOffset.x with a smaller value because you drag to the right by decreasing it
7) when animation is finished, you still have the same content size for your scrollView and therefore the same amount of scroll available. If you have the contentOffset.x at it's maximum value then image will be more on the left, if you have contentOffset.x with less value - image will be more on the right
8) if the x in _scrollView.contentOffset = CGPointMake(x, y); is related to actual content offset prior to animation then that makes sense that the image appears more on the left in the first case and more on the right in the second case.
If I'm right then this is how you could solve it:
a) If you want the image always to appear on specific x position, make sure to set constant contentOffset in the animation.
b) Adjust the code of calculating frame (someFrame) origin according to the contentOffset that you'll be animating to (looks like now it works only with the maximum contentOffset.x).
c) If after animation you don't want the content to be scrollable, make sure to set _scrollView.contentSize = _scrollview.bounds.size; in the animation block.
I'm not sure I completely understand your problem (Maybe you can try to explain what you want to accomplish in this animation?). Any way, maybe try this instead of using setContentOffset:
CGRect *rect = CGRectMake(x, y, 0, 0);
[_scrollView scrollRectToVisible:rect animated:YES];
Perhaps try using core animation rather than UIView animations. It won't make a difference if the reason you're running into trouble is because all animations are being removed from the layer, but if it's due to -[removeAnimationForKey:#"bounds"], this might be a winner.
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"bounds"];
animation.fromValue = [NSValue valueWithCGRect:_scrollView.layer.bounds];
animation.toValue = [NSValue valueWithCGRect:(CGRect){ .origin = CGPointMake(x,y), .size = scrollView.layer.bounds.size }];
[scrollView.layer addAnimation:animation forKey:#"myCustomScroll"];
scrollView.layer.bounds = (CGRect){ .origin = CGPointMake(x,y), .size = scrollView.layer.bounds.size };
P.S. I haven't tested the code above it's just off my head, so apologies for any silly errors.
I am working a pictureView which needs to be zoom in and zoom out on tap,
I have searched for the proper zoom in and zoom out, but not found (I have tried to achieve same task with UIView but its not good), so i came to ask if any body can help ?
I have 4 images assembled in a tableview, 2 in a row.
What i want is if user taps an image, it just zoom in and if he taps again it should zoom out.
Following is the code sample i have tried so far
[UIView animateWithDuration:1.0f animations:^{
img.frame = CGRectMake(0, 0, 300, 300);
img.alpha = 1.0;
}];
but when ever i try to use that, instead of zooming in, it translates from one of the 4 diagonals :( I hope I have cleared this question as possible as I can.
Regards
You need to add tap gesture recognizer for each UIImageView you are adding to the cells.
You need to have hidden UIImageView to show when user taps the image.
Here is what you do on tap:
2.1 Assign image to your hidden UIImageView, set its alpha to 0.0 and make it not hidden
2.2 Set proper frame to the hidden image view.
2.3 animate the reveal of the image like
[UIView animateWithDuration:1.0f animations:^{
img.frame = CGRectMake(0, 0, 300, 300);
img.alpha = 1.0;
}];
2.4 add tap gesture recognizer to your hidden image view in order to dismiss it when user taps.
2.5 make reverse animation when user taps e.g. set alpha of displayed image view to 0.0 in uiview animation block.
I didn't provide the code for the whole thing assuming that you will learn and remember such things.
Good Luck!
EDIT: don't forget to add hidden uiimageview to your view.
I'm working on a drawing app.
I want the user to be able to "drop" a shape on the screen and then move, resize or rotate it as desired.
The problem is with the rotation. I have the moving and resizing working fine.
I did this before with a rather complex and memory/processor-intensive process, which I am now trying to improve.
I've searched and searched but haven't found an answer similar to what I'm trying to do.
Basically, let's say the user drops a square on the "surface". Then, they tap it and get some handles. They can touch anywhere and pan to move the square around (working already), touch and drag on a resize handle to resize the square (working already), or grab the rotation handle to have the square rotate around its center.
I've looked into drawing the square using UIBezierPath or just having it be a subclass of UIView that I fill.
In either case, I'm trying to rotate the UIView itself, not some contents inside. Every time I try to rotate the view, either nothing happens, the view vacates the screen or it rotates just a little bit and stops.
Here's some of the code I've tried (this doesn't work, and I've tried a lot of different approaches to this):
- (void) rotateByAngle:(CGFloat)angle
{
CGPoint cntr = [self center];
CGAffineTransform move = CGAffineTransformMakeTranslation(-1 * cntr.x, -1 * cntr.y);
[[self path] applyTransform:move];
CGAffineTransform rotate = CGAffineTransformMakeRotation(angle * M_PI / 180.0);
[[self path] applyTransform:rotate];
[self setNeedsDisplay];
CGAffineTransform moveback = CGAffineTransformMakeTranslation(cntr.x, cntr.y);
[[self path] applyTransform:moveback];
}
In case it isn't obvious, the thinking here it to move the view to the origin (0,0), rotate around that point and then move it back.
In case you're wondering, "angle" is calculated correctly. I've also wrapped the code above in a [UIView beginAnimations:nil context:NULL]/[UIView commitAnimations] block.
Is it possible to rotate a UIView a "custom" amount? I've seen/done it before where I animate a control to spin, but in those examples, the control always ended up "square" (i.e., it rotated 1 or more full circles and came back to its starting orientation).
Is it possible to perform this rotation "real-time" in response to UITouches? Do I need to draw the square as an item in the layer of the UIView and rotate the layer instead?
Just so you know, what I had working before was a shape drawn by a set of lines or UIBezierPaths. I would apply a CGAffineTransform to the data and then call the drawRect: method, which would re-draw the object inside of a custom UIView. This UIView would host quite a number of these items, all of which would need to be re-drawn anytime one of them needed it.
So, I'm trying to make the app more performant by creating a bunch of UIView subclasses, which will only get a command to re-draw when the user does something with them. Apple's Keynote for the iPad seems to accomplish this using UIGestureRecognizers, since you have to use two fingers to rotate an added shape. Is this the way to go?
Thoughts?
Thanks!
-(void)rotate{
CGAffineTransform transform;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
[UIView setAnimationCurve:UIViewAnimationOptionBeginFromCurrentState];
myView.alpha = 1;
transform = CGAffineTransformRotate(myView.transform,0.5*M_PI);
[myView setUserInteractionEnabled:YES];
myView.transform = transform;
[UIView commitAnimations];
}
This might help.
for just simple rotation you might leave out the Animation:
-(void)rotate:(CGFloat)angle
{
CGAffineTransform transform = CGAffineTransformRotate( myView.transform, angle * M_PI / 180.0 );
myView.transform = transform;
}
I use a simple NSTimer to control a animation.