I have a view that is being shown within a larger view and will always remain in the same place. When some user input is provided, a second view will appear below the first one. want this to be a somewhat smooth transition so what I've done is place the second view directly behind the first one, then started a timer that check if the views overlap using their intersection, if they do, the second view is slightly lowered, and overlapping is checked again, until the views no longer overlap, and the timer stops.
I want the transition to seem like the second view was behind the first one and is now being slid out from underneath. For that reason I created an "imaginaryRect" that represents exactly where the second view (called progressBarView) would be, if it was being displayed entirely, and use that to check the intersection as I move imaginaryRect down. But I then make the rectangle below the intersection (which would be imaginaryRect minus the intersection height) the one that actually displays the second view, and that one's called newFrame.
This all works perfectly, except for how the second view is being animated. I want it to appear to slide out from under the top one, which would mean that as the view begins to appear below the top one, the user would first see the bottom part of the second view appear, as it slid further down he'd see the middle part, and finally the top finishes coming down and they are all visible. What is actually happening is that when the view starts appearing, it appears from the top down. First the top part appears, then middle, then bottom. It doesn't give the impression that it's being slid out from under the top one. In fact, it looks like isn't moving, and instead gives the impression that something that was on top of it covering it is being slid down.
I've been at this since the day before yesterday and I think the problem has to do with the origin of the frame. But that's it.
This is the code I'm using:
CGRect imaginaryRect = NSMakeRect(progressBarView.frame.origin.x,progressBarView.frame.origin.y, view.frame.size.width, view.frame.size.height);
CGRect rectIntersection = CGRectIntersection (view.frame,
imaginaryRect);
//if view and imaginary progress bar view frame intersect, the view is lowered
//the second condition prevents one drop too many at the end
if (!CGRectIsNull(rectIntersection) && (rectIntersection.size.height!=0)) {
CGRect offsetFrame = CGRectOffset (imaginaryRect, 0, -1);
imaginaryRect = offsetFrame;
//rectIntersection is recalculated after the offset, so it's height is subtracted for newFrame
rectIntersection = CGRectIntersection(view.frame, imaginaryRect);
//the rect below the area of intersection
CGRect newFrame = CGRectMake(imaginaryRect.origin.x, imaginaryRect.origin.y, view.frame.size.width, view.frame.size.height-rectIntersection.size.height);
//move the PBview to the new, slightly lowered frame (this is the frame that's located below the front view, but subtracts the intersection)
[progressBarView setFrame:newFrame];
Thanks for the help!
Related
How can you blur the whole view except a single table view cell?
The effect should be similar to the 3D touch blur effect. E.g. Mail app:
The effect of blur applies precisely to the whole screen but the selected cell in the case of the mail app.
If you only want the effect to apply to your table view, you could maybe put a blur visual view on tope of your each cell's content, and set its effect to nil
cell.blurView.effect = nil
appart when one cell is selected. To do that, play with the didSelectRow function and reload the data so that at the end you get the effect you want. (you can even animate the change with UIView.animate())
UIView.animate(withDuration: 0.5, animations: {
cell.blurView.effect = UIBlurEffect.init(style: .light)
}
The problem is that the solution I told you is not very power efficient, but I can think of another one:
Consider having two blur view that display no effect when no cell is selected, then you can as soon as the cell is selected, set the two blur view so that the first one takes the whole part of the screen at the TOP of your cell, and the other one covers the BOTTOM.
Ok last idea:
you could, in the didSelectRow method, add a blurView to the whole screen
UIApplication.shared.keyWindow?.addSubview(blurView)
and then add the cell on top of that and of course removing all this when the blur view is tapped for example
Hope it helps ;)
I'm currently making an OS X app with an NSScrollView. The scroll view's cells have a small "X" in them that allows me to remove them one at a time. However, whenever a cell is removed, the lower cells get pushed up to fill the space via a short animation. I'm wondering how to disable this animation so that the lower cells are instantly pushed up as soon as the cell is removed. Any help is appreciated!
Edit: The contents of the scroll view are maintained via an NSArrayController, so removing clicking the "x" sends a notification to an observing delegate which in turn calls:
-(void)alertRemoved:(NSNotification*)notification{
// Random code
...
[eventArrayController removeObject:alert];
}
I have a window into which I horizontally add two subviews. Into each subview, I place a variable number of subviews made up of a vertical slider, a text field rotated 90 degrees and placed to the left of the slider and another textfield, placed just under the slider. The slider subview's constraints are done in code, the parent views are both done in IB. When I add more slider views to the left window than the subview can handle in its default size, it resizes horizontally and forces the window's content view (and window) to also resize horizontally. Great, that's just what I want. But if I add more slider subviews than can fit in the right subview, they just get squeezed together and the subview does not expand as the left. I layout the slider views using code with this category converted to support NSViews, instead of UIVews:
UIView+AutoLayout1: https://github.com/jrturton/UIView-Autolayout
The constraints for the left and right subviews are more or less the same. I can't figure out why the right view does not resize as the left view does.
Here is a link to a sample project that demonstrates the problem:
SliderTest
Some someone help me out with this?
Also, a secondary question as I think my slider view could use a little work:
When a view is rotated using setFrame(Center)Rotation, do the top, right, bottom and top edges remain along the same edges or do they reflect the new orientation of the rotated view?
Thanks
I found the problem. The constraint between the left view and right edge of the window was fixed at 233 instead of >= 233. I had this at some point in the past, as I was adjusting the constraints to achieve the desired behavior and just overlooked this one through the troubleshooting process.
I have a drag n drop kind of app. Where you can select images and drag them anywhere on the screen!
The problem I'm running into is, when you move to another view, all the images reset to the center, when I return back.
For example if I press a button to take me to screen 2, all the "dragged" images I just did, will move back to the center.
This only happens when I have AUTOLAYOUT enabled :(
I have all my images start out in the center, so I'm guessing its something with autolayout...
Any ideas ?!
Here's an example of my drag image code.
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {
CGPoint translation = [recognizer translationInView:self.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
}
Your drag and drop code is manually configuring the layout by mutating the view.center property.
Once auto layout is enabled, auto layout takes responsibility for setting up the layout, so it takes exclusive responsibility for setting view.center, view.bounds, and view.frame (which is actually just calculated from center and bounds).
So once auto layout is enabled, although you can still set view.center manually, auto layout will clobber whatever you do the next time it calculates the layout that satisfies the constraints you have in place.
So how do you update your code to work with auto layout? If you want to use auto layout, what you need to do is modify your handlePan: method so that instead of modifying view.center it modifies whichever auto layout constraint is being used to calculate view.center. The details of this will depend on your constraint configuration. But if we assume, for example, that there is an NSLayoutContraint topSpaceConstraint that sets the view's top space to the superview, and another NSLayoutConstraint leftSpaceConstraint that sets the view's left space to the superview, then you could produce the same effect as
view.center = CGPointMake(view.center.x + translation.x,
view.center.y+ translation.y);
by instead doing something like
topSpaceConstraint.constant = topSpaceConstraint.constant + translation.y;
leftSpaceConstraint.constant = leftSpaceConstraint.consant + translation.x;
[view setNeedsLayout];
[view layoutIfNeeded];
The first two lines update the constraints. The last two lines cause the auto layout system to recalculate the resulting frame and apply it right away, rather than waiting until the next turn of the run loop.
Alternatively, you might be able to get away with updating the frame manually when you get UIGestureRecognizerChanged events, and then making the result "permanent" by updating the constraints as shown above only once you get UIGestureRecognizerEnded event. That would be more performant, since during the many UIGestureRecognizerChanged events you'd be updating the frame directly rather than relying on the auto layout system to do it.
I am working on iPhone application. I am having a MemoryViewController page on which I have to display questions to the user for a particular time period. I have to reload same view with new question again and again. Here I have to apply view animation in the form of right to left move. and the new view will contain new question.
Have I to take 2 different views on the same parent view? or it can be implemented with same view.
Any code help, please.
Thanks.
I would make them in two different views, so you would end up with something like:
newQuestionView.frame=CGRectMake(360.0,0.0,newQuestionView.frame.size.width,newQuestionView.frame.size.height);
[UIView animateWithDuration:1
animations:^{
oldQuestion.frame=CGRectMake(-360.0, 0.0, oldQuestion.frame.size.width, oldQuestion.frame.size.height);
newQuestionView.frame=CGRectMake(0.0, 0.0, newQuestionView.frame.size.width, newQuestionView.frame.size.height);
}];
What will happen is:
You first position the new question in the right side of the screen, so you can see it coming from the right. Then, inside the animation, you will put the old question in x=-360 and the new on in x=0, this way you will have the effect you want. In the animateWithDuration:1, you can change the 1 to whatever time you want the animation to last.