How to zoom two Images placed side by side, together? - iphone

I have two scroll-views placed side by side and they can be zoomed individually. I've done this by putting my view inside a scrollview and setting the zoom-scale for the scroll-views. So far, it works fine! Now, there's a new requirement to zoom the two images together so that if I zoom one image, the other is zoomed automatically with the same zoom scale. I was given the roambi app as reference in which two scrollviews can be scrolled together by scrolling either one of them for convenience during comparison. Basically, what I'm doing is also comparison between the two views. I've gone through scrollview delegate methods but was unable to achieve the required results. How do I do this?

I've never done this, but off the top of my head I would say first you need to get the zooming being the same in both of them (as per above), then you'll have to use the delegate methods to make sure both of your scrollviews have the same contentOffset value. i.e. when one changes via manual scrolling or via programmatic scrolling, you have to (using the delegate callbacks) set the other one to the same contentOffset value.
EDIT: As per request, adding a bit of (UNTESTED) code:
- (void)scrollViewDidScroll:(UIScrollView*)scrollView
{
if(scrollView == self.myFirstScroller)
{
self.mySecondScroller.contentOffset = self.myFirstScroller.contentOffset;
}
else {
self.myFirstScroller.contentOffset = self.mySecondScroller.contentOffset;
}
}
and zooming done similarly to above.
But if you're looking for some copy-paste solution you can just drop into your project, I'm afraid you'll have to teach yourself a bit more about scroll views. You should read the Apple Programming Guide, because scrollviews can be a bit tricky, and you often have to use quite a few of the delegate methods to get things working correctly.

