UIView Transition in table view - ios

I want to do transition of a view inside a table view cell. More precisely, when user clicks on a button in UITableViewCell a view should slide in from the right side of the cell and this view should slide back to its original position when user clicks on a button in the slided view. I could do all of this except the animation of sending the slided view back to its original position.
To accomplish this what I have done so far is, created a xib file for the table view cell which contains two views side by side, let it be view1 and view2. When the tableview is loaded to screen, only view1 is visible to the user. And set auto layout constraint for view1.trailingedge and view2.leadingedge as 0, the constraint is connected to cell.swift and named leftConstraint. Now when a button in view1 is clicked view2 slides in from the right side of the cell using the following code :-
self.view2.transform = CGAffineTransformMakeTranslation(UIScreen.mainScreen().bounds.width, 0)
UIView.animateWithDuration(0.4, animations: { () -> Void in
self.view2.transform = CGAffineTransformIdentity
self.leftConstraint.constant -= UIScreen.mainScreen().bounds.width
})
When tried to send back view2 to its old position (this should happen on the click of a button in view2) ie. right side of the cell animation is not working, all the elements in view2 just disappears. Using the following code for sending view to the right side of the cell:-
self.view2.transform = CGAffineTransformMakeTranslation(UIScreen.mainScreen().bounds.width, 0)
UIView.animateWithDuration(0.4, animations: { () -> Void in
self.view2.transform = CGAffineTransformIdentity
self.leftConstraint.constant += UIScreen.mainScreen().bounds.width
})
Thanks in Advance for any help. And special Thanks to #MarkHim for helping.

Since you need the transformation for the rightOut position twice, first for the in-animation and later for the out animation, you could save it in a variable like rightOutTransform. Try:
CGAffineTransform rightOutTransform = CGAffineTransformMakeTranslation(self.view.fame.size.width, 0);
// assuming view2 is currently in the cell
UIView.animateWithDuration(0.4, animations: {
self.view2.transform = rightOutTransform //
})
You might want to think about removing views you don't need anymore from the view hierarchy like this when the animation completed
view2.removeFromSuperview();

Related

How to animate a button to show a view to right and bounce to back when it is tapped

I want a button to expand the view to right when the button is tapped and bounce back when the view is tapped? can anyone suggest me?
Here is the screen shot for reference
Create a view that is the same size as the button behind the button, set the width of the view based on the right constraint and use the animation in the click response of the button, which should achieve the effect you want;
i think that you should use CoreGraphics, there is many simple tutorials you can find on youtube
Example
button.transform = CGAffineTransform(scaleX: 0, y: 0)
this method is what you are looking for in order to extend your custom view/button
Example like this: hope it helps.
let contraint:CGFloat = 0.0
if backViewWidthContraint.constant == 0 {
contraint = 300.0
}else{
contraint = 0.0
}
UIView.animate(withDuration: 3) {
self.backViewWidthContraint.constant = contraint
self.view.layoutIfNeeded()
}

How to create a segue to slide in and fade in at the same time (Xcode 9, Swift 4)

