UIScrollView zoomToRect scrolls the view when It should not - ios

I made a simple test project to show the problem:
there is an imageview which is contained in scrollview
view -> scrollview -> imageview
scrollview's content size is same as imageview size = (AllWidth, AllHeight).
The problem is that if scrollview is scaled EXACTLY to fit image by width (scrollView.zoomScale = 320.0/AllWidth;) then calling zoomToRect
[scrollView zoomToRect:CGRectMake(0.0, 0.0, AllWidth, AllHeight) animated: NO];
does scroll imageview to the bottom for some reason. But nothing is expected to happen with UI
if scrollview is NOT scaled EXACTLY to fit image by width (scrollView.zoomScale = (320.0-1)/AllWidth;), then calling zoomToRect does what is expected - image is scaled and not scrolled to the bottom.
i noticed that in 'buggy' case ContentOffset.y is changed, but i have no any idea why.
to reproduce the issue, start new project, in viewcontroller.h file add <UIScrollViewDelegate>; viewcontroller.m is here: http://pastebin.com/bPUtuYn1 (in test project you will need double tap green image, then change "320.0-1" to "320.0" and try again)

Related

Textview bounds UIImageView out of the View

I'm trying to rebuild the twitter post tweet feature as well as the UI. I'm currently at the point that, when I type something long in the UITextView. My selected image that I want to tweet get bounds out of the container view that is in a scrollview.
See this example:
The blue background is the scrollview background and the grey background is the container views background. I can't scroll too.
My UIImageView has initially 0 height and is directly attached to the top of the textview.
I change the height of the UIImageView with their constraint:
// sets the image
let newHeight = self.postedImageView.getImageHeight(forImage: image)
self.postedImageViewHeightConstraint.constant = newHeight
self.view.layoutIfNeeded()
self.postedImageView.showImage(image)
How can I make this the scrollviews contentView height to grow as I type something in the textview so it doesn't get bounds out the view?
These are my constraints:
Update:
With the postedimageviews bottom constraint added to the content views bottom

UIScrollView Bounces To Either Top Or Bottom

I have a UIScrollView for which I have a UIView which is the subview of the scroll view , the UIView has a lot of other subviews and I am getting the height for it dynamically after adding the subviews , this is my piece of code to add the view to scroll view
CGRect frameOfView = CGRectMake(0, 0,Get_Bounds.width, globalYPosition);
self.parentProductDetailView = [[UIView alloc]initWithFrame:frameOfView];
I am first initialising the view this way and then after adding all subviews I am doing this,
frameOfView.size.height = globalYPosition;
[self.parentProductDetailView layoutSubviews];
self.parentProductDetailView.frame = frameOfView;
[self.productDetailScrollView addSubview:self.parentProductDetailView];
self.productDetailScrollView.contentSize = CGSizeMake(0, self.parentProductDetailView.frame.size.height *1);
But my scrollview does not scroll properly it either sticks to top or bottom.
Here globalYPosition is the sum of height of all subviews added to parentProductDetailView
The procedure you used seems correct. No matter the subviews your scroll view should scroll properly by simply using a larger content size then its frame size.
The scroll view may stick, snap to some points if paging is enabled which is what is happening in your case. If the content view is larger then 1.5th of the frame size then the scroll view will snap to top/bottom or left/right. If it is smaller then it will only snap to starting position.
This may be very useful for situations like having a side menu that takes a part of a screen but in your case you should simply disable the paging and scrolling should work fine.

UIScrollView Zoom: Limit panning to imageView.image bounds

