Getting Started with IOS custom controls: Draggable Loop Progress

Source: Internet
Author: User
Tags uicontrol uikit

Sometimes Uikit's standard controls don't meet our needs, so we can customize the controls to meet our needs, such as this article will teach you how to customize a circular progress bar, and the user can change the progress value by dragging the handle on the progress bar. The main reference is this article: how to BUILD A CUSTOM CONTROL in IOS. Ad time: One of my free apps: nap alarm clock using this control, welcome to the AppStore search nap alarm clock for download use.

Our custom control inherits from the Uicontrol class, which is a subclass of UIView and is the parent of all Uikit controls (UIButton, UISlider, Uiswitch, etc.). The purpose of the Uicontrol instance is to create the appropriate logic to distribute the action to the appropriate target,90%, which will draw the user interface based on its own state (such as highlighted, selected, disabled, etc.).

Uicontrol has three key tasks to accomplish:

    • Drawing the user interface
    • Tracking users ' interactions
    • Target-action mode

Therefore, for the circular progress bar to be completed in this article, we will complete the following tasks:

Drawing a user interface that users can interact with by dragging the handle sliders, the user's actions are converted to the actions of target, and the control converts the frame origin of the slider to a value between 0-360 and is used on target/action. Here are three steps to explain the three steps that correspond to the three important tasks mentioned above.

1.1 Drawing the user interface


, we will be through the core graphics to draw the gray progress bar background, red progress bar, slider handle, the basic knowledge of core graphics, this article does not make a detailed introduction, if you need to leave a message, I will be available to you to translate the official core Graphics document (a bit more, after all).

-(void) DrawRect: (cgrect) rect {[Super Drawrect:rect];        Cgcontextref context = Uigraphicsgetcurrentcontext ();    1. Draw the gray background cgcontextaddarc (context, SELF.FRAME.SIZE.WIDTH/2, SELF.FRAME.SIZE.HEIGHT/2, radius, 0, m_pi*2, 0);    [[Uicolor Graycolor] setstroke];    Cgcontextsetlinewidth (context, _linewidth);    Cgcontextsetlinecap (context, Kcglinecapbutt);        Cgcontextdrawpath (context, kcgpathstroke);    2. Draw Progress Cgcontextaddarc (context, SELF.FRAME.SIZE.WIDTH/2, self.frame.size.height/2,radius,0, Torad (_angle), 0);    [[Uicolor Redcolor] setstroke];    Cgcontextsetlinewidth (context, _linewidth);    Cgcontextsetlinecap (context, kcglinecapround);        Cgcontextdrawpath (context, kcgpathstroke);    3. Draw drag Small block cgpoint handlecenter = [self pointfromangle: (self.angle)]; Cgcontextsetshadowwithcolor (context, Cgsizemake (0, 0), 3,[uicolor Bluecolor].    Cgcolor);    [[Uicolor Redcolor] setstroke];    Cgcontextsetlinewidth (context, _linewidth*2); Cgcontextaddellipseinrect (Context, CGRectMake (handlecenter.x, Handlecenter.y, _linewidth*2, _linewidth*2)); Cgcontextdrawpath (context, kcgpathstroke);}

