iPhone: Replacing UIView with itself (resetting view) - iphone

I have a UIView that represents a game screen. I have a reset button allowing users to replay that level. For the reset though I want to reset ALL UI controls to their default state as upon completion various animations take place that fade in/out text and move around images etc.
What I would like to do is replace the existing UIView with another copy of itself (with animation). How can I do this whilst not breaking the UINavigation stack? When a user presses back on the new screen I want them to goto the original parent UIView and not the game screen that was replaced.

I do something similar using a mask view.
Create a mask view, a UIView set as your starting view (or just an image).
Animate a transition from your game view to your mask view.
Reset your game view.
Remove your mask view, showing your game view.
Doing so your UINavigation stack won't be broken, because you actually use just one active view (game view) and a static mask to cover your view for transition.

On the top of your controller stack you presumably have controller that "owns the game view"?
I also assume that you are using a custom view within your controller to do most of the view stuff.
If this is the case, then you should be able to alloc, init another instance of your game view which will be in default state. Set it's alpha to 0.0f and add it to the view hierarchy, then animate its alpha to 1.0f and in the animation completion block remove and release th sold view that you no longer need.
Alternatively you could define the start condition, positions, values etc. and then just animate back to them when the button is pressed.
Hope this helps :)

I assume you have code to initialize all of you subviews and game-related data members right?
move that code to a separate method and have the reset button call the method.
I usually have a -setupSubviews method on each custom view i create and i call it each time i need to reset my view to its original state, for example:
- (void)setupSubviews
{
_titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
[self addSubview:_titleLabel];
_activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectZero];
_activityIndicator.hidesWhenStopped = YES;
[self addSubview:_activityIndicator];
_loading = NO;
}

Related

Hiding or Removing UIImageView and arrangement (IOS 5)

I have a UIViewController that I designed in Interface Builder. near the top of the View it has a UIImageView and then some other Views (Text etc) below. These are set to anchor to the top of the view.
In code when the view loads I remove the UIImageView in certain circumstances but it still seems to take space or the view's below don't spring up to the top based on their Anchor.
How can I make the Views below move up if the View above is removed?
You can change the frame of the other elements in the view.
in the viewDidLoad method you can use something like that:
-(void)viewDidLoad{
if(imageVisible){
otherElements.frame = CGRectMake(....);
}else{
otherElements.frame = CGRectMake(....);
}
}
I don't know what is the structure of the view, but you might consider nesting all of the other elements in one view so you could change all the elements positions in one command.
Unlike the Android view hierarchies, iOS view hierarchies are all developed in absolute coordinates. When you say a subview is anchored to the top, that means that if the size of the parent view changes, your view will stay in the same relative position to the top of the screen.
In order to make your views below the image view move up when the image is hidden or removed, you will have to manually arrange them yourself to account for the offset

iPhone Fall Down button (Animation)