I had implemented something similar a while ago (I did it for buttons). This is how I did it:
Take two UIScrollViews and reference them (I've used firstScrollView and secondScrollView)
Take two UIButtons and reference them (I've used firstImgBtn and secondImgBtn). Set the delegates to both the scrollviews and use the following delegate methods:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
//return the respective button in the scrollview to be zoomed
if(scrollView==firstScrollView){
return firstImgBtn;
}
else{
return secondImgBtn;
}
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView{
// zoom in the other scrollview when one has zoomed
if(zoomTogether){//a bool to decide whether to zoom the two together or not
if(scrollView==firstScrollView){
secondScrollView.zoomScale = firstScrollView.zoomScale;
}
else{
firstScrollView.zoomScale = secondScrollView.zoomScale;
}
}
}
This can be applied to any subclass of UIView-in your case it will be UIImageViews

Related

VoiceOver ignores visible views, and speaks accessibilityLabels of hidden views

I have UIView, that can contain one of two views. When I removeFromSuperview first view and addSubview second view I can still hear accessibiliyLabel of hidden view. And only in 1-2 seconds I can hear correct accessibiilityLabel.
I see that it is common situation when hidden state of view is changed, accessibility can be frustrated and still speak hidden views, and does not note visible views.
Also if in UITableViewCell UIButton is hidden and then hidden state changes to NO, VoiceOver ignores it like it is still hidden. Only manual implementation of UIAccessibilityContainer protocol for cell resolves mentioned problem
No Notifications can solve this issue. Even playing with accessibilityElementsHidden did not help. Struggling with this during several days
Please can you recommend is there any way to say Accessibility that hierarhy of views was changed
You can post a UIAccessibilityScreenChangedNotification or UIAccessibilityLayoutChanged to alert UIAccessibility that the view changed. Since you didn't post any code, I can only give you a generic example, e.g.:
UIAccessibilityPostnotification(UIAccessibilityLayoutChanged,accessibilityelement)
...where "accessibilityelement" would be a button or text field or other accessibility element that VoiceOver switches to next.
Reference: UIKIt Reference
Just ran into this myself with a third party side menu library and had to use accessibilityElementsHidden to fix it. I first tried leveraging the accessibilityViewIsModal property, but that only works on sibling views.
#pragma mark - IIViewDeckControllerDelegate
- (void)viewDeckController:(IIViewDeckController *)viewDeckController didOpenViewSide:(IIViewDeckSide)viewDeckSide animated:(BOOL)animated
{
if (viewDeckSide == IIViewDeckLeftSide) {
[self.topViewController.view endEditing:YES];
self.viewDeckController.leftController.view.accessibilityElementsHidden = NO;
}
}
- (void)viewDeckController:(IIViewDeckController *)viewDeckController didCloseViewSide:(IIViewDeckSide)viewDeckSide animated:(BOOL)animated
{
self.viewDeckController.leftController.view.accessibilityElementsHidden = YES;
}

CATiledLayer - how to use when async downloading images

In my application, I have got a scrollview, a bigger one with lots of subviews on it, subviews gets added dynamically based on scroll. I try to add subviews (imageviews) dynamically on scroll and when user scrolls then I try to fetch more images asynchronously based on pageSize etc from server and these images gets placed into it's corresponding imageview..
I have gone through Apple's WWDC Sessoion 104 as well which appears to be good for offline images.
I also try to resize the images on my scrollview in a ratio, which is fine I believe. The problem is When the number of images increases on the scrollview then application runs out of memory. It must be due to me using the images directly in an imageview instead of using CATiledLayer. But, I am looking for help in displaying async images on scrollview using CATiledLayer.
Many Thanks,
Reno Jones
I edit completely the answer based on the comments.
You should set a controller as delegate of the scrollview than in the scrollViewDidScroll: (or in scrollViewDidEndDecelerating: if you want to check it less often) method you can check if some your images are outside the visible part of the content view and then release (i.e. set the pointer to nil) them to save some memory.
For your convenience here's an example how to get the visible part of your content:
CGRect visibleRect;
visibleRect.origin = scrollView.contentOffset;
visibleRect.size = scrollView.bounds.size;
everything completely outside this rect should be released (of course you then have to reload them if user scroll: it may be tricky constantly load/unload...)
This in simple words is all I did.. I have already been downloading images async and caching them up on device, then I have added an UIImage (imageObject) property to my current tile class, which holds the image object being downloaded and then implemented the following and did the trick for me. And believe me or not, imageview loading vs CATiledLayer - CATiledLayer is 100x faster and efficient.
+ layerClass
{
return [CATiledLayer class];
}
- (void)drawRect:(CGRect)rect
{
[imgObject drawAtPoint:CGPointMake(0,0)];
}
Hope it helps someone else in future. Let me know if I can be of more help.

Scaling subviews nested deep within UIScrollView

This is causing me a headache of untold proportions.
I am trying to create a UML Drawing application for the iPad.
I currently have functionality to add classes to a 'canvas'. The canvas is simply a UIView, which is located within a UIScrollView.
Each class element is a UIView containing the class name, attributes and methods (UITextFields). These are all subviews of the canvas.
The problem I'm having is when I zoom in on the classes using the pinch/zoom functionality I'm just getting blurry UITextFields. To my understanding, this is because the UIScrollView just applies a transform, and that I need to handle scaling myself.
The only way I can think of doing this however is to redraw the classes and make them larger, which could potentially distort their placement relative to each other. For example if I had two classes side by side, and one doubled in size, then the left class may overlap the right one.
I've searched for hours for a solution and I'm getting nowhere, does anyone know of a code sample or advice that can illustrate a situation resembling mine? Or, if not, an example that shows how to scale a UITextField (or UILabel) in the manner I've described?
I'm thinking this may not be the most obvious answer based on how my question was phrased. But I solved the problem like so:
The first step is to implement the:
- (void)scrollViewDidEndZooming:(UIScrollView
*)scrollView withView:(UIView *)view atScale:(float)scale;
The key point I seemed to be missing (somehow) was that when the UIScrollView is scaled, it then resets it's scale factor to 1. So imagine you zoomed to 125%, and then zoomed out 25%, you'd actually be looking at your original view at 93% (ish), not 100%.
This obviously throws your drawing if, like me, you were trying to scale the subviews in relation to their original size.
The best way then is to keep a track of the scale (I used the variable scaleTracker) and then use this value to scale your views.
More specifically for my problem, the following code was used:
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
scaleTracker *= scale;
[canvas setTransform:CGAffineTransformIdentity];
canvas.frame = CGRectMake((int)canvas.original.origin.x,
(int)canvas.original.origin.y,
(int)(canvas.original.size.width * scaleTracker),
(int)(canvas.original.size.height * scaleTracker));
}
Good luck to anyone else who has issues with UIScrollView. For now I hope this can offer some help to any who are interested.

An easy, clean way to switch/swap views?

I have looked at several sources but I am still very confused! I want to make an application with several views (just standard views, no table views or anything), from which I can click buttons on each view to access the others.
I've seen several ways to do this, but the only one that made any sense to me is to have the application delegate be responsible for swapping views. And I'm not even sure my code correctly cleans up the memory of the view it's swapping!
Is there a cleaner, or easier way to switch between views (I don't care about animations) than using a delegate?
I've also seen presentModalViewController, but that seems sort of unorganized. (E.g. If you have more than one view presenting a modal, how can you easily tell the newest view to close all views up to the root).
There's also creating a window-based application and using the window to addSubView, and removeFromSuperview, but how would you swap one very for another without creating extra, cumbersome coding in the delegate method to detect what view what removed, and which new view should be added? I can't find an addViewToSuperview method, at least.
So please share how you guys swap views, and perhaps the benefit to your system.
Talk really slow, because I feel very slow when it comes to swapping views!
Thank you for your time!
Dealing with multiple views is pretty easy if you understand the concept behind the views. For example your Delegate could be linked to an empty parent View. Then you just create your children views and add them to the parent view with addSubview. The last added view is the one that will be displayed in the foreground.
Now you can bring the views into the front using bringSubviewToFront method. Keep in mind that all your views are kept in memory until you remove them from the parent view using the children view's removeFromSuperview method.
Swapping views is just removing the child view before you add the next one but then you have to decide if you want to retain them or if you want to release them but then you need to *re-create (alloc / init) the views later.
BTW If you views are not at the right place then you either need to adjust the positions relative to the parent view or set them right in the interface builder because iOS will not reposition them because you add them as sub view.
For example I used that code to switch between a view that displays an Ad or a ticker:
- (void) showAds:(BOOL)flag {
if( showAds != flag ) {
while([[self.bottomView subviews] count] > 0 ) {
[[[self.bottomView subviews] objectAtIndex:0] removeFromSuperview];
}
showAds = flag;
if( showAds ) {
[self.tickerViewController stop];
[self.bottomView addSubview:self.adViewController.view];
} else {
[self.bottomView addSubview:self.tickerViewController.view];
[self.tickerViewController start];
}
}}
The 2nd line makes sure I don't remove and add if nothing has changed. The next 3 lines remove any residual sub views. After that either add the Add or the Ticker view as my current sub view (including making sure the ticker is started / stopped properly).
Hope that helps.

How do I choose the correct view for zooming with multiple UIScrollView objects in a view (iPhoneSDK obj-C)?

I have added several UIScrollViews as subviews of a single UIView and set the frames so that each one is clearly visable. I set scrollEnabled to YES and set the contentSize larger than the bounds/frame. I do this in a for loop, and with each pass of the loop I release the UIScrollView (though the object is still stored because it has been subviewed into the UIView). This works well for being able to scroll around the imageView stored in each particular UIScrollView but I cannot for the life of me figure out how to get the zoom to work. I included the in the interface. Here are the methods I have tried for choosing the correct view for zooming:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
return [[myView subviews] objectAtIndex:pageNum];
}
and
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
return [myView viewWithTag:pageNum];
}
neither seems to work. The weird part is that scrolling works fine. I can't even get the viewForZooming method to get called at all if I put in an NSLog call. Any ideas? I think I've lost all my hair from getting frustrated with this.
Edit: Thanks a lot cduhn! All I needed was that little bump, I had forgotten to set the scrollView delegate to self... I've been working with various apps that take advantage of UIScrollView for months now and been using the delegate correctly and this most recent one I don't know where my brain went.
However, you do not need to override the scrollViewDidEndZooming:withView:atScale:, the delegate will call that no matter what after a zoom.
Also, after a little tweeking this worked:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
return [[[myView viewWithTag:pageNum] subviews] objectAtIndex:0];
}
This simply calls the scrollView inside View container and then gets the UIImage inside of that... works well.
It sounds like you may not have set the delegate property on your UIScrollViews to point at the object that implements viewForZoomingInScrollView:
Also note this snippet from the UIScrollView Class Reference:
For zooming and panning to work, the delegate must implement both viewForZoomingInScrollView: and scrollViewDidEndZooming:withView:atScale:; in addition, the maximum (maximumZoomScale) and minimum ( minimumZoomScale) zoom scale must be different.
Finally, a word of warning: Be careful when accessing the subviews of UIScrollView. Your subviews are not alone in there. UIScrollView adds its own UIImageViews as subviews of itself to implement its scrollbar UI. So code like this...
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return [[myView subviews] objectAtIndex:pageNum];
}
... may not do what you expect.