one

Let’s see the picture above

This is a function I bought in the App before. I didn’t finish writing it at the beginning. Now I think of it and improve it.

1. The light green part above is drawn using Bezier curves, which is not a problem;

2. The bottom curve is the Bezier curve. The Bezier curve has a point called the vertex, which is roughly at the top of the head, and this point and the left and right points to the screen make up the Bezier curve.

3. The midpoint of the head is always at the midpoint of the Bezier curve;

4. Curve are the coordinates of point a formula to calculate the fall, do not trained, college also forget to clean, so can’t count it, friend is interested in Google, but fortunately we here left and right sides is symmetrical, sleep a special Bessel curve, so the midpoint coordinates is vertical to the around the halfway point of the two attachment, The middle position of this line segment;

5. Knowing this formula is enough for us to write this function;

two

Look at the core code

- (void)handlePanAction:(UIPanGestureRecognizer *)pan { CGPoint point = [pan translationInView:self]; NSLog(@"%f",point.y); if (point.y < 0) { return; } if(! _isAnimating) {if (pan) state = = UIGestureRecognizerStateChanged) {/ / gestures while moving, _shapeLayer expands the area down with the gesture _mHeight = point.y + 60; Self. CurveX = KWIDTH / 2.0; Self. curveY = _mHeight > 240? Self. curveY = _mHeight > 240? 240 : _mHeight; _curveView.frame = CGRectMake(_curveX, self.curveY, _curveView.frame.size.width, _curveView.frame.size.height); _headerImage.center = CGPointMake(KWIDTH / 2, 105 + (self.curveY - 60) / 2); / / 60 is vertex y [self cuteDelegate backMeWithHeaderCenterY: + 105 (self) curveY - 60) / 2]; } else if (pan.state == UIGestureRecognizerStateCancelled || pan.state == UIGestureRecognizerStateEnded || pan.state == At the end of the UIGestureRecognizerStateFailed) {/ / gestures, _shapeLayer return to original state and spring dynamic effect _isAnimating = YES; _displayLink.paused = NO; / / open the displaylink method performs calculatePath. / / spring dynamic effect [UIView animateWithDuration: 1 delay: usingSpringWithDamping 0.0:0.3 initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ _curveView.frame = CGRectMake(KWIDTH/2, 60, 0.1, 0.1); Frame _headerimage. center = CGPointMake(KWIDTH / 2, 105); / / to eventually return to neutral NSLog (@ "% f", _headerImage center. Y); [self. CuteDelegate backMeWithHeaderCenterY: 105]; / / back to the position of the last child views change position } completion:^(BOOL finished) {if(finished) {_displaylink.paused = YES; _isAnimating = NO; Need to refresh the data or to here, on behalf of an end state, you can also pass through callbacks. [self. CuteDelegate backMeWithHeaderCenterY: 1000];}}]; }}} - (void)updateShapeLayerPath {// Update _shapeLayer Not too hard UIBezierPath *tPath = [UIBezierPath bezierPath]; [tPath moveToPoint:CGPointMake(0, 0)]; [tPath addLineToPoint:CGPointMake(KWIDTH, 0)]; [tPath addLineToPoint:CGPointMake(KWIDTH, MIN_HEIGHT)]; [tPath addQuadCurveToPoint:CGPointMake(0, MIN_HEIGHT) controlPoint:CGPointMake(_curveX, _curveY)]; [tPath closePath]; _shapeLayer.path = tPath.CGPath; } - (void)calculatePath {// Due to the spring animation at the end of the gesture, record the coordinates of the process and draw the _shapeLayer shape accordingly, Here for changes to the vertex coordinates CALayer. * layer = _curveView layer. PresentationLayer; self.curveX = layer.position.x ; self.curveY = layer.position.y; }Copy the code

The above code is not completely finished, although we have written the elastic animation of the lead image, but it is a big problem to put the data of the personal center on it. Only the elastic view we have customized will respond to the animation effect of the drop down, if something like this:



At the bottom is the scrollView, the view below does not respond to the pull down, if forced to add the gesture above method, scrollView will not slide, in short, the blogger here made a lot of attempts, often solve one problem, another, difficult to solve. Finally, the solution selected is the original UItableView, which uses the elastic animated view as a tableHeaderView. Similarly, the tableView will not respond to pulledown animations, so force a gesture. Here’s the code:

#import "ViewController.h" #import "LHCuteView.h" #import "MyTableView.h" @interface ViewController ()<CuteViewDelegate,UITableViewDelegate,UITableViewDataSource,UIScrollViewDelegate,UIGestureRecognizerDelegate> { MyTableView *tableView; LHCuteView *cuteView; UIView *subView; BOOL isCute; } @end #define KWIDTH ([[UIScreen mainScreen] bounds].size.width) #define KHEIGHT ([[UIScreen mainScreen] Bounds].size. Height) @implementation ViewController - (void)viewDidLoad {[super viewDidLoad]; [self.navigationController setNavigationBarHidden:YES animated:YES]; // [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent]; [self methodTwo]; } - (void)methodOne{ cuteView = [[LHCuteView alloc] initWithFrame:CGRectMake(0, 0, KWIDTH, KHEIGHT)]; cuteView.backgroundColor = [UIColor whiteColor]; cuteView.cuteDelegate = self; [self.view addSubview:cuteView]; cuteView.headerImage.image = [UIImage imageNamed:@"cute.jpg"]; subView = [[UIView alloc]initWithFrame:CGRectMake(0, 170, KWIDTH, KHEIGHT - 170)]; [cuteView addSubview:subView]; [self creatSubView]; } - (void)methodTwo { cuteView = [[LHCuteView alloc] initWithFrame:CGRectMake(0, 0, KWIDTH, 170)]; cuteView.backgroundColor = [UIColor whiteColor]; cuteView.cuteDelegate = self; [self.view addSubview:cuteView]; isCute = YES; cuteView.headerImage.image = [UIImage imageNamed:@"cute.jpg"]; tableView = [[MyTableView alloc]initWithFrame:CGRectMake(0, 0, KWIDTH, KHEIGHT) style:UITableViewStylePlain]; tableView.delegate = self; tableView.bounces = NO; tableView.dataSource = self; [self.view addSubview:tableView]; tableView.tableHeaderView = cuteView; UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanAction:)]; [tableView addGestureRecognizer:pan]; } - (void)handlePanAction:(UIPanGestureRecognizer *)pan { CGPoint point = [pan translationInView:tableView]; if (point.y > 0) { if (isCute == YES) { [cuteView handlePanAction:pan]; } } } - (void)creatSubView { for (int i = 0; i < 5; i++) { UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(10, i * 44, 100, 44)]; Label. text = [NSString stringWithFormat:@" %d", I]; label.textAlignment = NSTextAlignmentLeft; [subView addSubview:label]; } } - (void)backMeWithHeaderCenterY:(CGFloat)centerY { // tableView.frame = CGRectMake(0, centerY + 30 + 50, KWIDTH, KHEIGHT - 170); // subView.frame = CGRectMake(0, centerY + 80, KWIDTH, KHEIGHT - 170); if (centerY == 1000) { cuteView.frame = CGRectMake(0, 0, KWIDTH, 170); tableView.tableHeaderView = cuteView; [tableView reloadData]; } else { cuteView.frame = CGRectMake(0, 0, KWIDTH, centerY + 65); tableView.tableHeaderView = cuteView; } } #pragma mark - UITableViewDelegate - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 15; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 44; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; if (! cell) { cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"]; } cell.textLabel.text = [NSString stringWithFormat:@" personal center %ld",(long)indexPath. Row]; return cell; } - (void)scrollViewDidScroll:(UIScrollView *)scrollView { NSLog(@"%f",tableView.contentOffset.y); if (tableView.contentOffset.y > 0) { isCute = NO; } the if (tableView. ContentOffset. Y = = 0) {[self performSelector: @ the selector (canCute) withObject: nil afterDelay: 0.1]; } } - (void)canCute { isCute = YES; }Copy the code

three

The above is the blogger’s final code, in order to solve the tableView gesture conflict, need to customize tableView and implement gesture proxy method:

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    if (gestureRecognizer.state != 0) {
        return YES;
    } else {
        return NO;
    }
}
Copy the code

At the same time, in order for the tableView to roll down and back and not trigger the drop down when the offset is restored to 0, we need to do this in the scrollView agent. When isCute is YES, the animation will be performed. That’s what we need.

Above, I hope you can take a look at the code carefully, think carefully, otherwise it is difficult to understand, the principle of the beginning must see, or check their own bezier curve point coordinates calculation method, here is only a special case, remember.

In fact, here can also do depth encapsulation, but in order to understand you do not do too much processing, you can according to their own needs to transform oh, this is also a blogger in other people’s elastic animation on the function, has been derived from the original animation.

Demo download address: Click to download