I'm trying to use UIKit Dynamics to implement swipe-to-delete on my UICollectionViewCells. Things aren't going as planned, though. Here's the code in UICollectionViewCell's awakeFromNib method:
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.contentView];
UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:#[self.contentView]];
[collisionBehavior setTranslatesReferenceBoundsIntoBoundaryWithInsets:UIEdgeInsetsMake(0, 0, 0, -20)];
[self.animator addBehavior:collisionBehavior];
self.gravityBehavior = [[UIGravityBehavior alloc] initWithItems:#[self.containerView]];
self.gravityBehavior.gravityDirection = CGVectorMake(0, 0);
[self.animator addBehavior:self.gravityBehavior];
self.pushBehavior = [[UIPushBehavior alloc] initWithItems:#[self.containerView] mode:UIPushBehaviorModeInstantaneous];
self.pushBehavior.magnitude = 0.0f;
self.pushBehavior.angle = 0.0f;
[self.animator addBehavior:self.pushBehavior];
UIDynamicItemBehavior *itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:#[self.containerView]];
itemBehavior.elasticity = 0.45f;
[self.animator addBehavior:itemBehavior];
But this is not working so well. This is what happens at launch with the code above:
That behavior seems to be mostly generated by UICollisionBehavior. If I comment it out, the container view with everything that's not the red background doesn't animate, but does show up offset a few points to the left.
Am I right to try to implement this within UICollectionViewCell? What's the right way of doing this?
Thanks!
Never mind. It was pretty much a typo. The collision behavior was attached to the wrong object.
The right code should be
UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:#[self.containerView]];
[collisionBehavior setTranslatesReferenceBoundsIntoBoundaryWithInsets:UIEdgeInsetsMake(0, 0, 0, -20)];
[self.animator addBehavior:collisionBehavior];
Related
I'm new to the iOS UI development and I need some help to figure out, what is the best way to implement image belt (sequence of images in horizontal belt). I don't need details (someone to write me the code), just guidance what I should focus on learning as a libraries and most important design patterns (by design patters I mean software design for iOS UI).
The task details:
1. I will have image belt - sequence of few related images. This will be my horizontal transition. The transition animation will be simple push animation (something like push CATransion), initiated by swipe left/right. On top of the images there will be overlay with some text, icon info and etc. The overlay info will be the same for all images in the current belt.
2. I will have multiple image belts - this will be my vertical transition. The transition between belts will be triggered by swipe up/down. The different belts will contain unrelated information, so the information shown in overlays from point 1 must be also changed. The animation will be also simple push animation as in point 1.
I probably should inherit UIView and implement my belt as one object, which will consist of different UIView(overlay) and UIImageViews(for the images). Am I on the right track?
Some helpful brainstorm will be highly appreciated.
Yes - I've done many of these. You add a UIView above the top view. I usually use a full-screen one with some alpha so they can see through the core content a little. Then add stuff on top of that which won't change: things like your text, icons, etc... Then on top of that you put the image you want to swipe and add a swipe gesture recognizer, typically one for left and one for right. When they swipe you init a new UIView off the edge of the device, init it with the image, and animate the frames of both left or right, depending on which way they've swiped. Mine are help tutorials showing how to use my app step-by-step so I also init multi-part animations on some of the frames that fly in; that's a nice looking optional effect. Here's the one I use (with the animation support stripped out or it'd be too much code) and there's lots of variations. Edited to note my app doesn't support rotation but if yours does you have to adjust the frames after a rotation.
- (void)init
{
currentPanelNumber = 10;
self = [super initWithNibName:nil bundle:nil];
if (self)
{
[self.view setBackgroundColor:[UIColor clearColor]];
currentPanelNumber = 10;
overlay = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1024, 768)];
overlay.backgroundColor = [UIColor colorWithRed:.9 green:.9 blue:.9 alpha:.9];
[self.view addSubview:overlay];
CGRect currentPanelFrame = CGRectMake(267, 175, 494, 444);
currentPanel =
[[HelpView alloc] initWithFrame:currentPanelFrame withImage:[UIImage imageNamed:#"10"]];
currentPanel.frame = currentPanelFrame;
[overlay addSubview:currentPanel];
// ----------------------------------
// Gesture swipes go here
swipeLeftRecognizer =
[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeLeft:)];
[swipeLeftRecognizer setDirection:UISwipeGestureRecognizerDirectionLeft];
[overlay addGestureRecognizer:swipeLeftRecognizer];
swipeRightRecognizer =
[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeRight:)];
[swipeRightRecognizer setDirection:UISwipeGestureRecognizerDirectionRight];
[overlay addGestureRecognizer:swipeRightRecognizer];
swipeDownRecognizer =
[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeDown:)];
[swipeDownRecognizer setDirection:UISwipeGestureRecognizerDirectionDown];
[overlay addGestureRecognizer:swipeDownRecognizer];
UITapGestureRecognizer *tapRecognizer =
[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
[overlay addGestureRecognizer:tapRecognizer];
skipIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"SkipAndStartIcon"]];
CGSize size = CGSizeMake(84, 124);
skipIcon.frame = CGRectMake((self.view.frame.size.width/2)-(size.width/2), self.view.frame.size.height-size.height-25, size.width, size.height);
[self.view addSubview:skipIcon];
}
- (void)goNext
{
// Clear out all subviews to remove lingering animations
[[currentPanel subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
if(currentPanelNumber>=80)
{
[self closeHelp];
return;
}
NSString *nextImage = [NSString stringWithFormat:#"%i", currentPanelNumber+10];
CGRect nextPanelFrame = CGRectMake(765, 175, 494, 444);
nextPanel = [[HelpView alloc] initWithFrame:nextPanelFrame withImage:[UIImage imageNamed:nextImage]];
nextPanel.frame = nextPanelFrame;
[overlay addSubview:nextPanel];
[UIView animateWithDuration:.2 animations:^
{
nextPanel.frame = currentPanel.frame;
}
completion:^(BOOL finished)
{
currentPanel.image = nextPanel.image;
nextPanel.alpha = 0;
currentPanelNumber += 10;
}
- (void)goPrevious
{
if(currentPanelNumber<=10)
{
return;
}
// Clear out all subviews to remove lingering animations
[[currentPanel subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
NSString *nextImage = [NSString stringWithFormat:#"%i", currentPanelNumber-10];
CGRect nextPanelFrame = CGRectMake(-230, 175, 494, 444);
// nextPanel = [[UIImageView alloc] initWithImage:[UIImage imageNamed:nextImage]];
nextPanel = [[HelpView alloc] initWithFrame:nextPanelFrame withImage:[UIImage imageNamed:nextImage]];
nextPanel.frame = nextPanelFrame;
[overlay addSubview:nextPanel];
[UIView animateWithDuration:.2 animations:^
{
nextPanel.frame = currentPanel.frame;
}
completion:^(BOOL finished)
{
currentPanel.image = nextPanel.image;
nextPanel.alpha = 0;
currentPanelNumber -= 10;
}];
}
I have a UIVIew (container) and another UIView (box) the box view is inside of the ContainerView. When a UIButton is pressed I would like the box view to drop down off the bottom of the screen, and bounce with 10px left; then once the bouncing has stopped I still want the box to have 10px showing. Here is some sample code of from another question:
UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self]; //self is the container
UIGravityBehavior* gravityBehavior = [[UIGravityBehavior alloc] initWithItems:#[box]];
[animator addBehavior:gravityBehavior];
UICollisionBehavior* collisionBehavior = [[UICollisionBehavior alloc] initWithItems:#[reportBar.bar]];
collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
[animator addBehavior:collisionBehavior];
UIDynamicItemBehavior *elasticityBehavior =
[[UIDynamicItemBehavior alloc] initWithItems:#[box]];
elasticityBehavior.elasticity = 0.7f;
[animator addBehavior:elasticityBehavior];
The code is running when it should but the box isn't dropping.
Edit 1:
Self refers to the container UIView
I have also tried changing self for the currentViewController.view, no change.
Edit 2:
all of this code is inside the container view implementation file.
give a try to make animator property,
#property UIDynamicAnimator *animator;
and then your code,
_animator = [[UIDynamicAnimator alloc] initWithReferenceView:self];
...
I think you didn't specify the correct reference view. It should be either self.view or self.containerView
UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self];
Update
I think you should put the code in the ViewController for this scene and as #BaSha suggested create a animator property and after a button click you will add the behavior and will reference self.containerView
Just make sure that boxView is inside of the containerView
The following code snippet can provide BOUNCE EFFECT on your views.
CABasicAnimation * animation = [CABasicAnimation animationWithKeyPath:#"position.y"];</br>
[animation setFromValue:[NSNumber numberWithFloat:y-position1]];
[animation setToValue:[NSNumber numberWithFloat:y-position2]];
[animation setDuration:.7]; // time gap between the bounces
animation.repeatCount=500; // no:of times bounce effect has to be done
[YOURVIEW.layer addAnimation:animation forKey:#"somekey"];
As you may know that the iOS 7 home screen can do a visual things like, when the user moving the device, the background is moving as well. How can I do the similar thing in my application? Let say I got two images view. One is on top of another. How to implement the similar things? Thank.
you can set UIInterpolatingMotionEffect x and y ordination with help of UIMotionEffectGroup. I just test one code in to my demo and i put this here check this:-
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect frame = self.view.bounds;
for (NSInteger i=0; i<1; i++) {
CGFloat left = (frame.size.width-100)/2+i%2*10;
CGFloat top = (frame.size.height-100)/2+i%3*10;
UIImageView *demoView = [[UIImageView alloc] initWithFrame:CGRectMake(left, top , 100, 100)];
[demoView setImage:[UIImage imageNamed:#"FA4nH.jpg"]];
// demoView.backgroundColor = [UIColor colorWithRed:i/12.0f green:i/18.0f blue:i/24.0f alpha:0.8];
[self.view addSubview:demoView];
UIInterpolatingMotionEffect *xAxis = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:#"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
UIInterpolatingMotionEffect *yAxis = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:#"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
left += i*50;
top += i *50;
xAxis.minimumRelativeValue = #(-left);
xAxis.maximumRelativeValue = #(left);
yAxis.minimumRelativeValue = #(-top);
yAxis.maximumRelativeValue = #(top);
UIMotionEffectGroup *motionEffectGroup = [[UIMotionEffectGroup alloc] init];
motionEffectGroup.motionEffects = #[xAxis, yAxis];
[demoView addMotionEffect:motionEffectGroup];
}
}
Check this in to real Device that work nice i tested this in to my one of the demo project. hope that helps to you.
in iOS 7 you have UIMotionEffect.
Another user in Stackoverflow ask a similar question.
You can read here: Solution to parallax effect in iOS 7
Also you can take a look to this library in GitHub: NGAParallaxMotion. Basically is a tiny category that help you to achieve a parallax effect with UIMotionEffect.
I want to replicate the attachment behavior of UITableViewCell, just like what Apple made in the Messages App.
I tried subclassing UITableViewCell and here is the code :
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self];
self.attachmentBehavior = [[UIAttachmentBehavior alloc] initWithItem:self.superview attachedToAnchor:self.superview.center];
[self.attachmentBehavior setFrequency:4.5];
[self.attachmentBehavior setDamping:0.3];
UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:#[self]];
//gravity direction: right
[gravityBehavior setGravityDirection:CGVectorMake(0.0, -0.8)];
UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:#[self]];
[collisionBehavior addBoundaryWithIdentifier:#"topBoundary" fromPoint:CGPointMake(0.0f, 0.0f) toPoint:CGPointMake(self.contentView.frame.size.width, 0.0f)];
[collisionBehavior addBoundaryWithIdentifier:#"bottomBoundary" fromPoint:CGPointMake(0.0f, self.contentView.frame.size.height) toPoint:CGPointMake(self.contentView.frame.size.width, self.contentView.frame.size.height)];
UIDynamicItemBehavior* itemBehaviour = [[UIDynamicItemBehavior alloc] initWithItems:#[self]];
itemBehaviour.elasticity = 0.9;
[self.animator addBehavior:itemBehaviour];
[self.animator addBehavior:gravityBehavior];
[self.animator addBehavior:collisionBehavior];
But, it doesn't seem to work.
Can someone help me to reproduce the same functionality as the Messages app please ?
Edited :
I know that Apple uses UICollectionView instead tableview for the Messages App, but i hope there should be a way to do this kind of functionality through tableview also.
I am trying my hand at UIKit Dynamics and am trying to create a simple animation with a ball that bounces off of the screen boundaries.
As shown in the code below, when I add the gravity behavior the ball seems to go off the screen as expected. But when I add the collision behavior, nothing happens. The ball stays as is at the center of the screen where I have drawn it initially.
I also trie to add a push behavior with continuous push force option, but still the ball does not move.
#implementation TAMViewController
UIDynamicAnimator* animator;
UIGravityBehavior* gravity;
UICollisionBehavior* collision;
UIPushBehavior* push;
- (void)viewDidLoad
{
[super viewDidLoad];
TAMBouncyView *ballView = [[TAMBouncyView alloc] initWithFrame:CGRectMake(0,0,
self.view.frame.size.width,
self.view.frame.size.height)];
[self.view addSubview:ballView];
animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
gravity = [[UIGravityBehavior alloc] initWithItems:#[ballView]];
[animator addBehavior:gravity];
collision = [[UICollisionBehavior alloc] initWithItems:#[ballView]];
[collision setTranslatesReferenceBoundsIntoBoundary:YES];
[animator addBehavior:collision];
push = [[UIPushBehavior alloc] initWithItems:#[ballView]
mode:UIPushBehaviorModeContinuous];
[animator addBehavior:push];
// Do any additional setup after loading the view, typically from a nib.
}