mirror of
				https://github.com/SoPat712/YTLitePlus.git
				synced 2025-10-30 20:34:03 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			202 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
	
	
			
		
		
	
	
			202 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
	
	
| //
 | |
| //  FHSRangeSlider.m
 | |
| //  FLEX
 | |
| //
 | |
| //  Created by Tanner Bennett on 1/7/20.
 | |
| //  Copyright © 2020 FLEX Team. All rights reserved.
 | |
| //
 | |
| 
 | |
| #import "FHSRangeSlider.h"
 | |
| #import "FLEXResources.h"
 | |
| #import "FLEXUtility.h"
 | |
| 
 | |
| @interface FHSRangeSlider ()
 | |
| @property (nonatomic, readonly) UIImageView *track;
 | |
| @property (nonatomic, readonly) UIImageView *fill;
 | |
| @property (nonatomic, readonly) UIImageView *leftHandle;
 | |
| @property (nonatomic, readonly) UIImageView *rightHandle;
 | |
| 
 | |
| @property (nonatomic, getter=isTrackingLeftHandle) BOOL trackingLeftHandle;
 | |
| @property (nonatomic, getter=isTrackingRightHandle) BOOL trackingRightHandle;
 | |
| @end
 | |
| 
 | |
| @implementation FHSRangeSlider
 | |
| 
 | |
| #pragma mark - Initialization
 | |
| 
 | |
| - (instancetype)initWithFrame:(CGRect)frame {
 | |
|     self = [super initWithFrame:frame];
 | |
|     if (self) {
 | |
|         _allowedMaxValue = 1.f;
 | |
|         _maxValue = 1.f;
 | |
|         [self initSubviews];
 | |
|     }
 | |
| 
 | |
|     return self;
 | |
| }
 | |
| 
 | |
| - (void)initSubviews {
 | |
|     self.userInteractionEnabled = YES;
 | |
|     UIImageView * (^newSubviewImageView)(UIImage *) = ^UIImageView *(UIImage *image) {
 | |
|         UIImageView *iv = [UIImageView new];
 | |
|         iv.image = image;
 | |
| //        iv.userInteractionEnabled = YES;
 | |
|         [self addSubview:iv];
 | |
|         return iv;
 | |
|     };
 | |
| 
 | |
|     _track = newSubviewImageView(FLEXResources.rangeSliderTrack);
 | |
|     _fill = newSubviewImageView(FLEXResources.rangeSliderFill);
 | |
|     _leftHandle = newSubviewImageView(FLEXResources.rangeSliderLeftHandle);
 | |
|     _rightHandle = newSubviewImageView(FLEXResources.rangeSliderRightHandle);
 | |
| }
 | |
| 
 | |
| #pragma mark - Setters / Private
 | |
| 
 | |
| - (CGFloat)valueAt:(CGFloat)x {
 | |
|     CGFloat minX = self.leftHandle.image.size.width;
 | |
|     CGFloat maxX = self.bounds.size.width - self.rightHandle.image.size.width;
 | |
|     CGFloat cappedX = MIN(MAX(x, minX), maxX);
 | |
|     CGFloat delta = maxX - minX;
 | |
|     CGFloat maxDelta = self.allowedMaxValue - self.allowedMinValue;
 | |
| 
 | |
|     return ((delta > 0) ? (cappedX - minX) / delta : 0) * maxDelta + self.allowedMinValue;
 | |
| }
 | |
| 
 | |
| - (void)setAllowedMinValue:(CGFloat)allowedMinValue {
 | |
|     _allowedMinValue = allowedMinValue;
 | |
| 
 | |
|     if (self.minValue < self.allowedMaxValue) {
 | |
|         self.minValue = self.allowedMaxValue;
 | |
|     } else {
 | |
|         [self setNeedsLayout];
 | |
|     }
 | |
| }
 | |
| 
 | |
| - (void)setAllowedMaxValue:(CGFloat)allowedMaxValue {
 | |
|     _allowedMaxValue = allowedMaxValue;
 | |
| 
 | |
|     if (self.maxValue > self.allowedMaxValue) {
 | |
|         self.maxValue = self.allowedMaxValue;
 | |
|     } else {
 | |
|         [self valuesChanged:NO];
 | |
|     }
 | |
| }
 | |
| 
 | |
| - (void)setMinValue:(CGFloat)minValue {
 | |
|     _minValue = minValue;
 | |
|     [self valuesChanged:YES];
 | |
| }
 | |
| 
 | |
| - (void)setMaxValue:(CGFloat)maxValue {
 | |
|     _maxValue = maxValue;
 | |
|     [self valuesChanged:YES];
 | |
| }
 | |
| 
 | |
