1/** 2 * Copyright (c) Facebook, Inc. and its affiliates. 3 * 4 * This source code is licensed under the MIT license found in the 5 * LICENSE file in the root directory of this source tree. 6 */ 7 8#import "RNCSlider.h" 9 10@implementation RNCSlider 11{ 12 float _unclippedValue; 13 bool _minimumTrackImageSet; 14 bool _maximumTrackImageSet; 15} 16 17- (instancetype)initWithFrame:(CGRect)frame 18{ 19 return [super initWithFrame:frame]; 20} 21 22- (void)setValue:(float)value 23{ 24 value = [self discreteValue:value]; 25 _unclippedValue = value; 26 super.value = value; 27 [self setupAccessibility:value]; 28} 29 30- (void)setValue:(float)value animated:(BOOL)animated 31{ 32 value = [self discreteValue:value]; 33 _unclippedValue = value; 34 [super setValue:value animated:animated]; 35 [self setupAccessibility:value]; 36} 37 38- (void)setupAccessibility:(float)value 39{ 40 if (self.accessibilityUnits && self.accessibilityIncrements && [self.accessibilityIncrements count] - 1 == (int)self.maximumValue) { 41 int index = (int)value; 42 NSString *sliderValue = (NSString *)[self.accessibilityIncrements objectAtIndex:index]; 43 NSUInteger stringLength = [self.accessibilityUnits length]; 44 45 NSString *spokenUnits = [NSString stringWithString:self.accessibilityUnits]; 46 if (sliderValue && [sliderValue intValue] == 1) { 47 spokenUnits = [spokenUnits substringToIndex:stringLength-1]; 48 } 49 50 self.accessibilityValue = [NSString stringWithFormat:@"%@ %@", sliderValue, spokenUnits]; 51 } 52} 53 54- (void)setMinimumValue:(float)minimumValue 55{ 56 super.minimumValue = minimumValue; 57 super.value = _unclippedValue; 58} 59 60- (void)setMaximumValue:(float)maximumValue 61{ 62 super.maximumValue = maximumValue; 63 super.value = _unclippedValue; 64} 65 66- (void)setTrackImage:(UIImage *)trackImage 67{ 68 if (trackImage != _trackImage) { 69 _trackImage = trackImage; 70 CGFloat width = trackImage.size.width / 2; 71 if (!_minimumTrackImageSet) { 72 UIImage *minimumTrackImage = [trackImage resizableImageWithCapInsets:(UIEdgeInsets){ 73 0, width, 0, width 74 } resizingMode:UIImageResizingModeStretch]; 75 [self setMinimumTrackImage:minimumTrackImage forState:UIControlStateNormal]; 76 } 77 if (!_maximumTrackImageSet) { 78 UIImage *maximumTrackImage = [trackImage resizableImageWithCapInsets:(UIEdgeInsets){ 79 0, width, 0, width 80 } resizingMode:UIImageResizingModeStretch]; 81 [self setMaximumTrackImage:maximumTrackImage forState:UIControlStateNormal]; 82 } 83 } 84} 85 86- (void)setMinimumTrackImage:(UIImage *)minimumTrackImage 87{ 88 _trackImage = nil; 89 _minimumTrackImageSet = true; 90 minimumTrackImage = [minimumTrackImage resizableImageWithCapInsets:(UIEdgeInsets){ 91 0, minimumTrackImage.size.width, 0, 0 92 } resizingMode:UIImageResizingModeStretch]; 93 [self setMinimumTrackImage:minimumTrackImage forState:UIControlStateNormal]; 94} 95 96- (UIImage *)minimumTrackImage 97{ 98 return [self thumbImageForState:UIControlStateNormal]; 99} 100 101- (void)setMaximumTrackImage:(UIImage *)maximumTrackImage 102{ 103 _trackImage = nil; 104 _maximumTrackImageSet = true; 105 maximumTrackImage = [maximumTrackImage resizableImageWithCapInsets:(UIEdgeInsets){ 106 0, 0, 0, maximumTrackImage.size.width 107 } resizingMode:UIImageResizingModeStretch]; 108 [self setMaximumTrackImage:maximumTrackImage forState:UIControlStateNormal]; 109} 110 111- (UIImage *)maximumTrackImage 112{ 113 return [self thumbImageForState:UIControlStateNormal]; 114} 115 116- (void)setThumbImage:(UIImage *)thumbImage 117{ 118 [self setThumbImage:thumbImage forState:UIControlStateNormal]; 119} 120 121- (UIImage *)thumbImage 122{ 123 return [self thumbImageForState:UIControlStateNormal]; 124} 125 126- (void)setInverted:(BOOL)inverted 127{ 128 if (inverted) { 129 self.transform = CGAffineTransformMakeScale(-1, 1); 130 } else { 131 self.transform = CGAffineTransformMakeScale(1, 1); 132 } 133} 134 135- (void)setDisabled:(BOOL)disabled 136{ 137 self.enabled = !disabled; 138 [self layoutSubviews]; 139} 140 141- (float)discreteValue:(float)value 142{ 143 if (self.step > 0 && value >= self.maximumValue) { 144 return self.maximumValue; 145 } 146 147 if (self.step > 0 && self.step <= (self.maximumValue - self.minimumValue)) { 148 double (^_round)(double) = ^(double x) { 149 if (!UIAccessibilityIsVoiceOverRunning()) { 150 return round(x); 151 } else if (self.lastValue > value) { 152 return floor(x); 153 } else { 154 return ceil(x); 155 } 156 }; 157 158 return MAX(self.minimumValue, 159 MIN(self.maximumValue, self.minimumValue + _round((value - self.minimumValue) / self.step) * self.step) 160 ); 161 } 162 163 return value; 164} 165 166@end 167