I have a screen-sized UIScrollView holding an identically sized UIImageView.
I have an image set inside of the UIImageView with AspectFit, so with a wider image, there are black bars on the top and bottom. This is as expected when zoomed out.
Double tapping the screen forces a [self.scrollView setZoomScale:self.scrollView.maximumZoomScale animated:YES]; The problem with this is that on images like the one mentioned above, I'm able to pan far beyond the edges of the photo.
I assume this is because I return imageView; in (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView and the imageView height is taller than the image, so I'm able to pan to the top and bottom of the imageView, ignoring its contents.
So, how do I limit panning the scrollview to the bounds of the image?
U need to use this: Emulating aspect-fit behaviour using AutoLayout constraints in Xcode 6
Aspect fit on Autolayout. Then You need add aspect ration constraint when loading image, if images are different size. U can get one error, image after zoom sticks to right edge. Still can't solve it.
Just set the content size of scrollview to the size of image just by this code:
scrollView.contentSize = [scrollView imageView].image.size;
Note that you should do this at the time you set image for your scrollview imageView.

UIView is a child of UIScrollview, but when I zoom in or out the UIView doesn't stay in the correct location relative to the image in the scrollview

The scrollview shows a floorplan, and the UIView is a little green dot that shows the user's location on the floorplan. So I need to be able to zoom in, and have the green dot stay in the same spot on the floorplan. When I pan, the green dot moves correctly, but when I zoom, it moves away from where it should be.
Here is a screenshot of my storyboard. The small green square is the view that is a child of the Scrollview, and shows the user's location. I move it around programatically, but this is not causing the problem. http://i.imgur.com/TTRMXNS.png
Heres the code that puts the tilemap into the scrollview:
CCDirector* director = (CCDirector *)[self childViewControllers][0];
director.view.frame = CGRectMake(0, 0, floorplanWidth, floorplanHeight);
CGSize sizeOfScene = CGSizeMake(floorplanWidth, floorplanHeight);
float minimumScale = 1;//This is the minimum scale, set it to whatever you want. 1.0 = default
_sceneScrollView.maximumZoomScale = 4.0;
_sceneScrollView.minimumZoomScale = minimumScale;
_sceneScrollView.zoomScale = .1;
[_sceneScrollView setContentMode:UIViewContentModeScaleAspectFit];
[_sceneScrollView sizeToFit];
[_sceneScrollView setContentSize:sizeOfScene];
[_sceneScrollView addSubview:[director view]];
There's actually a lot of things wrong with what I see above that leads me to believe that you should probably look up more information regarding iOS and scrollviews. The first thing is that a scrollView has a contentSize that's either intrinsically determined via auto layout, or via code by setting the contentSize. In this case, your contentSize would be set via setting the image. The second thing to note is when you zoom in using a scrollView, you provide a view to zoom in on. This view and it's respective subviews will be zoomed in on. I see that your green dot is in the storyboard and is a direct subview inside the scrollview's contentView, this is incorrect. Your green dot will need to be either a subview of your own containerView with the UIImageView and your dot in it, or a subview of your UIImageView (which is sometimes wanky in the storyboard, you'll you'll want to add that in code). To note, UIImageViews have their own scale factor inside of them versus iOS's scale factor. So if you're attempting to dynamically mark anything in a UIImageView, keep that in mind.

imageView centered inside scrollView

How can I vertically center an image inside a scrollView?
I'm using storyboards in Xcode 5. The main view is embedded inside a navigation controller, and "Adjust scroll view insets" option is enabled in main Storyboard. This main view has a scrollView which size is equal to the main view size.
The imageView is inside the scrollView and it's the same size as the scrollView. Content mode is set to AspectFit.
So, hierarchy is as follows:
- UINavigationController
- UIView
- UIScrollView
- UIImageView
The image may be landscape or portrait, and can be any size (it's loaded at runtime). This is why imageView is the same size as the scrollView.
How can I vertically center the image inside the scrollView?
EDIT:
As commented before, I have set imageView's contentMode to AspectFit because the image may be too big, so I need it resized. The problem I have is that the image is not center of the scrollView.
You can check screenshot at link and download source code at link.
It will be good to use auto layout as mentioned by #Douglas. However, if you prefer the traditional way, you can also make it work.
I'll first give you the answer and then explain it to you. You should first delete the image view from the storyboard ( I'll explain it later), and then add the viewWillAppear method.
- (void)viewDidLoad
{
[super viewDidLoad];
// 1. Add the image view programatically
UIImageView * imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"portrait.jpg"]];
[_scrollView addSubview:imageView];
_imageView = imageView;
}
- (void)viewWillAppear:(BOOL)animated
{
// 2. calculate the size of the image view
CGFloat scrollViewWidth = CGRectGetWidth(_scrollView.frame);
CGFloat scrollViewHeight = CGRectGetHeight(_scrollView.frame);
CGFloat imageViewWidth = CGRectGetWidth(_imageView.frame);
CGFloat imageViewHeight = CGRectGetHeight(_imageView.frame);
CGFloat widthRatio = scrollViewWidth / imageViewWidth;
CGFloat heightRation = scrollViewHeight / imageViewHeight;
CGFloat ratio = MIN(widthRatio, heightRation);
CGRect newImageFrame = CGRectMake(0, 0, imageViewWidth * ratio, imageViewHeight * ratio);
_imageView.frame = newImageFrame;
// 3. find the position of the imageView.
CGFloat scrollViewCenterX = CGRectGetMidX(_scrollView.bounds);
CGFloat scrollViewCenterY = CGRectGetMidY(_scrollView.bounds) + _scrollView.contentInset.top / 2 ;
_imageView.center = CGPointMake(scrollViewCenterX, scrollViewCenterY);
}
Here is the explanation:
You should not put the imageView in the storyboard, otherwise the frame of the imageView will be fixed by the storyboard, and will not change with the size of the image. Even if you choose UIViewContentModeScaleAspectFill, the frame of the imageView is still not changed. It just add some white space around the image.
Now the imageView has the same size as your image. If you want it to be fully displayed, you need to calculate the frame yourself.
Pay attention to the _scrollView.contentInset.top / 2, this is why you need to put the codes in viewWillAppear instead of viewDidLoad. The _scrollView.contentInset.top is the height of the navigation bar and is calculated automatically for you before willViewAppear.
You put your image view in a scrollView, I guess you want to zoom in and out. If this is true, add self.imageView = imageView; and the bottom of viewDidLoad. Set the delegate of _scrollView to self and add the following method:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return _imageView;
}
I made a comment, but then took a look at your project. You are almost there. I ran through the following steps and have gotten the result you are looking for.
First, make sure you have auto layout turned ON!!!
In your storyboard click on your scroll view. You had a scroll view that was the same size as the view. You are going to put on some constraints. Down at the bottom of the story board you will see some icons.
The fourth one over looks sort of like an I-beam on its side, it is the pin button. After selecting the scroll view, click on this and it will bring up a pop up menu.
For the scroll view click on all the bars around the middle block so you pin the scroll view to the sides of the main view.
You will notice they are all red now.
Then go and click on the imageview. Once again you had it set to the size of the view. Using the pin button again, you are going to pin just the Width at 320 and the Height at 568. When you are done you are then going to use the next button over.
This is the align button. Click on that after you have selected your image view. You are going to click on Horizontal Center in Container, and Vertical Center in Container.
Next you will need to add one method to your ViewController.m file.
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[_scrollView setContentSize:CGSizeMake(self.view.frame.size.width, self.view.frame.size.height)];
}
Start up the simulator and let her rip! You will get one warning though. It says the content size is ambiguous for the scroll view. But that's OK, because you will set it on viewDidLayoutSubviews.
Hope that helps, or helps someone out. Autolayout and scroll views are a bit tough!!
EDIT#1
if you want to then make the image view scalable, by pinch zooming you can do the following.
Make sure you made the .h file follow the UIScrollViewDelagate.
#interface ViewController : UIViewController <UIScrollViewDelegate>
This will allow the scroll view to be able to access the delegate methods of the scroll view. The method you are looking for is called..
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
Then in the viewDidLoad method of your .m file do the following.
_scrollView.minimumZoomScale = 0.5;
_scrollView.maximumZoomScale = 4.0;
_scrollView.delegate = self;
The underscore and the variable name is the same as self.variable. Either will work.
That should do it. Let me know if it works or if you have any other questions. ENJOY!
These are the ones u can use, the 3 modes of ImageView content display.You can do this by dynamically setting them or u can set them in storyboard too, click on the ImageView and go to properties tab-bar and choose from there, run them and select which output u want.
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.contentMode = UIViewContentModeScaleToFill;
imageView.contentMode = UIViewContentModeScaleAspectFill;
Hope this helps
If you want to center image in an imageview use
imageView.contentMode=UIViewContentModeCenter;
image retains it's size in this this content mode. Alternatively you can use other content modes as per your requirement.
UIViewContentModeScaleToFill,
UIViewContentModeScaleAspectFit, // contents scaled to fit with fixed aspect. remainder is transparent
UIViewContentModeScaleAspectFill, // contents scaled to fill with fixed aspect. some portion of content may be clipped.
UIViewContentModeRedraw, // redraw on bounds change (calls -setNeedsDisplay)
UIViewContentModeCenter, // contents remain same size. positioned adjusted.
UIViewContentModeTop,
UIViewContentModeBottom,
UIViewContentModeLeft,
UIViewContentModeRight,
UIViewContentModeTopLeft,
UIViewContentModeTopRight,
UIViewContentModeBottomLeft,
UIViewContentModeBottomRight,

Resources