Is it possible do something like this ?
When I click on the button I need the following animation: button to set some alpha filter and starts to fall down as indicated by the arrow, it will disappear on tab.
Can you tell me how to do this ? Thanks a lot ...
Here is image url: http://img534.imageshack.us/img534/8149/screenqx.jpg
It's definitely possible, but there are some issues you have to overcome. One is that UIBarButtonItem isn't a UIView. One way is to loop through the subviews of the UIToolbar or UINavigationBar. Another way is to figure out the position of the button. Another is to get the view using private api if you're not submitting to the AppStore.
Once you have the view, you can move it to the superview of the UIToolbar or UINavigationBar or you can create a view on top of that (and hide the real UIBarButtonItem since you're done with that). The latter is more difficult because mimicking the look of the default bordered UIBarButtonItem isn't easy.
Now you need to get the center of the UITabBarItem somehow. You can either use private api or you can loop through the subviews.
Create a CGPath using Quartz functions or using UIBezierPath. The start point will be the center of the button and the end point will be the center of the UITabBarItem.
Create a CAKeyFrameAnimation and attach said CGPath.
Create a CABasicAnimation to animate the opacity.
Add both to a CAAnimationGroup.
Attach the animation group to your button view's CALayer.
Make sure to also set the position and the alpha in order to prevent the view from jumping back to its original position after the animation.
Once you attach the animation group, the animation should start, so make sure you're doing all of this in the button's selector method.
You can't really move it from view to view, as your views could clip and then you'd get frames with only a partial image. Probably the best thing to do is to create a view on the fly which covers the whole screen, copy the button image into the view at the original point, remove the button from the original view, then animate that image to where you want it to go, then add the button to the final destination.

Drag UIView without disabling its child controls iPhone/iPad

I have a UIView control (white rectangle in image)
Moreover I am able to drag that control...
And when I press the button I load a subview which is another nib that I created and I placed random controls in it to illustrate my point...
If you guys are interested in finding out how I placed that nib file in that UIView control take a look at this question. I don't thing you have to read it in order to understand my question.
Anyways the problem when loading that nib file is that I can no longer drag the top UIView. Because of this I changed:
for:
in the UIView of the subview. In otherwords the UIView of the nib file that I am placing in the UIView that has the white background.
and when I did that I was able to drag the control but the controls inside the subview no longer works. I have also tried placing the touchesMoved method in the subview instead but when I do that the application behaves strange. Plus the purpose of placing the nib file in a UIView control was to avoid repeating the same drag funcionality on several nib files.
I actually need to create an application like a power point presentation and I need to change the slide as the user slides the UIView and if it's cords are less than x for example then I load the next slide (nib file) in that uiview controller. Maybe there is a simpler way of doing what I need but if I get this drag to work I am done cause I would just have to do that functionality just once.
You should leave the UserInteractionEnabled flag on for your subview if you want it to respond to events.
One way to achieve this would be to do your dragging using a UIGestureRecognizer.
UIPanGestureRecognizer is perfect for this (UIGestureRecognizer at apple)
Basically you'd attach the gesturerecognizer to the view which you want to pan then adjust it's position in the callbacks it provides.
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc]
initWithTarget:self action:#selector(handlePanGesture:)];
panGesture.minimumNumberOfTouches = 1;
[draggableSubview addGestureRecognizer:panGesture];
[panGesture release];
Then in the handlePanGesture method you figure out how far the user panned using the translationInView method of the recognizer which it gets passed and translate the subview accordingly.

Anchor a UIView

I have a UITableViewController inside of a UINavigationController.
I want to have a UIView appear over the top of the table view but not susceptible to the scrolling of the table view.
I.e. if the table view is scrolled, the UIView should remain in the same position relative to the screen, rather than relative to the table view. It should appear anchored in a certain position.
What is the best way to achieve this?
EDIT: To clarify, the view should float transparently over the top of the table view.
Many thanks!
I also wanted to have a floating UIView over my tableView.
So, within my RootViewController (which is a UITableViewController), this worked for me
- (void)viewDidLoad {
/* mylabel is a UILabel set in this class */
[self.mylabel setUserInteractionEnabled:NO];
/* navigationController comes from higher up in the navigation chain */
[self.navigationController.view addSubview:self.mylabel];
}
Similar to what Peter said, create a UIView that will contain both the TableView and the subclassed UIView. Such as:
UIView *view = [[UIView alloc] initWithFrame:frame]; // Define frame as you like
[view addSubview:myTableView]; // This is the reference to your tableView
[view addSubview:myAnchoredView]; // This is the reference to your UIView "floating" subclass
You will also need to turn off user interaction for your floating view. I don't know if this will specifically pass the touches to the underlying UIView's or not though:
[myAnchoredView setUserInteractionEnabled:NO];
If this is blocking touches to your tableView, you may need to pass the reference to your tableView to the anchored view at initialization, then pass the touch events along. You can do this by overriding the touch response methods in UIResponder. (If there is a better way, someone please speak up.)
Do you mean the anchored view should appear transparent over the UITableView, or just above, i.e. anchored view uses top 20% of the available space, table view uses the rest?
In any case, create a UIView containing the anchored view and the table view. If you want the anchored view transparent over the table view, it's a bit tricky, because to scroll the table view, touches have to pass through the anchored view.
Add the surrounding view's view controller to the navigation controller instead of just the tableview.
I investigated how UIScrollView keeps its scrollIndicator above the UIScrollView's content and yet unmoving by examining a UIScrollView in the debugger.
The scrollIndicators are UIImageViews. And you can see they are direct descendants of the UIScrollView itself. You can also see that any scrolled content is also a direct descendent. So how is it that the scroll indicators don't move?
I tried updating the position of my static content constantly in - (void)scrollViewDidScroll:(UIScrollView *)scrollView this, surprisingly, works. I'm not sure if it is how UIScrollView itself does it, but without some private magic, it must be something like this.

