iOS - Positioning UIViews - iphone

I have a UIView and in interface builder I have set it's location to 160, 57.
I at some point during the apps life cycle, the UIView may move, and so I have a button to put it back to where it was before. So I use the following code:
[self.myView setCenter:CGPointMake(160, 57)];
However, when the UIView moves back, it's not in exactly the same place as it was when the app first loaded. It's a tiny tiny bit to one side.
Any idea why this is? Thanks in advance.

Try setting the view's location using view.bounds.origin instead of view.center.

I have solved my problem by using:
[self.myView setCenter:CGPointMake(159.5, 57)];
I didn't realise CGPointMake would accept floating point values so I thought I had to use 159 (too little) or 160 (too much). 159.5 was just right though.
It still doesn't explain why 160 works in Interface builder but I can just set this value when the view loads anyway.
Thanks for everyone's answers.

Related

CATransform 3D with a modified .m34 breaks view hierarchy/ordering in iOS6, but not the view it was applied to

Foreword, this isn't me losing a view off screen because I did the transform wrong, it's weirder.
Problem is, if I use an .m34 transform to achieve the perspective I need, the view hierarchy breaks, but remove the transform and it draws everything correctly.
Here's an example.
I have a background image (subviewOne), a menu(subviewTwo), and an object on top of all of that which I apply the CATransform3D to (subviewThree).
Simple code:
CALayer *layer = subviewThree.layer;
CATransform3D perspectiveTransform = CATransform3DIdentity;
perspectiveTransform.m34 = -1.0 / 500;
layer.transform = perspectiveTransform;
Prior to applying this code, the view hierarchy was, and still is on iOS 5:
(bottom to top)
subviewOne->subviewTwo->subviewThree
After applying it, I end up with:
(bottom to top still)
subviewTwo->subviewOne->subviewThree
Now, subviewThree still has the perspective transform applied to it, and is in the correct spot, on top of everything else, same as on iOS5. However, the Menu/subviewTwo, is now hidden by the background image/subviewOne, and nothing I do will get it to be drawn on top of the subviewOne. No amount of insertSubviewAtIndex:, bringSubviewToFront, sendSubviewToBack, etc, will make the view draw correctly.
This is incredibly peculiar particularly because the views that are drawn out of order are NOT having any kind of CATransform3D applied to them.
I have verified this independently in two different apps and multiple devices 6 devices. iOS5 draws everything correctly, and if I remove those four lines, everything draws correctly, but nothing I've tried on iOS 6 stops the .m34 from breaking the view ordering. It's not always as simplistic as the example I've provided, but this is the most demonstrable case I have witnessed.
Has anyone else experienced this, solved this?
Edit: More info for comment.
Yeah, typo with the extra *.
Figure there's an Imageview, QuadCurve Menu, and Textview.
I was calling the method with the .m34 in the viewDidLoad, but swapped it to the viewDidAppear real quick to check for you.
Doesn't matter. Don't get me wrong, the subviews are listed in the correct order when you call
NSLog(#"%#", [self.view.subviews description]);
They just aren't drawn on screen correctly.
In desperation, I wrote some crazy weird code, and I discovered the following.
I can call the method that draws the menu on a 10 second delay,
[self performSelector:#selector(createQuadCurveMenu) withObject:nil afterDelay:10];
which ends in
[self.view addSubview:menu]
As well as a totally superfluous
[self.view bringSubviewToFront:menu]
and it's still drawn behind an imageView that is set as the lowest subview in the .xib.
I have verified this two ways. I can go into the .xib and set the imageView to hidden, and running again I can see the menu, now that the imageView isn't covering it. I can also just comment out the code that applies the .m34 transform to the textView, and the menu then again correctly appears on top of the imageView. Again, none of this happens on iOS5 and iOS4.
At this point, I'm starting to think that it's a bug inside iOS6 itself, and have been waiting for the NDA to expire so I can ask here if anyone else has experienced it.
Pretty sure this is an iOS 6 bug: I've blogged about it here: iOS 6 Rendering Bug: 3D-Rotation Causes Layers to Render Without Respect for View Hierarchy.
Good news: You can work around the bug by setting zPositions on the affected layers: set the zPositions in increasing order of the view hierarchy. So if I've understood correctly, you want:
subviewOne.layer.zPosition = 0;
subviewTwo.layer.zPosition = 1000;
subviewThree.layer.zPosition = 2000;
Check out the blog for more info, including a link to the Open Radar version of the bug I've logged with Apple.
Also, this might be considered a duplicate of this post: iOS 6 view hierarchy nightmare. It has the same bug source and solution, although the symptoms you both describe are different.

How do yo move a UIWebView offscreen?

How do you move a UIWebView offscreen?
Is that determined by the CGRect? Or some other property of UIView or UIWindow?
You can try:
[webView setFrame:CGRectMake(320.0f, 0.0f, 320.0f, 480.0f)];
or
[webView removeFromSuperview];
The first one just move it offscreen, you just cannot see it. The second one remove it from superview, maybe it still exist in memory, or maybe it'll removed when received memory warning.
UIWebView is a subclass of UIView (as are most visible objects in cocoa touch) which means you can use setBounds or setFrame in order to 'move' the view. If you use negative or large positive numbers the view will be moved offscreen.
Do remember that things offscreen also take up memory ;-)
Yes, you can do that. You could change the frame property of UIWebView to some coordinates which are off the screen.
You could do this but if you are done with the UIWebView & simply want to close it then this might not be the best solution as the memory allocated is still not released. First animate it off the screen then release it to free the memory. To release it do [YourWebView removeFromSuperview]; [YourWebView release]; YourWebView=nil;.
You can hide it by setting the hidden property to YES.
You can also move it off the screen with the frame, as you mentioned. A good place to start is CGRectMake(self.superview.frame.size.width,self.superview.frame.size.height,...) though it won't do well with rotations.
You can also set the alpha to 0, which is akin to making it hidden.
You can also send it the method removeFromSuperview.
There may be more ways.
Enjoy,
Damien

iOS - status bar randomly turns solid black

Developing an iPhone app.
I've got a really strange problem where, every once in a while, the status bar at the top of my app screen will turn solid black. Not like the black version of the status bar, but like a solid black rectangle with NO text/icons. It's very rare, but usually seems to occur after returning to the app via multi-tasking or from a locked device (the app has been running in the background). I've seen it occur on both 3GS and iPhone4. Here's a screenshot:
I can never reproduce it when trying, it just seems to eventually happen at some point (sometimes it will go for days without happening).
Once it does occur, the app seems to continue functioning fine, even with the status bar gone, except for when I do one specific action in the app which will cause everything to freeze up all the sudden (the app doesn't crash, but everything on screen is frozen and non-interactive). Without explaining the design in detail, the specific action that causes it to freeze up (after the bug appears) is performing a simple upload in the background to a SQL database. Resetting the app is the only way to fix the problem once the black status bar appears.
Anyone else ever experienced this? I can't find a single thread anywhere explaining similar behavior, and it's driving me nuts.
It happened once in my app when I called a drawing method in my custom subclass of UIView instance right before I added it as a subview to parent view.
The solution was apparently easy: add it as a subview first before sending/calling any custom drawing methods.
Examples:
CustomView *aView = [[CustomView alloc] init];
[aView drawSomething];
[self.view addSubview:aView]; //wrong approach
[aView release];
Should be:
CustomView *aView = [[CustomView alloc] init];
[self.view addSubview:aView];
[aView release];
[aView drawSomething];
The screenshot is missing, but what you describe sounds as though you've incorrectly implemented the use of Apple's built-in view controllers.
Both UINavigationController and UITabBarController will automagically shift all the content inside them down by 20-pixels, if they detect there is "supposed" to be a statusbar on screen at the moment.
My guess is that you have some code that is removing the statusbar, but which is kicking-in after the Apple code has already detected it and shifted everything down to accomodate.
The "fix" is to re-read the docs on Apple's classes very carefully and use them as Apple dictates (usually, people use them in ways that seem sensible - e.g. embedding them inside other views - but which Apple has expressly declared are unsupported. Sadly those classes from Apple are very fragile)
Are you holding a reference to a QLPreviewController instance? I was able to solve this problem in my app by creating a new autoreleased QLPreviewController whenever I need to display a file modally, as opposed to reusing the same instance over and over again.
I had a similar problem, which I described in this question here
If you have any, try removing any CGRect frame created by reference to:
[UIScreen mainScreen].applicationFrame]
and instead create the frame using a more manual definition. If that works, you can decide how to proceed from that point.

A view that is moving

I've no experience in making something move in my app. And I observed this effect in Flickit Pro. The Tap for details view will shake for one or two second and then stop. It looks cute and very user-friendly.
So how can I make effects like this? A gif that is moving? Or some other methods with the help of Cocoa Touch?
Thanks in advance.
Di
A high-level way would be [UIView beginAnimations: context:] (where both parameters can be NULL in this simple case). Then you can just change the properties that want to change of the view that should be animated, add some other "effects" like ease-in/out, etc. pp. When you are done with this, you just call [UIView commitAnimations] and it will animate everything for you.
However, in the case that you need more freedom, look into the CAAnimation class (its inside the QuartzCore framework).
Also: Look into the documentation for both ways (UIView / CAAnimation) and look into session 424 and 425 of the 2010 WWDC.
There are already some answers on stackoverflow on this:
Shake visual effect on iPhone (NOT shaking the device)
UIView shake animation
how to create iphone's wobbling icon effect?
and here is a link that does it on mac:
http://www.cimgf.com/2008/02/27/core-animation-tutorial-window-shake-effect/
I hope these are enough links to help.

UIScrollView works as expected but scrollRectToVisible: does nothing

I have used UIScrollView before, and am using it now, and never had a problem. I'm now adding it to an old app, and while it works as expected (I can look at the contents, scroll around with my finger, all the bounds and sizes are setup right so there is no empty space in the content, etc.), I just can't get scrollToRectVisible to work. I have even simplified the call so that it merely moves to the 0,0 position:
[scrollView scrollRectToVisible:CGRectMake(0, 0, 10, 10) animated:YES];
or move it to 0,200:
[scrollView scrollRectToVisible:CGRectMake(0, 200, 10, 10) animated:YES];
I even made a quick app to test this and I can get scrollRectToVisible to work there as I expect. But in my old app, I can't seem to make it do anything.
I can make the scrollView scroll with setContentOffset:, but that's not what I want.
This scrollView and its contents are defined in the nib by IB and used with an IBOutlet. The only code I am using in my app to handle the scrollView is
[scrollView setContentSize:CGSizeMake(scrollView.contentSize.width, imageView.frame.size.height)];
(I'm only interested in vertical scrolling not horizontal).
Has anyone run into a problem like this?
I have compared the scrollView attributes in both apps and they are identical.
ADDENDUM:
My scrollViews frame is: 0.000000 0.000000 480.000000 179.000000
My scrollViews contentSize is: 0.000000 324.000000
It still acts like the rect I want to scroll to is already visible and no scrolling is needed. Not sure if that is what is happening. This is just the darnest thing. Seems like such an easy thing to resolve...
ADDENDUM #2:
This is how I am making do without scrollRectToVisible:
CGPoint point = myRect.origin;
if (![clefScrollView pointInside:point withEvent:nil]) {
point.x = 0;
if (point.y > clefScrollView.contentSize.height - clefScrollView.bounds.size.height)
point.y = clefScrollView.contentSize.height - clefScrollView.bounds.size.height;
[clefScrollView setContentOffset:point animated: YES];
}
Everything else about this scrollView works as expected, but scrollRectToVisible. WHY?!? Any wild guesses?
Over a month later, and I finally figured it out. While the alternative above worked well, it has been bugging me and I had to finally figure it out. Turns out that it was somewhat of a stupid mistake.
Here's the old code in my viewDidLoad, where I set up the scrollView:
[clefScrollView setContentSize:CGSizeMake(clefScrollView.contentSize.width, clefView.frame.size.height)];
The value of a scrollView height or width can't be 0! I think this got past me because I was assuming that ScrollView sizes start out with a valid size, and I was missing the fact that one dimension was zero!
This works:
[clefScrollView setContentSize:CGSizeMake(clefView.frame.size.width, clefView.frame.size.height)];
Yeah, I have not had success with scrollRectToVisible:animated:, but setContentOffset:animated: always works for me. Out of curiosity, why do you not want to use setContentOffset:animated:? It seems to be the proper solution.
You might want to check and see that the scrollView's delaysContentTouches property is set to NO.
If you call the method scrollRectToVisible or setContentOffset from a touch within a subview of your scrollView then your scrollView could be holding things up by delaying touches.
So, make sure you set the following in your scrollView.
scrollView.delaysContentTouches = NO;
You will most likely be able to move the scrollView with and without animation set to YES.
i had it like this and it didn't work
scrollView.contentSize = CGSizeMake(scrollView.contentSize.width, someKnownValue);
i was just changing the height of the contentSize, so I didn't think that would give me any problem but it did ...
had to change it to this
scrollView.contentSize = CGSizeMake(someOtherKnownValue, someKnownValue);
turns out scrollView.contentSize.width is not necessarily set to a valid value from the get go, so better give it an specific value
The suggested solution above may still give an error if you haven't set the frame for the "clefScrollView".
If the solution above is used and still having the same problem, make sure you have initialized your scollView (in this case clefScrollView) frame prior to setting the content view.
clefScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0,0,320,450)];
[clefScrollView setContentSize:CGSizeMake(clefView.frame.size.width, clefView.frame.size.height)];
A little late to the game but I was having the same problem. Though I absolutely had my scrollview's content size set correctly - even excessively so for the height value. Even after extensive checks to validate the frames and content sizes - still wasn't working. I had to adjust the "bounds" frame height, then everything worked great.
I had the same symptoms as this issue..the scrollRectToVisible was not working as intended. My problem was that the scrollview on the storyboard had a ambiguous constraint problem. Once that was fixed the call worked just fine. It is something else to check when the scrollRectToVisible call isn't working as intended.
For me the problem was that a constraint in a subview was not explicit.
Check that every constraint in your content is set, even if you are not needing it apparently for the layout.