[IOS effect set] achieves QQ's elimination of red dots (one-click return)

Source: Internet
Author: User

[IOS effect set] achieves QQ's elimination of red dots (one-click return)

The sticky little red dots on QQ are fun and interesting, so I want to implement them myself. I see that there are fewer iOS implementations and more Android ones, so I will use iOS to implement this ~

:

Debugging diagram:

In fact, in terms of implementation, I first realized the effect of the second figure.

Implementation

1. Understand the principle and how to draw the "adhesive" shape (that is, to draw two circles and two besell curves ).

2. Create a New UIView (AZMetaBallCanvas), which is used as a separate canvas to draw the "adhesive" shape, implement algorithms using programs, and draw them out.

3. Add a canvas (AZMetaBallCanvas)attach:(UIView *)Method, and add a gesture listener, re-painting, so that any view can be "pasted" on the canvas.

4. Determine whether to disconnect the animation based on the distance of the heartbeat link. When the user's finger leaves, determine whether the animation is an explosive animation or a rebound animation based on the distance.

Detailed Process

First, you must understand what the shape of the drag process is like MetaBall ). After careful observation, we can find that two circles of different sizes are combined with two besell curves.

I have broken down the algorithm into another blog, it is strongly recommended that you do not know how the shape is drawn. Let's take a look at the detailed calculation method of "algorithm analysis" QQ "one-click return".

1. Draw and drag

Now that we know how to draw the coordinate points, we can implement them now.

First, create a new "canvas" inherited fromUIView

//AZMetaBallCanvas.h@interface AZMetaBallCanvas : UIView@property(nonatomic,strong) Circle *centerCircle;@property(nonatomic,strong) Circle *touchCircle;@end

CircleFor custom object classes, some basic attributes of the circle are defined, such as the Center Coordinate and radius.

Why create a new canvas?

Because the red dot can be dragged in full screen mode, do not look at it on QQ.CellBut you can pull it to anotherCellIn this case, you need to give the little red dot enough position to draw, and then create a canvas to draw the little red dot action.

AZMetaBallCanvasCurrently, there are two attributes: two circles, one center circle and one touch circle. According to requirements, the center circle should remain unchanged. The touch circle will change with the position of the finger touch the screen, you need to draw the besell curve between the two circles to form the ball effect.

Next, start writing.AZMetaBallCanvasImplementation

//AZMetaBallCanvas.m#define RADIUS 40.0@interface AZMetaBallCanvas() {    UIBezierPath *_path;    CGPoint _touchPoint;}@end@implementation AZMetaBallCanvas- (instancetype)initWithCoder:(NSCoder *)aDecoder {    self = [super initWithCoder:aDecoder];    NSLog(@"initWithCorder");    if (self) {        [self initData];    }    return self;}- (void)initData {    _touchCircle = [Circle initWithcenterPoint:self.center radius:RADIUS];    _centerCircle = [Circle initWithcenterPoint:self.center radius:RADIUS];    _touchPoint = self.center;    NSLog(@"self.center (%f, %f)", self.center.x, self.center.y);}@end

Initialize the positions of two circles first. The default value isViewIninit,initWithFrame,initWithCoderAdd the custom Initialization Method to the parent class constructor.initData.

Override Plotting Method

As in AndroidonDraw(), In iOSdrawRectCan be rewritten and then called[view setNeedsDisplay].

- (void)drawRect:(CGRect)rect {    _path = [[UIBezierPath alloc] init];    [self drawCenterCircle];    [self drawTouchCircle:_touchPoint];    [self drawBezierCurveWithCircle1:_centerCircle Circle2:_touchCircle];}

As mentioned in algorithm analysis, we only need to draw two circles (drawCenterCircle,drawTouchCircle) And the beiser curve connecting the two circles (drawBezierCurve), The algorithm is actually a detailed calculation method of [algorithm analysis] QQ "one-click return"

Built-in beiser curve for iOSUIBezierPathIts built-in Circle MethodaddArcWithCenter: radius: startAngle: endAngle: clockwise:So we only need to call it!