The Pointfromangle method is to obtain the corresponding latitude and longitude of the ring from a given angle, simply using a basic triangular function relationship:
-(Cgpoint) Pointfromangle: (int) angleint{    //center point    cgpoint centerpoint = Cgpointmake (Self.frame.size.width/2-_ LineWidth, SELF.FRAME.SIZE.HEIGHT/2-_linewidth);        Get the coordinates cgpoint result on the ring according to the angle    ;    Result.y = Round (centerpoint.y + radius * sin (Torad (angleint)));    Result.x = Round (centerpoint.x + radius * cos (Torad (angleint)));        return result;}


1.2 Tracking users ' interactions

With 1.1 completed, we have now mapped the user interface, but it is not yet responsive to our touch events. as long as we rewrite (override) The three methods of Uicontrol, we can track user actions.

1.2.1 Start tracking Touch events

When the user touches the bound within the Uicontrol, the Begintrackingwithtouch method is called, and this method returns the bool type, which returns YES to continue tracking the touch event.

-(BOOL) Begintrackingwithtouch: (Uitouch *) Touch withevent: (uievent *) event{    [Super Begintrackingwithtouch:touch Withevent:event];    return YES;}

1.2.2 Continuous tracking of touch time

The above method returns YES to continue tracking touch events, so when the user drags on the screen, Continuetrackingwithtouch is called, and the bool value returned by the method indicates whether the touch event continues to be tracked. By this method we will update the position of the handle according to the location of the user's touch.

-(BOOL) Continuetrackingwithtouch: (Uitouch *) Touch withevent: (uievent *) event{    [Super Continuetrackingwithtouch : Touch withevent:event];    Get touch point    cgpoint lastpoint = [Touch locationinview:self];    Use touch points to move small pieces    [self movehandle:lastpoint];    Send Value Change event    [self sendactionsforcontrolevents:uicontroleventvaluechanged];    return YES;}
where we call the Movehandle: method to update the position of the slide handle:

-(void) Movehandle: (cgpoint) lastpoint{        //Get center point    cgpoint centerpoint = Cgpointmake (SELF.FRAME.SIZE.WIDTH/2,                                      SELF.FRAME.SIZE.HEIGHT/2);    The center point to any point of the angle    float currentangle = Anglefromnorth (CenterPoint,                                        lastpoint,                                        NO);    int angleint = floor (currentangle);    Save new angle    self.angle = angleint;    Redraw    [self setneedsdisplay];}

Anglefromnorth (cgpoint p1,cgpoint p2,BOOL Flipped) method is the angle of the center point to any point,

Is from the Apple is the example code ClockControl in the function, relatively complex (mathematics did not learn ... ), just as the Apple provides a way to invoke on the line.

Static inline float Anglefromnorth (cgpoint p1, cgpoint P2, BOOL flipped) {    Cgpoint v = cgpointmake (p2.x-p1.x,p2.y-p1.y );    float Vmag = sqrt (SQR (v.x) + SQR (V.Y)), result = 0;    v.x/= Vmag;    V.y/= Vmag;    Double radians = atan2 (v.y,v.x);    result = Todeg (radians);    Return (Result >=0  ? Result:result + 360.0);}

1.2.3 End Trace

This method is called when the trace is closed, and the override method is not required in our example

Now, the Circle slider control can work, drag the slide handle to see.

1.3 target-action Mode

If you want your custom controls to be consistent with the uicontrol behavior, you need notification processing when the value of the control changes: Using the Sendactionsforcontrolevents method, and developing a specific event type, The events corresponding to the value change are generally uicontroleventvaluechanged.

Apple has pre-defined many event types (Xcode, cmd + mouse click on uicontroleventvaluechanged). If your control is inherited from Uitextfield, then we might be interested in Uicontroleventedigitingdidbegin, if you want to do a touch up action, You can use Uicontroltouchupinside. In the Continuetrackingwithtouch method in the previous section of this article, we have called the Sendactionsforcontrolevents method. when this is done, each object (the Observer-registering the event) receives a notification of the response when the value of the control changes.


2. Using a custom controlIn addition to changing the progress through user touch events, sometimes we also want to modify the code, we only need to implement the storage angle of the property angle set method:
-(void) Changeangle: (int) angle{    _angle = angle;     [Self sendactionsforcontrolevents:uicontroleventvaluechanged];    [Self setneedsdisplay];}

OK, now we're using our controls in Viewcontroller:
    Jxcircleslider *slider = [[Jxcircleslider alloc] Initwithframe:cgrectmake (0, 0, +)];    Slider.center = Self.view.center;        [Slider addtarget:self action: @selector (newvalue:) forcontrolevents:uicontroleventvaluechanged];    [Slider changeangle:120];    [Self.view Addsubview:slider];

we initialize and then set the center display, register the value change response event, when the progress value changes, will call the method
-(void) NewValue: (jxcircleslider*) slider{    NSLog (@ "newvalue:%d", Slider.angle);}

Project Source code: Https://github.com/dolacmeng/JXCircleSlider

The final effect is as follows:






Getting Started with IOS custom controls: Draggable Loop Progress

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.