I'm trying to create a custom segue which slides in from the right and slides out (like the default Push segue) but also fades in/out as it slides in/out. I think I've figured out the fading code for transitioning to the destination view controller but can't figure out how to make the view slide in from the left and slide out to the right. I thought this would have something to do with the trailing and leading constraints of the view but I'm not really sure how to reference those constraints in my custom segue class. I know you can connect constraints to the code using IBOutlets for specific view controllers but I want to use this same custom segue class for custom segues across all my view controllers.
I was also wondering how to make the segue refer to the unwind segue class to go from the destination view controller to the source view controller. For example, when I click on the segue in the storyboard, in the "class" text field, I put the class name for the segue which transitions to the destination view controller but where would I do the same for the unwind segue so that when I click back, it also performs the custom segue to go back to the source view controller.
This is the code I've done so far for the segue which transitions to the destination view controller (haven't started on the unwind segue yet but I imagine it would be pretty much the same). Near the bottom of the class, I started trying out the anchor properties but they didn't work. Thanks!
class DimSegue: UIStoryboardSegue {
override func perform() {
// Get the view of the source
let sourceViewControllerView = self.source.view
// Get the view of the destination
let destinationViewControllerView = self.destination.view
let screenWidth = UIScreen.main.bounds.size.width
let screenHeight = UIScreen.main.bounds.size.height
// Make the destination view the size of the screen
destinationViewControllerView?.frame = CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight)
// Insert destination below the source
// Without this line the animation works but the transition is not smooth as it jumps from white to the new view controller
destinationViewControllerView?.alpha = 0;
sourceViewControllerView?.addSubview(destinationViewControllerView!);
let margins = destinationViewControllerView?.superview?.layoutMarginsGuide
// Animate the fade, remove the destination view on completion and present the full view controller
UIView.animate(withDuration: 1, delay: 0, options: .curveLinear, animations: {
destinationViewControllerView?.leadingAnchor.constraint(equalTo: (margins?.leadingAnchor)!, constant: 1000)
destinationViewControllerView?.trailingAnchor.constraint(equalTo: (margins?.trailingAnchor)!, constant: 1000)
destinationViewControllerView?.layoutIfNeeded()
destinationViewControllerView?.alpha = 1
}, completion: nil )
}
}

Animate NSLayoutConstraint & view simultaneously in separate blocks

I have two relatively simple animations. One is animating the top constraint of a UIButton so that it slides up. The other is animating the background color on a UIView.
self.buttonAnimationConstant.constant = 0
self.view.layoutIfNeeded() // ensure the constraint is at 0
self.buttonAnimationConstraint.constant = 100
UIView.animateWithDuration(0.25, delay: 0.0) {
self.view.layoutIfNeeded()
}
and my color animation:
UIView.animateWithDuration(0.25, delay: 0.0) {
self.colorView.backgroundColor = UIColor.purpleColor()
}
If I try executing them at the same time, then the button will animate up but it cancels the color animation, presumably because of view.layoutIfNeeded. Note that these two animations are in separate places so they can't be joined into one block (one sits at the view controller level, the other embedded inside a custom view but both within the same view controller). How can I animate both a constraint and a view property such that one doesn't cancel the other?
Essentially the issue is how do you go about animating both a constraint and a view that sit in the same view hierarchy?
Animation blocks do not cancel each other. The issue here is this line:
self.view.layoutIfNeeded() // ensure the constraint is at 0
Calling layoutIfNeeded outside an animation block will cancel your animations (because they set a new value for the values you animate) and there is not much you can do to prevent that. What you could do is making sure that no layoutIfNeeded is called outside an animation block while performing an animation. Of course this does not happen if the views are not in the same view hierarchy.

UIView is not showing except for a button action in swift

I have created a UI in storyboard which has top, center, and bottom UIViews.
Below the bottom screen there is another UIView which will show only for a button action in bottom, this comes as .CurveLinear from bottom to top ,
This works perfectly fine for a button action, but I want to happen this for a viewDidAppear, but its not working:
UIView.animateWithDuration(0.5, delay: 0.1, options: .CurveLinear , animations: {
self.infoView.frame = CGRectMake(0, 300, self.infoView.frame.size.width, self.infoView.frame.size.height)
}) { (true) in
}
This is the code block that I execute to bring the view from bottom to top, how come it only works for a button action?
Found the issue , this animation didn't work until i use NSTimer , i think i had to wait until the view renders properly , but viewDidAppear executes after the view renders , so too many unanswered questions

How can I flip an iOS UITableViewCell?