# Pragma mark draw circle --- circle-(void) drawCenterCircle {[self drawCircle: _ path circle: _ centerCircle];}-(void) drawTouchCircle :( CGPoint) center {_ touchCircle. centerPoint = center; [self drawCircle: _ path circle: _ touchCircle];}-(void) drawCircle :( UIBezierPath *) path circle :( Circle *) circle {[_ path addArcWithCenter: circle. centerPoint radius: circle. radius startAngle: 0 endAngle: 360 clockwise: true]; [_ path fill]; [_ path stroke]; [_ path removeAllPoints];}
# Pragma mark draw curve --- draw the besell curve-(void) drawBezierCurveWithCircle1 :( Circle *) circle1 Circle2 :( Circle *) circle2 {float circle1_x = circle1.centerPoint. x; float circle1_y = circle1.centerPoint. y; float circle2_x = circle2.centerPoint. x; float circle2_y = circle2.centerPoint. y; // float d = sqrt (powf (circle1_x-circle2_x, 2) + powf (circle1_y-circle2_y, 2 )); // float angle1 = atan (circle2_y-circle1_y)/(circle1_x-circle2_x )); // float angle2 = asin (circle1.radius-circle2.radius); // float angle3 = M_PI_2-angle1-angle2; float angle4 = M_PI_2-angle1 + angle2; float placement = cos (angle3) * circle1.radius; float offset1_Y = sin (angle3) * circle1.radius; float placement = cos (angle3) * circle2.radius; float flood = sin (angle3) * circle2.radius; float offset3_X = cos (angle4) * circle1.radius; float flood = sin (angle4) * circle1.radius; float offset4_X = cos (angle4) * circle2.radius; float cursor = sin (angle4) * circle2.radius; float p1_x = relative-offset1_X; float p1_y = circle1_y-offset1_Y; float p2_x = circle2_x-offset2_X; float p2_y = relative-cursor; float p3_x = circle1_x + offset3_X; float p3_y = circle1_y + week; float p4_x = circle2_x + offset4_X; float p4_y = week + week; CGPoint p1 = CGPointMake (p1_x, p1_y ); CGPoint p2 = CGPointMake (p2_x, p2_y); CGPoint p3 = CGPointMake (p3_x, p3_y); CGPoint p4 = CGPointMake (p4_x, p4_y); CGPoint p1_center_p4 = CGPointMake (p1_x + p4_x) /2, (p1_y + p4_y)/2); CGPoint p2_center_p3 = CGPointMake (p2_x + p3_x)/2, (p2_y + p3_y)/2); [self drawBezierCurveStartAt: p1 EndAt: p2 controlPoint: p2_center_p3]; [self drawLineStartAt: p2 EndAt: p4]; [self outcome: p4 EndAt: p3 controlPoint: p1_center_p4]; [self drawLineStartAt: p3 EndAt: p1]; [_ path moveToPoint: p1]; [_ path closePath]; [_ path stroke];}
2. Simple listening gesture Edition

The simplest thing is to directlyAZMetaBallCanvasRewritetouchXXXAnd then callsetNeedsDisplayNotificationUIViewRedraw.

#pragma mark touch event- (void)touchesBegan:(NSSet
  
    *)touches withEvent:(UIEvent *)event {    UITouch *touch = [touches anyObject];    _touchPoint = [touch locationInView:self];    [self setNeedsDisplay];}- (void)touchesMoved:(NSSet
   
     *)touches withEvent:(UIEvent *)event {    UITouch *touch = [touches anyObject];    _touchPoint = [touch locationInView:self];    [self setNeedsDisplay];}
   
  

In fact, the effect of the second graph has come out. The difference is to change the radius of the two circles.

The method to change the radius is very simple.

# Pragma change radius-(void) changeCenterCircleRadiusTo :( float) radius {_ centerCircle. radius = radius; [self setNeedsDisplay];}-(void) changeTouchCircleRadiusTo :( float) radius {_ touchCircle. radius = radius; [self setNeedsDisplay];}
Basic Edition

According to the phenomenon, we need to drag and drop the red dot to move it, instead of pointing to it, where the red dot is. Therefore, we need to add a gesture listener to the red dot, instead of a canvas ".

So we add a method to the canvas.- (void)attach:(UIView *)item;And then add the imported viewPanGesture.

-(Void) attach :( UIView *) item {UIPanGestureRecognizer * drag = [[UIPanGestureRecognizer alloc] initWithTarget: self action: @ selector (drag :)]; item. userInteractionEnabled = YES; [item addGestureRecognizer: drag];}-(void) drag :( required *) recognizer {// get the touch point _ touchPoint = [recognizer locationInView: self]; // obtain the touch view UIView * touchView = recognizer. view; switch (recognizer. state) {case UIGestureRecognizerStateBegan: {// touch start: Draw a copy of The touchView on the canvas //... for this part, see the source code break;} case UIGestureRecognizerStateChanged: {// in motion: recording the touch position, changing the coordinates of the touchView and touchCircle [self resetTouchCenter: _ touchPoint]; break ;} case UIGestureRecognizerStateEnded: {// touch end: determines whether to execute an animation blast or a spring animation based on the length of the heartbeat line //... for this part, see the source code break;} default: break;} [self setNeedsDisplay]; // redraw}

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.