| - (void)valuesChanged:(BOOL)sendActions {
 | |
|     if (NSThread.isMainThread) {
 | |
|         if (sendActions) {
 | |
|             [self sendActionsForControlEvents:UIControlEventValueChanged];
 | |
|         }
 | |
|         [self setNeedsLayout];
 | |
|     }
 | |
| }
 | |
| 
 | |
| #pragma mark - Overrides
 | |
| 
 | |
| - (CGSize)intrinsicContentSize {
 | |
|     return CGSizeMake(UIViewNoIntrinsicMetric, self.leftHandle.image.size.height);
 | |
| }
 | |
| 
 | |
| - (void)layoutSubviews {
 | |
|     [super layoutSubviews];
 | |
| 
 | |
|     CGSize lhs = self.leftHandle.image.size;
 | |
|     CGSize rhs = self.rightHandle.image.size;
 | |
|     CGSize trackSize = self.track.image.size;
 | |
| 
 | |
|     CGFloat delta = self.allowedMaxValue - self.allowedMinValue;
 | |
|     CGFloat minPercent, maxPercent;
 | |
| 
 | |
|     if (delta <= 0) {
 | |
|         minPercent = maxPercent = 0;
 | |
|     } else {
 | |
|         minPercent = MAX(0, (self.minValue - self.allowedMinValue) / delta);
 | |
|         maxPercent = MAX(minPercent, (self.maxValue - self.allowedMinValue) / delta);
 | |
|     }
 | |
| 
 | |
|     CGFloat rangeSliderWidth = self.bounds.size.width - lhs.width - rhs.width;
 | |
| 
 | |
|     self.leftHandle.frame = FLEXRectMake(
 | |
|         rangeSliderWidth * minPercent,
 | |
|         CGRectGetMidY(self.bounds) - (lhs.height / 2.f) + 3.f,
 | |
|         lhs.width,
 | |
|         lhs.height
 | |
|     );
 | |
| 
 | |
|     self.rightHandle.frame = FLEXRectMake(
 | |
|         lhs.width + (rangeSliderWidth * maxPercent),
 | |
|         CGRectGetMidY(self.bounds) - (rhs.height / 2.f) + 3.f,
 | |
|         rhs.width,
 | |
|         rhs.height
 | |
|     );
 | |
| 
 | |
|     self.track.frame = FLEXRectMake(
 | |
|         lhs.width / 2.f,
 | |
|         CGRectGetMidY(self.bounds) - trackSize.height / 2.f,
 | |
|         self.bounds.size.width - (lhs.width / 2.f) - (rhs.width / 2.f),
 | |
|         trackSize.height
 | |
|     );
 | |
| 
 | |
|     self.fill.frame = FLEXRectMake(
 | |
|         CGRectGetMidX(self.leftHandle.frame),
 | |
|         CGRectGetMinY(self.track.frame),
 | |
|         CGRectGetMidX(self.rightHandle.frame) - CGRectGetMidX(self.leftHandle.frame),
 | |
|         self.track.frame.size.height
 | |
|     );
 | |
| }
 | |
| 
 | |
| - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
 | |
|     CGPoint loc = [touch locationInView:self];
 | |
| 
 | |
|     if (CGRectContainsPoint(self.leftHandle.frame, loc)) {
 | |
|         self.trackingLeftHandle = YES;
 | |
|         self.trackingRightHandle = NO;
 | |
|     } else if (CGRectContainsPoint(self.rightHandle.frame, loc)) {
 | |
|         self.trackingLeftHandle = NO;
 | |
|         self.trackingRightHandle = YES;
 | |
|     } else {
 | |
|         return NO;
 | |
|     }
 | |
| 
 | |
|     return YES;
 | |
| }
 | |
| 
 | |
| - (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
 | |
|     CGPoint loc = [touch locationInView:self];
 | |
| 
 | |
|     if (self.isTrackingLeftHandle) {
 | |
|         self.minValue = MIN(MAX(self.allowedMinValue, [self valueAt:loc.x]), self.maxValue);
 | |
|     } else if (self.isTrackingRightHandle) {
 | |
|         self.maxValue = MAX(MIN(self.allowedMaxValue, [self valueAt:loc.x]), self.minValue);
 | |
|     } else {
 | |
|         return NO;
 | |
|     }
 | |
| 
 | |
|     [self setNeedsLayout];
 | |
|     [self layoutIfNeeded];
 | |
| 
 | |
|     return YES;
 | |
| }
 | |
| 
 | |
| - (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
 | |
|     self.trackingLeftHandle = NO;
 | |
|     self.trackingRightHandle = NO;
 | |
| }
 | |
| 
 | |
| - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
 | |
|     return NO;
 | |
| }
 | |
| 
 | |
| @end
 | 