I have a tableview with a number of cells. Each cell has a little info "i" button, which I would like the user to be able to click in order to edit the information in that cell, by "flipping" the cell from the right.
I have a separate table cell XIB for each of the two possible cell states, and cellForRowAtIndexPath provides the correct XIB (with a different cell identifier) depending on whether the cell is supposed to be in the regular view or the detail/edit view. This works fine using, e.g., reloadRowsAtIndexPaths to reflect the changed state when the "i" button is pressed.
But I just can't figure out how to animate a flip when the cell's "i" button is pressed. Flipping isn't one of the options for "withRowAnimation" in reloadRowsAtIndexPaths. And using a standard animation approach like UIView animateWithDuration doesn't work: reloadRowsAtIndexPaths just causes the relevant cell to reload instantly, ignoring the animation instructions. I even tried to use drawViewHierarchyInRect to pick up the cell's future state as an image, but I couldn't get the cell to redraw itself quickly enough to be picked up by drawViewHierarchyInRect (and I don't want the user to actually see the result of the animation before the animation).
Does anyone have an idea of how to handle this?
EDIT
To summarize, the challenge I'm having is: is there another way to swap UITableView cell contents with a different UITableViewCell Xib besides reloadRowsAtIndexPaths (which breaks animations), without causing trouble with the IBOutlets of the new Xib? (Loading it as a Nib into a subview seems to break the IBOutlets.) The answers so far haven't addressed this.
It will be complicated if u use two subclassed UITableViewCell, instead use a single subclassed UITableViewCell, and perform flip-animation for example,
let xib contains the subclass UITableViewCell in its contentView add two views
normal View
Flipped View
in this view's add the contents what u want to display, and make sure both hav outlet in the cell
for example that i took
in the above two view first one View-FlipView and its contents label and button and second one is also same as first view, top view should be the normalView
connect the button actions to cell and u just perform like below in custom cell
//flip the view to flipView
- (IBAction)flipButtonAction:(UIButton *)sender
{
[UIView transitionWithView:self.contentView duration:0.6 options:UIViewAnimationOptionTransitionFlipFromRight animations:^{
[self.contentView insertSubview:_flipView aboveSubview:_normalView];
} completion:^(BOOL finished) {
}];
}
//flip the view back to normalView
- (IBAction)flipBackButtonAction:(id)sender
{
[UIView transitionWithView:self.contentView duration:0.6 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
[self.contentView insertSubview:_normalView aboveSubview:_flipView];
} completion:^(BOOL finished) {
}];
}
and it will look like something below
any problem just comment ... :) hope this helps u .. :)
Swift 4:
#IBAction func flipButtonAction(_ sender: UIButton) {
UIView.transition(with: contentView, duration: 0.6, options: .transitionFlipFromRight, animations: {() -> Void in
self.contentView.insertSubview(flipView, aboveSubview: normalView)
}, completion: {(_ finished: Bool) -> Void in
})
}
//flip the view back to normalView
#IBAction func flipBackButtonAction(_ sender: Any) {
UIView.transition(with: contentView, duration: 0.6, options: .transitionFlipFromLeft, animations: {() -> Void in
self.contentView.insertSubview(normalView, aboveSubview: flipView)
}, completion: {(_ finished: Bool) -> Void in
})
}
You probably don't want to reload the table's data to flip any given cell. Your cells should be able to flip "on their own." So you'll need to subclass UITableViewCell and in your subclass you'll have something like a flip function, that does some animations of the cell's subviews.
Now here's a trick with flip animations. You can't just change the view hierarchy and flip at the same time, or you'll see the "back side" of your view at the wrong time during the animation. Use two animations in a row:
[UIView animateWithDuration:... {
// Flip the content "half way" by rotating 90 degrees about the y axis.
// At the end of this animation your view will be perpendicular to the
// screen and *not visible*.
contentView.layer.transform = CATransform3DMakeRotation(M_PI_2, 0, 1, 0);
} completion: {
// Here you can rearrange your views (remember the view isn't visible
// right now!
//
// When the "back side" views are all ready, you can kick off the second
// half of the flip animation.
[UIView animateWithDuration:... {
// Flip *back* to the identity (not all the way around to M_PI)
// because if you flip all the way around your views will actually
// be flipped. You don't want that. Users will instinctively see
// the movement as *continuous* and interpret the flip back and forth
// animation as one continuous rotation all the way around.
contentView.layer.transform = CATransform3DIdentity;
}
}
I can't see why you couldn't use [UIView animateWithDuration...].
You could have two UIViews in each cell who's scale you animate. The first would be visible and the second would be hidden
At the half-way point of the animation, simply hide the first UIView and unhide the second and continue the animation from there.

Resources