I am developing an application in which i am creating small sub views in the same view.
What i want is when i change the value of alpha of the view, the value of alpha for sub view is also getting changed which i do not want.
How to implement the code for changing the value of the view not the small sub views created.
Thanks,
You cannot do that, the alpha is inheritate, so what you have to do is to change the view structure from
YourMainView -> Your SubView
To
ContainerView ->YourMainView
-> Your SubView
So now YourMain View the one that you want to apply the animation, is not the paret view of your current subView, the both views are sibilings, also ContainerView will have a clear background, so it wont affect it will just contain both the views
As suggested already, you should not add YourSubVew as subview of YourMainView.
Make both of your views a subview of an empty and transparent common subview (ContainerView) which has the same size and position that YourMainView currently has.
ContainerView -> YourMainView
-> YourSubView
Make sure to add YourMainView first as subview of ContainerView before you add YourSubView as subview of ContainterView. Otherwise YourMainView may overlap/hide YourSubView.
Doing so you can set both views' alpha independend from each other.
(Omar's answer is quite correct, but his "graphical visualisation" is misleading and it missed the point of the sequence of the subviews.)
Edit:
What you have today is like this:
yourMainView.alpha = 1.0;
...
[yourMainView addSubView:yourSubView];
yourMainView.alpha = 0.1; //probably with animations etc.
What happens is, that yourSubView will "inherit" the alphaValue of its superview.
ANd there is even more to that. Assuming that your subView has an alpha of 0.5, that would effectively become 0.05 when when its superview's alpha is set to 0.1.
Change that code to:
containerView = [[UIView alloc] init]; //you may choose a different init method
//If you use initWithFrame then use the frame of yourMainView.
//However, make sure that ContainterView is of the same size as yourMainView and has the same position.
[containerView addSubView:yourMainView];
yourMainView.alpha = 1.0;
...
[containerView addSubView:yourSubView]; //add it to the container too!
yourMainView.alpha = 0.1; //this will now effect the MainView only.
That is basically all the trick. Views can perfectly well overlap each other without being subviews. Make them subviews only then when they really are subveiws, when they are moved togehter, appear and disappear together, etc.
Related
I am probably doing something extremely stupid but I cannot figure out why this does not work.
I am trying to perform a simple UIView block animation but have run into trouble. I have recreated in a test project.
I have a view on a View controller, when I press the button, I create a new view and set its frame to be out of the current view (above it). I want to animate the transition so that the view currently on the screen moves downwards out of the view as the new one above it comes down to take its place.
Here is the code which is hooked up to the button,
the original view is hooked up as self.view1
- (IBAction)buttonPressed:(id)sender {
UIView *view2 = [[UIView alloc] init];
view2.backgroundColor = [UIColor blueColor];
float offScreenY = 0 - self.view1.frame.size.height;
CGRect offScreenRect = CGRectMake(0, offScreenY, self.view1.frame.size.width, self.view1.frame.size.height);
view2.frame = offScreenRect;
[self.view addSubview:view2];
float oldY = self.view1.frame.origin.y + self.view1.frame.size.height;
CGRect oldRect = CGRectMake(0, oldY, self.view1.frame.size.width, self.view1.frame.size.height);
[UIView animateWithDuration:0.5 animations:^{
self.view1.frame = oldRect;
view2.frame = CGRectMake(0, 0, self.view1.frame.size.width, self.view1.frame.size.height);
}];
}
This just animates view2 down and does not animate view 1.
If I do not add view 2 as a subview and only put view1's frame change in the animation block then view1 animates correctly.
BUT they will not work together!
Why is this?
This is a classic symptom of having autolayout turned on. If you animate frame, it works, but as soon autolayout reapplies the constraints on the view, view1 will return to its original location. By adding view2, iOS automatically reapplies autolayout constraints immediately and your view1 therefore won't move.
Bottom line, don't use autolayout and try to animate frame properties directly. Two solutions:
The easy solution is to turn off autolayout. Go to IB, select the "File inspector" and uncheck the "Use Autolayout" button:
If you want to keep autolayout on, you shouldn't be animating by changing the frame properties directly. You would animate by change the layout constraint constants. This has been answered elsewhere on S.O., but if you need guidance on that approach, let me know.
The basic idea, though, is to create an IBOutlet for your top constraint for view1 called, say, view1TopConstraint, and then in your animation block you can say
self.view1TopConstraint.constant += self.view1.frame.size.height;
[self.view layoutIfNeeded];
For this to work, though, you'd have to be careful about your other constraints on view1 (e.g., have a height constraint, have no bottom constraint or if you have one, lower its priority, etc.). This can be a hassle the first time you do it, but you'll quickly get the hang of animating by changing constraints.
But, then again, if you're using constraints, you probably shouldn't be defining view2 by its frame, but probably defining constraints for that, too.
In this case it is better for you to have a container view.
Add view1 and view2 inside this container accordingly. Container's some part will be in the screen and container's frame size will be double of the size of a view. Animate the container, so the other two views will be animated accordingly..
I've got a main view.
Inside main view are two container views: buttons container and display container.
Inside each of those containers are buttons and display fields, respectively.
So in short, I've got three levels of views: main, sub (containers), and sub-sub (buttons and fields).
When a button is pressed, I want to animate an image of that button from the button area to the display area. That is, I need to move it two levels up, then two levels back down.
Currently, I'm creating a UIImage, identical to the custom button's UIImage, on top of the button. I move it, then destroy it at the end of the animation, so I don't have to alter the actual button (which I want to stay in place so I can re-use it).
Obviously I can get this UIImageView's center/bounds/frame.
However, I'm having trouble determining the coordinates for the destination. Frame and Center are relative to the superview, but that's just one level up. Seems like there's a lot of math do to in order to add up the correct X and Y offsets to get to the destination.
Is this a job for UIView's convertRect:toView: or convertRect:fromView: ? I'm having a hard time determining just how to use those, or deciding whether they're actually the right methods to use.
Seems like a common enough problem - moving something from one "nested" view to another "nested" view - but I've searched and can't find the answer.
Those convertRect methods are tough to get the hang of. Your view contains two sub views subA and subB, and subA contains a button, and you'd like to animate the button moving from subA to subB. Let's do the animation in the view controller that has the main view....
// subA is the receiver. that's the coordinate system we care about to start
CGRect startFrame = [subA convertRect:myButton.frame toView:self.view];
// this is the frame in terms of subB, where we want the button to land
CGRect endFrameLocal = CGRectMake(10,10,70,30);
// convert it, just like the start frame
CGRect endFrame = [subB convertRect:endFrameLocal toView:self.view];
// this places the button in the identical location as a subview of the main view
// changing the button's parent implicitly removes it from subA
myButton.frame = startFrame;
[self.view addSubview:myButton];
// now we can animate in the view controller's view coordinates
[UIView animateWithDuration:1.0 animations:^{
myButton.frame = endFrame; // this frame in terms of self.view
} completion^(BOOL finished) {
myButton.frame = endFrameLocal; // this frame in terms of subB
[subB addSubview:myButton];
}];
I have added a subview over my UITableView using:
TransparentViewController *tvc =
[[TransparentViewController alloc]
initWithNibName:#"TransparentViewController" bundle:nil];
[self.view addSubview:tvc.view];
My Nib has a UIImageView in it that has some text and a transparent background.
When I load the detailView for the table for the first time I show the subview that gives a brief explanation of the information that you can see below the text. Works really well.
What i would like to do is alter the alpha of the underlying table so that it is dimmer but not affect the alpha of the overlay subview. If i use:
[self.view setAlpha:(CGFloat)];
It dims the overlay as well. I seem to be having a mental block.
Changing the alpha affects the subviews as well. Your tvc.view is a subview of self.view, so it is naturally going to be affected.
Why don't you try this: put another view in tvc.view and send this view to this view to the back.
(UIView*) back = [[UIView alloc] initWithFrame:CGFrameMake(...)];
back.backgroundColor = [UIColor grayColor]; // choose a color that you like;
back.alpha = 0.5; // whatever works for you
[tvc.view addSubview:back];
[tvc.view sendSubviewToBack:back];
Set the size and alpha of this new view to something you like. The table view will show through it to a limited extent, which may accomplish what you are trying to do.
Since this is part of our tvc view, it will appear when you show that view and go away when you hide that view.
EDIT - I've worked out what I was originally doing wrong. I was changing the size of the UIScrollView, instead of the pattern subview. I have fixed that, but amended my question with the new problem this has thrown up.
I am making a notes section in my app with a lined-paper effect. The lines are on a separate UIScrollView which responds to scrollViewDidScroll: so the lines and text always move together. My lines are set up like this in viewWillAppear:
CGRect noteLinesRect = CGRectMake(self.view.bounds.origin.x,
self.view.bounds.origin.y,
self.view.bounds.size.width,
noteTextView.contentSize.height+self.view.bounds.size.height);
UIScrollView *anoteXLinesView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
self.noteXLinesView = anoteXLinesView;
[anoteXLinesView release];
LinePatternView *linesPattern = [[LinePatternView alloc] initWithFrame:noteLinesRect];
self.linesPatternView = linesPattern; [linesPattern release];
[self.noteXLinesView addSubview:self.linesPatternView];
[linesPattern release];
CGPoint newOffset = CGPointMake(self.noteTextView.contentOffset.x, noteTextView.contentOffset.y - NOTE_LINES_OFFSET);
self.noteXLinesView.contentOffset = newOffset;
[self.view insertSubview:self.noteXLinesView atIndex:0];
This works fine when the user first looks at a stored note - all the text is nicely underlined. But when they write more text, eventually they get to the bottom of the lines I created in viewWillAppear and are writing on 'blank paper'. So I need my lined-paper pattern to dynamically get bigger and smaller so it is always a bit bigger than the contentSize of my textView. I am trying to do that like this:
-(void)textViewDidChange:(UITextView *)textView
{
self.linesPatternView.frame = CGRectMake( self.linesPatternView.frame.origin.x, //-self.noteTextView.contentOffset.y+NOTE_LINES_OFFSET,
self.linesPatternView.frame.origin.y,
self.linesPatternView.frame.size.width,
noteTextView.contentSize.height+self.view.bounds.size.height );
}
The problem is, although the lined-paper pattern does increase in size, it doesn't add new lines at the bottom. Instead, the pattern stretches out and gets bigger as the view gets bigger. What am I doing wrong?
One of the solutions is to make 3 views, each containing the lines of the size of your scrollview frame on screen. You position the three one underneath the other in the scrollview and monitor the scrollview through its delegate.
When scrolling down you check:
As soon as the topmost one goes offscreen for more than Y pixels you remove it from the scrollview and insert it underneath the bottom one.
When scrolling up you check:
As soon as the bottommost one goes offscreen for more than Y pixels you remove it from the scrollview and insert it above the top one.
Is there a reason you’re not simply using a tiled pattern as your background view’s backgroundColor? UIColor’s +colorWithPatternImage: will let you set a background that’ll tile indefinitely and won’t stretch as your view resizes. If part of the background has to be different—like the top of your paper, for instance—you can just place an image view containing that at the top of your background view.
Fixed! In addition to the changes outlined in my edit to the question above, I just needed to call [self.linesPatternView setNeedsDisplay]; after the resize.
I have a view hierarchy like this:
UIView
- ADBannerView
- UIImageView
- UILabel
- UIButton
- UINavigationController
- UIView
I'm loading the image view, label and button from a nib file and the UINavigationController from another nib. All have autoresizing masks set. I'm creating the ADBannerView programmatically.
Now my problem is that I would like the image, label, button to move down and the navigation controller to shrink when I insert an ADBannerView. However this is not happening, instead the ADBannerView is placed on top of the image and the label.
Can anybody explain to me what am I doing wrong here?
In other to get those things to "automatically" shift down when you put in the ADBannerView, you'll need to enclose them in their own view and then change the size and position of that view. Assuming the ADBannerView is 50 pixels tall, you'll want to move that UIView down 50 pixels and reduce its height by 50 pixels.
Assuming that self.enclosingView is the new view that you will use to enclose the image, label and button... and assuming you want to make this animated (you probably do, it usually looks a lot better):
// Start the AdBannerView off of the top of the screen
CGRect adFrame = self.bannerView.frame;
adFrame.origin.x = 0.0;
adFrame.origin.y = 0.0 - adFrame.size.height;
self.bannerView.frame = adFrame;
[UIView beginAnimations:#"Show Ads" context:nil];
// Animate the shrinking of the enclosing view
CGRect enclosingFrame = self.enclosingView.frame;
enclosingFrame.size.height -= self.bannerView.frame.size.height;
enclosingFrame.origin.y += self.bannerView.frame.size.height;
self.enclosingView.frame = enclosingFrame;
// Animate the motion of the bannerView into view
adFrame.origin.y = 0.0;
self.bannerView.frame = adFrame;
[UIView commitAnimations];
Autoresizing mask defines size changes on parent's frame changes, not on sibling insertion/removal. You have to adjust frame for corresponding views programmatically. Kenny Wyland already gave you idea how this can be achieved with less pain. Take a look at CGRectDivide method - with it it's easy to split available space between two views.