How to zoom for an iOS drawing app? - iphone

I'm making a drawing application for the iPad where users use one finger to draw lines and rectangles. However, i'm struggling with adding the zoom features.
Some background info of my current code:
There is an appdelegate which sets the view controller
Most of the action takes place inside the view controller including IBActions, popovers, etc.
The xib file uses a custom view i made and this is where all the drawing actions take place
This is what i've done so far:
Inside viewDidLoad, i have
[scrollView setContentSize:CGSizeMake(768, 1024)];
[scrollView setMinimumZoomScale:0.5];
[scrollView setMaximumZoomScale:5];
[scrollView setDelegate:self];
In my xib file, i tried tossing a UIScrollView ontop of my customview (and making the IB connections), but of course, it covers my custom view and you can't draw. I tried the reverse by placing a UIScrollView followed by my own custom view, but i still can't draw either.
Any pointers on what to do?

Add this to your viewController in the .h file:
<UIScrollViewDelegate>
An then this on your .m file:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return backgroundImage;
}
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {
NSLog(#"scrollViewDidEndZooming");
}
Also, make sure that in your xib, the scrollview's delegate is linked to File's Owner.
Edit 1:

Related

add subview to custom uiview in interfacebuilder

I have made a custom UIView composed of several subviews and added it to a Nib file.
The view is loading correctly, but my problem arises when I try to add a UIView to my custom UIView from InterfaceBuilder.
I would like the added subviews to go to the topmost subview of my custom UIView, but not surprisingly, the subviews are added to the root custom UIView.
I could do some magic in the init of the custom UIView, moving the added view around.
is there any alternatives?
Any thought on best practice to solve this?
That seems to be right, since when you add the customView, int the nib file, you dont have access to its child subView, that means adding views to this custom view, will add them to the root view and not the childs,
As you said you will have to do some workaround to make this work, such as using tags to define the views and then move them by code
You need to add your Custom UIView to subview of your Root view and all other subviews of root UIView as a subview of your Custom View.So that you can get what exactly you want.
You IB hierarchy should be like below...
--->Root UIView
--->Custom UIView
--->UItextField
--->UIlabel
--->UiimageView
If you adding your Custom UIView in a code, then you need to connect IBoutlet for all subviews and then make them all as a subview of your custom view.
There doesn't seem to be any clever solution.
Instead i ended up overriding layoutSubviews like this:
-(void)layoutSubviews
{
[super layoutSubviews];
for (UIView *subview in self.subviews){
if (![self.internalViews containsObject:subview]) {
[subview removeFromSuperview];
CGRect f =subview.frame;
f.origin.y += self.frame.origin.y;
subview.frame = f;
[self.contentContainer addSubview:subview];
}
}
}
Doing construction of the view i added all by subviews to the array internalViews. The contentContainer is the view intended to serve as parent for all InterfaceBuilder added view.

Create a scrollable menu with UIImages representing each possible selection. These UIImages must be able to snap to the grid one by one

I'm trying to create a menu (using UIScrollView) where the user can select images (using UIImageViews).
I intend to have at least 3 images visible at anytime. When I scroll, the images will be able to snap into position.
However, if I am to use a UIScrollView which is large enough to display 3 images at anyone time, and I enable paging, the paging will move all 3 images together and snap only at the next 3 images.
And if I am to use UIScrollView that fits just 1 image, and I enable clipsToBounds (which helps me draw the images beyond the boundary of the UIScrollView). My figure gestures can only be detected within UIScrollView itself, I want my figure gestures to be detected as long as any of the images are touched.
Thanks.
You can use following method of UIScrollView to scroll it from code as much as you want.
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated
you can call this from following method of UIScrowViewDelegate.
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
Thus, you can manage how much you scroll view will call.
And for getting touches, implement a separate class that display images(inherit it from UIImageView or UIView) and implement touchesBegin or touchesEnded in that. Here when you get the touch in your custom view call some method of parent view and notify it with proper arguments(you can assign tag property and pass it to scroll view to find exactly which image was tapped).
.....I am not sure weather I am solving your problem or not.....so post here if you need any further assistance.
I wrote a custom UIView class which overrides the hitTest method of UIView.
In the header of the custom UIView class, declare a UIScrollView, later you will need to assign the UIScrollView which is displaying the menu to this variable.
UIScrollView *thatScrollView;
In the implementation, remember to synthesize the variable and overwrite hitTest
#synthesize thatScrollView;
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if ([self pointInside:point withEvent:event]) {
return thatScrollView;
}
return nil;
}
Then in the UIViewController class, create an instance of the class and assign the scrollview you want to scroll:
hiddenView.underneathButton = scrollView1;

layoutsubviews only called once despite any device rotation

just what the title says: I create an empty UIView subclass and I add a subview to it, I create an empty layoutSubviews method and I add a breakpoint there. Then I build the project and the simulation stops when loading the view at that point in the layoutSubviews method. Everything is fine so far. I continue the simulation and I rotate the device (assuming that the view controller is set to allow any orientation) but layoutSubviews is never called again, despite I can see how my object is rotating.
Any idea?
OK, i will simplify my question: How do I create a custom UIView with some subviews and make it responsive to the device orientation? I don't need to use drawRect or anything, just subclass UIView, add a couple of subViews and handle them when the device is rotating.
Did you try setting the autoresizingMask on the UIView? For example like below:
someView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
From the UIView documentation:
'When a view’s bounds change, that view automatically resizes its
subviews according to each subview’s autoresizing mask'
If you set the autoresizingMask to something other than None it should mean that the layoutSubviews method is always called when the views bounds change.
I'm not sure if it's exactly the same but i ran into a similar problem. I was using a UISplitViewContoller (template from Xcode) and adding a subview into the DetailViewController. The layoutSubviews methods was not getting called on rotation because it was a subview of the main UIView in the ViewController. So i added this to the DetailsViewController to get it to work (detailView is my subview):
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
if (detailView != nil) [detailView layoutSubviews];
}

Problem with UIScrollView and CATiledLayer

I'm working on the example code named PhotoScroller (an Apple's example of WWDC 2010).
There is an UIScrollView which return a custom UIView when zooming
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
    return imageView;
}
The layer of this imageView is a CATiledLayer.
My problem is for each zoom the drawRect of the imageView is called (so 10 or 30 times for a basic zoom). And then it refresh ALL the screen (so the size given to drawrect in fact).
I would like to refresh some parts of the UIImageView when a zoom occured and not all the screen (so by using setNeedDisplayInRect: instead of setNeedDisplay).
But I don't know how to proceed to avoid the call of this refresh method to do some if else and so refresh some parts of the imageView.
I tried to add an other UIView between the UIScrollView and the subclassed uiview (with catiledlayer). But I don't know how to prevent the subviews to be refreshed :-/
If anyone has an idea, It would be very helpful !
Thanks :-)
Vincent

How to get active subview (UIImageView) from UIScrollView

I have several UIImage subviews in one UIScrollView. I'm trying to emulate iPhones's Photos app. To enable pinch zooming, I have implemented UIScrollViewDelegate and the one thing I'm unable to figure out is this delegate function:
(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView;
How do I find out which UIImage subview is currently active?
Something like:
(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
return activeUIImageViewSubView;
}
You probably want to keep track yourself of the current UIImage subview.
Or if you have only one visible at a time, look for the one with the coordinate values that make it visible.
If you want to zoom them all at the same time, you may want to group all your UIImage in an intermediate UIView that could be scrolled and panned.