Difference between directly setting a controller's view and adding view as a subview

I have just started learning objective-C and the iphone sdk and I have a question that I hope someone can help shed some light on.
What is the difference in the following:
self.view = someView;
and
[self.view addSubView: someView];
Say for example, in a simple app, where we have only one controller and one container view (has a few image subviews).
What is the difference between the two statements? The reason that I'm asking is because I was tinkering around in some sample code and I noticed the view was being initialized with images as subviews like so:
if (self = [super initWithFrame:CGRectZero])
{
//adds some images as subviews here
}
As I understand it the initWithFrame: CGRectZero, creates a frame with size at [0,0,0,0] (essentially invisible).
When I directly set the view with
self.view = someView;
I notice the view actually displays the image. But when I add the view to as a subview of controller's 'default' view, it doesn't. So basically my question is, whats going on behind the scenes? Why is the first method "resizing" the frame and the second one not doing the same thing.
What you see on the screen of your iPhone is almost always a hierarchy of views.
When you look at, say, your inbox in Mail, you're seeing a bunch of views. There's a big containing view.[1] Within that, there's a navigation bar view, a table view, and a toolbar view. Within the navigation bar view, there's a button view on each side and a label view in the middle. Inside the table view, there are a bunch of table cell views, and each of those cells has several label views. The toolbar has five button views. I could go further and talk about the views inside those buttons and so on, but I'm sure you get the idea.
The view above any given view is its superview; the views below it are its subviews. So a table cell view has a table view as its superview and a bunch of label views as its subviews. The top view, the one that has all the other views inside it, is called the root view.
Each view has its own drawing surface. The rectangle formed by that drawing surface is called the frame. The frame of a view is relative to the frame of its containing view. So if one of our table cell's label subviews has its frame at (0,0), that means it will be in the table cell's top left corner, even if the cell is halfway down the screen.
When you're writing a view controller, self.view is that root view I mentioned earlier; all the other views are subviews of that one (or subviews of its subviews, etc.). One of the features of a view controller is that it automatically resizes its self.view to fit the screen. (The available area will be smaller in the middle of a phone call: the status bar is twice as high then, so there's less space for your app. It will also be smaller if your view controller is being managed by a navigation controller or tab bar controller, but that's a different story.) But just because you resize its root view doesn't mean that the root view's subviews will automatically resize. To do that, you need to set their autoresizing mask (a property which tells the view how it should react when its superview changes size):
someView.autoresizingMask = UIViewAutoresizingFlexibleWidth
| UIViewAutoresizingFlexibleHeight;
(There's a graphical way to set up the autoresizing mask in Interface Builder—click the ruler icon in the inspector window and look at the "Autosizing" section.)
Even that's not enough, though, if someView isn't the right size to start with. To do that, adjust its frame before you add it as a subview of self.view:
someView.frame = CGRectMake(
0, // all the way to the left
0, // all the way at the top
self.view.frame.size.width, // same width as the root view
self.view.frame.size.height, // same height too
);
So why would you ever use subviews if you have to do all this twiddling that the root view does for you? Simple: you can only have one root view, but one view is almost never enough for what you need to do. If you really need only one view, of course, you can just set it as the root view and go on your merry way, but chances are, things are more complicated than that.
[1] I'm simplifying a bit here, but that's fine for right now.
When you add a view as a subview, you need to make sure that you're actually adding to an existing view.
self.view = view sets the controller's view. Without this (either in code or done with a XIB) you'll never see anything as the controller has no view to show.
[self.view addSubView: someView] assumes that self.view is already set. If it doesn't, you're adding someview as a subview of nil, and it will never get seen.
Basically, think of self.view as the big container, and all the subviews are just pieces inside of it. If you don't need any subviews, setting self.view to a UIImageView or UIWebView is fine. If you do need subviews, you'll need a big, empty container view in which to put them.
In your case, I'm betting self.view is never set, and you're adding your image views to nil.
Setting the view controller "view" property only changes the view it is managing.
Adding a view as a subview of another view, actually adds the subview underneath the other view.
They are very different things, as one adjusts a view controller and the other alters a view hierarchy.
As a guess, the reason you didn't see anything the first way was the frame for the subview you were adding was CGRectZero (0 in size).