project_files/HedgewarsMobile/Classes/MNEValueTrackingSlider.m
changeset 6679 d8b98aa486a6
child 6700 e04da46ee43c
equal deleted inserted replaced
6678:beab48f963d5 6679:d8b98aa486a6
       
     1 //
       
     2 // MNEValueTrackingSlider
       
     3 //
       
     4 // Copyright 2011 Michael Neuwert
       
     5 // "You can use the code in your own project and modify it as you like."
       
     6 // http://blog.neuwert-media.com/2011/04/customized-uislider-with-visual-value-tracking/
       
     7 //
       
     8 
       
     9 
       
    10 #import "MNEValueTrackingSlider.h"
       
    11 
       
    12 #pragma mark -
       
    13 #pragma mark Private UIView subclass rendering the popup showing slider value
       
    14 @interface SliderValuePopupView : UIView
       
    15 @property (nonatomic, retain) UIFont *font;
       
    16 @property (nonatomic, copy) NSString *text;
       
    17 @property (nonatomic) float arrowOffset;
       
    18 @end
       
    19 
       
    20 @implementation SliderValuePopupView
       
    21 
       
    22 @synthesize font = _font;
       
    23 @synthesize text = _text;
       
    24 @synthesize arrowOffset = _arrowOffset;
       
    25 
       
    26 -(id) initWithFrame:(CGRect) frame {
       
    27     self = [super initWithFrame:frame];
       
    28     if (self) {
       
    29         self.font = [UIFont boldSystemFontOfSize:18];
       
    30     }
       
    31     return self;
       
    32 }
       
    33 
       
    34 -(void) dealloc {
       
    35     self.text = nil;
       
    36     self.font = nil;
       
    37     [super dealloc];
       
    38 }
       
    39 
       
    40 -(void) drawRect:(CGRect) rect {
       
    41     // Create the path for the rounded rectangle
       
    42     CGRect roundedRect = CGRectMake(self.bounds.origin.x, self.bounds.origin.y, self.bounds.size.width, floorf(self.bounds.size.height * 0.8));
       
    43     UIBezierPath *roundedRectPath = [UIBezierPath bezierPathWithRoundedRect:roundedRect cornerRadius:6.0];
       
    44     roundedRectPath.lineWidth = 2.0f;
       
    45 
       
    46     // Create the arrow path
       
    47     UIBezierPath *arrowPath = [UIBezierPath bezierPath];
       
    48     /*
       
    49     // Make sure the arrow offset is nice
       
    50     if (-self.arrowOffset + 1 > CGRectGetMidX(self.bounds) / 2)
       
    51         self.arrowOffset = -CGRectGetMidX(self.bounds) / 2 + 1;
       
    52     if (self.arrowOffset > CGRectGetMidX(self.bounds) / 2)
       
    53         self.arrowOffset = CGRectGetMidX(self.bounds) / 2 -1;
       
    54      */
       
    55 
       
    56     CGFloat midX = CGRectGetMidX(self.bounds) + self.arrowOffset;
       
    57     CGPoint p0 = CGPointMake(midX, CGRectGetMaxY(self.bounds));
       
    58     [arrowPath moveToPoint:p0];
       
    59     [arrowPath addLineToPoint:CGPointMake((midX - 10.0), CGRectGetMaxY(roundedRect))];
       
    60     [arrowPath addLineToPoint:CGPointMake((midX + 10.0), CGRectGetMaxY(roundedRect))];
       
    61     [arrowPath closePath];
       
    62 
       
    63     // Attach the arrow path to the rounded rect
       
    64     [roundedRectPath appendPath:arrowPath];
       
    65 
       
    66     // Color various sections
       
    67     [[UIColor blackColor] setFill];
       
    68     [roundedRectPath fill];
       
    69     [[UIColor whiteColor] setStroke];
       
    70     [roundedRectPath stroke];
       
    71     [[UIColor whiteColor] setFill];
       
    72     [arrowPath fill];
       
    73 
       
    74     // Draw the text
       
    75     if (self.text) {
       
    76         [[UIColor lightYellowColor] set];
       
    77         CGSize s = [_text sizeWithFont:self.font];
       
    78         CGFloat yOffset = (roundedRect.size.height - s.height) / 2;
       
    79         CGRect textRect = CGRectMake(roundedRect.origin.x, yOffset, roundedRect.size.width, s.height);
       
    80 
       
    81         [_text drawInRect:textRect
       
    82                  withFont:self.font
       
    83             lineBreakMode:UILineBreakModeWordWrap
       
    84                 alignment:UITextAlignmentCenter];
       
    85     }
       
    86 }
       
    87 
       
    88 @end
       
    89 
       
    90 #pragma mark -
       
    91 #pragma mark MNEValueTrackingSlider implementations
       
    92 @implementation MNEValueTrackingSlider
       
    93 
       
    94 @synthesize thumbRect, textValue;
       
    95 
       
    96 #pragma Private methods
       
    97 
       
    98 -(void) _constructSlider {
       
    99     valuePopupView = [[SliderValuePopupView alloc] initWithFrame:CGRectZero];
       
   100     valuePopupView.backgroundColor = [UIColor clearColor];
       
   101     valuePopupView.alpha = 0.0;
       
   102     [self addSubview:valuePopupView];
       
   103 }
       
   104 
       
   105 -(void) _fadePopupViewInAndOut:(BOOL)aFadeIn {
       
   106     [UIView beginAnimations:nil context:NULL];
       
   107     [UIView setAnimationDuration:0.25];
       
   108     if (aFadeIn) {
       
   109         valuePopupView.alpha = 1.0;
       
   110     } else {
       
   111         valuePopupView.alpha = 0.0;
       
   112     }
       
   113     [UIView commitAnimations];
       
   114 }
       
   115 
       
   116 -(void) _positionAndUpdatePopupView {
       
   117     CGRect _thumbRect = self.thumbRect;
       
   118     CGRect popupRect = CGRectOffset(_thumbRect, 0, -floorf(_thumbRect.size.height * 1.5));
       
   119     // (-100, -15) determines the size of the the rect
       
   120     popupRect = CGRectInset(popupRect, -100, -15);
       
   121 
       
   122     // this prevents drawing the popup outside the slider view
       
   123     if (popupRect.origin.x < -self.frame.origin.x+5)
       
   124         popupRect.origin.x = -self.frame.origin.x+5;
       
   125     else if (popupRect.origin.x > self.superview.frame.size.width - popupRect.size.width - self.frame.origin.x - 5)
       
   126         popupRect.origin.x = self.superview.frame.size.width - popupRect.size.width - self.frame.origin.x - 5;
       
   127     //else if (CGRectGetMaxX(popupRect) > CGRectGetMaxX(self.superview.bounds))
       
   128     //    popupRect.origin.x = CGRectGetMaxX(self.superview.bounds) - CGRectGetWidth(popupRect) - 1.0;
       
   129 
       
   130     valuePopupView.arrowOffset = CGRectGetMidX(_thumbRect) - CGRectGetMidX(popupRect);
       
   131 
       
   132     valuePopupView.frame = popupRect;
       
   133     valuePopupView.text = self.textValue;
       
   134     [valuePopupView setNeedsDisplay];
       
   135 }
       
   136 
       
   137 #pragma mark Memory management
       
   138 
       
   139 -(id) initWithFrame:(CGRect) frame {
       
   140     self = [super initWithFrame:frame];
       
   141     if (self) {
       
   142         [self _constructSlider];
       
   143     }
       
   144     return self;
       
   145 }
       
   146 
       
   147 -(id) initWithCoder:(NSCoder *)aDecoder {
       
   148     self = [super initWithCoder:aDecoder];
       
   149     if (self) {
       
   150         [self _constructSlider];
       
   151     }
       
   152     return self;
       
   153 }
       
   154 
       
   155 -(void) dealloc {
       
   156     [valuePopupView release];
       
   157     [textValue release];
       
   158     [super dealloc];
       
   159 }
       
   160 
       
   161 #pragma mark -
       
   162 #pragma mark UIControl touch event tracking
       
   163 -(BOOL) beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
       
   164     // Fade in and update the popup view
       
   165     CGPoint touchPoint = [touch locationInView:self];
       
   166     // Check if the knob is touched. Only in this case show the popup-view
       
   167     if(CGRectContainsPoint(CGRectInset(self.thumbRect, -14.0, -12.0), touchPoint)) {
       
   168         [self _positionAndUpdatePopupView];
       
   169         [self _fadePopupViewInAndOut:YES];
       
   170     }
       
   171     return [super beginTrackingWithTouch:touch withEvent:event];
       
   172 }
       
   173 
       
   174 -(BOOL) continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
       
   175     // Update the popup view as slider knob is being moved
       
   176     [self _positionAndUpdatePopupView];
       
   177     return [super continueTrackingWithTouch:touch withEvent:event];
       
   178 }
       
   179 
       
   180 -(void) cancelTrackingWithEvent:(UIEvent *)event {
       
   181     [super cancelTrackingWithEvent:event];
       
   182 }
       
   183 
       
   184 -(void) endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
       
   185     // Fade out the popoup view
       
   186     [self _fadePopupViewInAndOut:NO];
       
   187     [super endTrackingWithTouch:touch withEvent:event];
       
   188 }
       
   189 
       
   190 #pragma mark -
       
   191 #pragma mark Custom property accessors
       
   192 -(CGRect) thumbRect {
       
   193     CGRect trackRect = [self trackRectForBounds:self.bounds];
       
   194     CGRect thumbR = [self thumbRectForBounds:self.bounds
       
   195                                          trackRect:trackRect
       
   196                                              value:self.value];
       
   197     return thumbR;
       
   198 }
       
   199 
       
   200 @end