Skip to content

Commit

Permalink
[Slider] Allowing Full Haptics for Discrete Sliders (#7765)
Browse files Browse the repository at this point in the history
* haptics for slider

* updating formatting and style for slider haptics

* updated formatting for slider tests

* updating slider test name

* adding full haptics option for discrete sliders

* updated formatting for full haptics

* updating full haptics

* updating formatting for discrete haptics

* fixing formating
  • Loading branch information
afweiss authored and yarneo committed Jul 9, 2019
1 parent 4ed8860 commit 46efae7
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 5 deletions.
11 changes: 11 additions & 0 deletions components/Slider/examples/SliderCollectionViewController.m
Expand Up @@ -40,6 +40,7 @@ @interface MDCSliderModel : NSObject
@property(nonatomic, assign) BOOL hollowCircle;
@property(nonatomic, assign) BOOL enabled;
@property(nonatomic, assign) BOOL hapticsEnabled;
@property(nonatomic, assign) BOOL shouldEnableHapticsForAllDiscreteValues;

- (void)didChangeMDCSliderValue:(MDCSlider *)slider;

Expand All @@ -62,6 +63,7 @@ - (instancetype)init {
_hollowCircle = YES;
_enabled = YES;
_hapticsEnabled = YES;
_shouldEnableHapticsForAllDiscreteValues = NO;
}

return self;
Expand Down Expand Up @@ -109,6 +111,7 @@ - (void)applyModel:(MDCSliderModel *)model withColorScheme:(MDCSemanticColorSche
_slider.thumbHollowAtStart = model.hollowCircle;
_slider.enabled = model.enabled;
_slider.hapticsEnabled = model.hapticsEnabled;
_slider.shouldEnableHapticsForAllDiscreteValues = model.shouldEnableHapticsForAllDiscreteValues;

// Don't apply a `nil` color, use the default
if (model.sliderColor) {
Expand Down Expand Up @@ -251,6 +254,14 @@ - (instancetype)init {
model.discreteValueLabel = NO;
[_sliders addObject:model];

model = [[MDCSliderModel alloc] init];
model.labelString = @"Discrete slider with full haptics";
model.numDiscreteValues = 5;
model.value = 1;
model.discreteValueLabel = NO;
model.shouldEnableHapticsForAllDiscreteValues = YES;
[_sliders addObject:model];

model = [[MDCSliderModel alloc] init];
model.labelString = @"Dark themed slider";
model.labelColor = [UIColor whiteColor];
Expand Down
12 changes: 10 additions & 2 deletions components/Slider/src/MDCSlider.h
Expand Up @@ -335,13 +335,21 @@ IB_DESIGNABLE
*/
@property(nonatomic, strong, null_resettable) UIColor *trackBackgroundColor UI_APPEARANCE_SELECTOR;

/** When @c YES, haptics are enabled. The haptics casue a light impact reaction when the slider
reaches the minimum or maximum value.
/** When @c YES, haptics for min and max are enabled. The haptics casue a light impact reaction when
the slider reaches the minimum or maximum value.
Defaults to @c YES in iOS 10 or later, @c NO otherwise
*/
@property(nonatomic, assign) BOOL hapticsEnabled;

/** When @c YES, haptics for any value change are enabled for discrete sliders. The haptics casue
a light impact reaction when the slider value changes for discrete sliders. Can only be set to yes
for discrete sliders. Haptics will only occur if hapticsEnabled is also set to @c YES.
Defaults to @c NO
*/
@property(nonatomic, assign) BOOL shouldEnableHapticsForAllDiscreteValues;

@end

@interface MDCSlider (ToBeDeprecated)
Expand Down
18 changes: 15 additions & 3 deletions components/Slider/src/MDCSlider.m
Expand Up @@ -114,6 +114,7 @@ - (void)commonMDCSliderInit {
} else {
_hapticsEnabled = NO;
}
_shouldEnableHapticsForAllDiscreteValues = NO;
}

#pragma mark - Color customization methods
Expand Down Expand Up @@ -332,6 +333,14 @@ - (void)setHapticsEnabled:(BOOL)hapticsEnabled {
}
}

- (void)setShouldEnableHapticsForAllDiscreteValues:(BOOL)shouldEnableHapticsForAllDiscreteValues {
if (@available(iOS 10.0, *)) {
if (_thumbTrack.numDiscreteValues >= 2) {
_shouldEnableHapticsForAllDiscreteValues = shouldEnableHapticsForAllDiscreteValues;
}
}
}

- (void)setInkColor:(UIColor *)inkColor {
_thumbTrack.inkColor = inkColor;
}
Expand Down Expand Up @@ -544,9 +553,12 @@ - (void)thumbTrackValueChanged:(__unused MDCThumbTrack *)thumbTrack {
[self sendActionsForControlEvents:UIControlEventValueChanged];
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, self.accessibilityValue);
if (@available(iOS 10.0, *)) {
if (self.hapticsEnabled && (_thumbTrack.value == _thumbTrack.minimumValue ||
_thumbTrack.value == _thumbTrack.maximumValue)) {
[self.feedbackGenerator impactOccurred];
if (self.hapticsEnabled) {
if (self.shouldEnableHapticsForAllDiscreteValues ||
_thumbTrack.value == _thumbTrack.minimumValue ||
_thumbTrack.value == _thumbTrack.maximumValue) {
[self.feedbackGenerator impactOccurred];
}
}
}
}
Expand Down
79 changes: 79 additions & 0 deletions components/Slider/tests/unit/SliderTests.m
Expand Up @@ -1117,6 +1117,35 @@ - (void)testDefaultHapticsEnabledValue {
}
}

- (void)testDefaultsSouldEnableHapticsForAllDiscreteValuesValue {
if (@available(iOS 10.0, *)) {
for (NSUInteger i = 0; i < 5; ++i) {
// When
self.slider.numberOfDiscreteValues = i;

// Then
XCTAssertFalse(self.slider.shouldEnableHapticsForAllDiscreteValues);
}
}
}

- (void)testSettingshouldEnableHapticsForAllDiscreteValuesValue {
if (@available(iOS 10.0, *)) {
for (NSUInteger i = 0; i < 5; ++i) {
// When
self.slider.numberOfDiscreteValues = i;
self.slider.shouldEnableHapticsForAllDiscreteValues = YES;

// Then
if (i == 0 || i == 1) {
XCTAssertFalse(self.slider.shouldEnableHapticsForAllDiscreteValues);
} else {
XCTAssertTrue(self.slider.shouldEnableHapticsForAllDiscreteValues);
}
}
}
}

- (void)testEnabledHapticFeedback {
// Given
self.slider.minimumValue = 0;
Expand Down Expand Up @@ -1166,6 +1195,56 @@ - (void)testNotEnabledHapticFeedback {
}
}

- (void)testEnabledFullHapticNotEnabledHapticFeedback {
// Given
self.slider.minimumValue = 0;
self.slider.maximumValue = 5;
self.slider.hapticsEnabled = NO;
self.slider.numberOfDiscreteValues = 2;
self.slider.shouldEnableHapticsForAllDiscreteValues = YES;

if (@available(iOS 10.0, *)) {
_mockFeedbackGenerator = [[MockUIImpactFeedbackGenerator alloc] init];
self.slider.feedbackGenerator = _mockFeedbackGenerator;
for (NSUInteger i = 0; i < 6; ++i) {
self.slider.value = i;

// When
[self.slider thumbTrackValueChanged:self.slider.thumbTrack];

// Then
XCTAssertFalse(_mockFeedbackGenerator.impactHasOccurred);

_mockFeedbackGenerator.impactHasOccurred = NO;
}
}
}

- (void)testEnabledFullHapticFeedback {
// Given
self.slider.minimumValue = 0;
self.slider.maximumValue = 5;
self.slider.hapticsEnabled = YES;
self.slider.numberOfDiscreteValues = 2;
self.slider.shouldEnableHapticsForAllDiscreteValues = YES;

if (@available(iOS 10.0, *)) {
_mockFeedbackGenerator = [[MockUIImpactFeedbackGenerator alloc] init];
self.slider.feedbackGenerator = _mockFeedbackGenerator;
for (NSUInteger i = 0; i < 6; ++i) {
self.slider.value = i;

// When
[self.slider thumbTrackValueChanged:self.slider.thumbTrack];

// Then
XCTAssertTrue(_mockFeedbackGenerator.impactHasOccurred);

_mockFeedbackGenerator.impactHasOccurred = NO;
}
}
}

#pragma mark Private test helpers

- (CGFloat)randomNumber {
Expand Down

0 comments on commit 46efae7

Please sign in to comment.