Cause UIScrollView zoomToRect: to only display a portion - objective-c

I have a UIScrollView subclass that contains a UIImageView. When the user double taps on the zone I want to zoom to that CGRect (calculated from CGPoint) and "hide" the rest of the UIImageView. The final effect is similar in Mavel.app and The Walking Dead.app when you are reading a comic.
Until now I got:
-(void)presentRect:(CGRect)rect {
self.bounds = originalFrame; //1
[UIView beginAnimations:#"navigateToPos" context:nil];
[self zoomToRect:rect animated:NO];
self.bounds = rect;
[UIView commitAnimations];
}
This works, but "zoomToRect" needs the whole bounds of the UIScrollView and when I restart it (line 1), it gives an undesired effect.
I am stuck with this. I don't know if I need a new approach or need to use another property of UIScrollView.
Any help is appreciated. Thanks.

I downloaded this apps to see it. I'm almost sure they didn't even use uiscrollview. The way the pages moves make me think about that. And uiscrollview should be used only when you really need it, because it have a lot issues when you're customizing. (tiled content, zooming and others problems).
Slide to a next page only 50px aprox., the page goes to the next, in uiscrollview it didn't happen because it works diff.
As I said before, probably it's made using 4 bars (as you correct me) or it can be done with a view wrapping the uiimage and working as a mask. You only need calculate the size of the zoom square and move it to center, and resize the wrapper view to fit this new size. The substitute for the uiscrollview for pages can be a simple image gallery, but where is images you put this "comic-view".

I've solved using other properies from UIScrollView simulating the desired effect.

Related

Identifying correct window frame size for filling background color

I am developing in Cocoa, and I am currently having problems with filling the background of a NSWindowController.
I understand that subclassing is the way forward if you want to customise your cocoa app. So I created a custom NSView named whiteView and added this view as a subview to my windowController's contentView; however, there are some issues with completely filling the background of the window. Can anyone explain how I can have the color cover the complete surface area of the window's frame pls. Thank you
These are the results that I have so far.
1) This is the window when I leave it as it is, notice the white color only having covered half of the window.
2)Here is the same window again when I adjust the window far to the right and bottom. The white screen seems to stretch enough so that it covers the elements.
This is how I create the custom view
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
[[NSColor whiteColor] set];
NSRectFill([self bounds]);
}
And this how I achieve plaster the view onto my window.
WhiteView *whiteBackgroundView = [[WhiteView alloc] initWithFrame:self.window.frame];
[self.window.contentView addSubview:whiteBackgroundView positioned:NSWindowBelow relativeTo:self.window.contentView];
What do I need to do to correctly allow for my window's background to be fully covered in white?
First, the simple solution is to use -[NSWindow setBackgroundColor:] to just set the window's background color. No need for a view.
If you're still interested in how to fix the view-based approach, probably what's wrong is that you haven't set the autoresizing mask of the view to make it follow the changes in the window size. For example, you could do [whiteBackgroundView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable].
However, you could also set the whiteBackgroundView as the window's contentView rather than as a subview of it. The window's content view is always kept at the size necessary to fill the window's content rect. All of the other views of your window would be subviews of the white background view. In my opinion, this is better than making it a sibling that just happens to be at the back. Using relative ordering among siblings views to achieve a particular rendering order is a hack.
Finally, there's no reason to invoke super's implementation in your -drawRect: if the superclass is NSView itself. NSView doesn't do any drawing in its -drawRect:. Also, your subclass takes over full responsibility for the entire drawn contents of its bounds, so you'd overdraw whatever super had drawn, anyway. (Also, you need only fill dirtyRect rather than [self bounds].)
While you're at it, since your class fills its bounds, you should override -isOpaque to return YES for optimization.
Update: regarding the frame of the view: if it's not going to be the window's content view, then you want to set its frame to be its prospective superview's bounds. So, you should have used self.window.contentView.bounds if you wanted whiteBackgroundView to fill the content view.
More generally, if you want the content rect of a window, you would do [window contentRectForFrameRect:window.frame]. But if a view is going to be a window's content view, there's no need to set its frame to anything in particular. It will be resized automatically.
Update 2:
To transfer the view hierarchy from the original content view to the new content view (when you're making the white background view the content view):
NSArray* subviews = [self.window.contentView.subviews copy];
[subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
[whiteBackgroundView setSubviews:subviews];
[subviews release];
(Written for manual retain-release. If using ARC, just drop the -release invocation.)
Regarding the frame to use, as mentioned in the first update: keep in mind that the view's frame should be expressed in the coordinate system of its superview. So, as I said, self.window.contentView.bounds would work if you're putting the new view into the content view. The window's frame and content rect are in screen coordinates. They would be completely incorrect for positioning a view.

How to dynamically size UITableView in Objective-C?

I'm just starting with iOS development and I was trying to achieve something that doesn't seem to work so far for me...
Here's the situation:
I have a nib file in which I have placed a UITableView, and just underneath a UIToolbar. That works just fine, the scaling is fine if I try different screensizes etc... So I was happy.
But here's the problem:
If the toolbar should be visible or not is a choice that a user can make somewhere in the application. However when the users selects to not see the toolbar I just call the method setHidden on the toolbar and pass it 'YES'.
The toolbar is now gone when I try this but the UITableView is not strechted to the bottom of the screen which gives me quite an ugly result.
So here's finally the question:
How can I automatically let the view stretch to the bottom when hiding toolbar? I guess I will have to do it in code (and not just some configuration option somewhere) but as I'm coming from Android this is somewhat strange for me.
Your best option will probably be to resize the tableview frame as you show/hide the tool bar.
CGRect frame = myTableView.frame;
frame.size.height += toolbar.frame.height;
myTableView.frame = frame;
Because you're using Auto-Layout, you'd want to create a height constraint for the UITableView and link it with your view controller via an IBOutlet. Then, to modify the height of the UITableView, simply do:
_tableViewHeightConstraint.constant += toolbar.frame.height;
You can even animate this with:
[UIView animateWithDuration:0.25 animations:^{
_tableViewHeightConstraint.constant += toolbar.frame.height;
}];
Note that you might need to call [_tableView layoutIfNeeded] after changing the height constraint.

How can I flip between two UIView?

I'm using two UITextView objects. Each UITextView represents the side of a single card in a flash card application. Just like when using regular flash cards, I want the user to have the ability to flip a card. I am asking how to flip between two UIView objects because UITextView are UIView subclasses so the same idea should work.
The animation I am looking for looks like this.
The only problem with the above example is that it utilizes two UIViewController objects and UITextView is not a subclass of UIViewController so the same principle does not apply.
Any ideas on how to do the flip animation?
You can use the UIView class method +transitionFromView:toView:duration:options:completion: to accomplish this. Both your text views need to be descendants of a common superview. Use the option UIViewAnimationOptionTransitionFlipFromLeft (or ...FromRight) to get a horizontal flip.
Looks like your question has been answered already here, just tweak the transform to make it a horizontal instead of vertical flip:
- (void)horizontalFlip {
[UIView animateWithDuration:someDuration animations:^{
yourView.layer.transform = CATransform3DMakeRotation(M_PI, 0.0, 1.0, 0.0);
} completion:^(BOOL finished){
// code to be executed when flip is completed
}];
}
As explained in that linked question, you can further modify this to do half the flip by using M_PI_2, then in the completion block of the first animation swap out the UITextViews and start a new animation to finish the flip.
Don't forget to #import math.h and #import <QuartzCore/Quartz.h> at the top of your file!
you can first hide the one UITextView and Show the another UITextView. To flip it, you can hide the displayed UITextView and show the hidden UITextView. You can also use animations explained here for it to create a flip effect.

Uiwebview in uiscrollview tips

I have a UIScrollview to allow for pagination, and a UIWebview on the detail views inside. I know you are not supposed to do that according to Apples Class Reference, but I don't see another option.
In order to make responses and experience a bit better, I disabled scrolling of the UIWebview, with:
[[[webView subviews] lastObject] setScrollEnabled:FALSE];
But now I am looking for a solution to make the webview the right size, depending on the content. Is there an easy way to do this, where the width of the webview stays the same, but the height grows (automatically) when that is required to show the full article? This will remove the scrolling problem, as it sit he scrollview who will take care of all the scrolling in this scenario.
Does that make sense?
From the documentation for UIWebView, it states:
Important: You should not embed UIWebView or UITableView objects in
UIScrollView objects. If you do so, unexpected behavior can result
because touch events for the two objects can be mixed up and wrongly
handled.
A more appropriate approach would be to add your UIWebView to a UIViewController with a UIScrollView (or UITableView) underneath. I'd be conscious of the amount of space you'll have left though for the scroll view though, especially if you're dealing with the iPhone.
Hope that's a nudge in the right direction.
Update:
After looking into this (I was sure there would be a way), it seems the best approach I managed to come up with is to add your UIWebView to the header view of a UITableView.
//create webview
_webView = [[UIWebView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 280.0)];
//load request and scale content to fit
[_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.stackoverflow.com/"]]];
[_webView setScalesPageToFit:YES];
//add web view to table header view
[[self tableView] setTableHeaderView:_webview];
This adds a UIWebView to the header of the table view before the cells are displayed underneath. Note that a table header view (and footer views also) are different from section headers (and footers) so you can still use these two if you are using UITableViewStylePlain.
Be sure to attenuate the frame of the webview to allow for any cells underneath to be visible or else the user will not be able to scroll the tableview as any touches will be intercepted by the webview.
This still goes against the UIWebView documentation (stated above) but, in practice, this implementation actually works fine as long as the webview does not cover the entire scrollable region of the view.
Here's a screenshot of the test app I made:
Hope that helps :)
There is a better way to do this.
From iOS 5.0 onwards, apple expose the UIScrollView present inside the UIWebView. So to resize the webview based on the contents, here is what you do.
Make the parent of UIWebView the delegate to that UIWebView.
Implement the webViewDidFinishLoad: and in that function just do this.
CGSize sz = [webView.scrollView contentSize];
CGRect rect = webView.frame;
rect.size.height = sz.height;
webView.frame = rect;
Even if there are multiple load start and finish, it does not matter since eventually we will have the web view resized to fit the contents.
In case you don't want the user to see the dynamic resizing, you can just set the alpha of webview to 0 and when everything loads and you are done with resizing, you can transition it to alpha 1 with animation.

NSWindow: alternative to -setOpaque:NO

I want to have a window which is like QuickTime X window. An all opaque window with rounded corners.
I've obtained it implementing a custom borderless NSWindow with:
[window setOpaque:NO];
[window setBackgroundColor: [NSColor clearColor]];
and a custom NSView with:
- (void)drawRect:(NSRect)rect
{
NSBezierPath* thePath = [NSBezierPath bezierPath];
[thePath appendBezierPathWithRoundedRect:rect xRadius:radius yRadius:radius];
[thePath fill];
}
It works as expected but the window becomes noticeably slow when it gets resized fast.
I've identified that this slowdown is given by -setOpaque:NO; if I remove that line, the window can be resized fast again but corners are obviously no more rounded.
Is there a way to avoid using -setOpaque:NO and still be able to have rounded corners? Maybe one can have a window which is all opaque except for the corners?
The view is a NSOpenGLView so I can leverage on OpenGL if it may helps.
See this Apple developer example: https://developer.apple.com/library/mac/#samplecode/RoundTransparentWindow/Introduction/Intro.html
In Quartz/Core Graphics, opaque rects are faster to composite than non-opaque rects.
But an opaque window means you need to draw a rectangle and anything you didn't fill would be black.
If you want a custom window that is not a sharp-edged rectangle, you must set the window to be non-opaque.
Anyway, this is almost certainly, not your main bottleneck.
First thing is to stop doing so much stuff in drawRect:
Make that NSBezierPath a property.
Only replace it when the rect is actually changing size.
Only do that in viewWillDraw: or some earlier point.
Maybe one of the view or window resize NSNotifications or a delegate method.
In drawRect: you should do only drawing really, as much as possible.
You should only redraw what you need to, as much as possible.
This is still small, and probably not your bottleneck.
You'll need to examine the drawing in ALL of the views in your window.
Your window is really the root CGContext (drawing context) that you get access to on OS X. Everything in your context is all of your subviews.
Every subview is a potential drawing bottleneck.
An OpenGL view drawing during live resize of the window sounds like a prime candidate.
You might throttle frame rates or something during live resize of the view or the window.
That should get it a little snappier.
Beyond that, you'll notice from NSWindow and NSView classes that not drawing during live resize IS a performance win.
See the NSView Class documentation and specifically the methods noted under the section Managing Live Resize
inLiveResize
preservesContentDuringLiveResize
getRectsExposedDuringLiveResize:count:
rectPreservedDuringLiveResize
viewWillStartLiveResize
viewDidEndLiveResize
Those last two look like a great place to sandwich some reduction in drawing,
Try using the setAlphaValue method of NSWindow.