Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import Slider from '@react-native-community/slider';
maximumValue={1}
minimumTrackTintColor="#FFFFFF"
maximumTrackTintColor="#000000"
thumbSize={32}
/>
```

Expand Down Expand Up @@ -93,6 +94,7 @@ To use this library you need to ensure you are using the correct version of Reac
| `inverted` | Reverses the direction of the slider.<br/>Default value is false. | bool | |
| `vertical` | Changes the orientation of the slider to vertical, if set to `true`.<br/>Default value is false. | bool | Windows |
| `thumbTintColor` | Color of the foreground switch grip.<br/>**NOTE:** This prop will override the `thumbImage` prop set, meaning that if both `thumbImage` and `thumbTintColor` will be set, image used for the thumb may not be displayed correctly! | [color](https://reactnative.dev/docs/colors) | Android |
| `thumbSize` | Sets the size (width and height) of the thumb.<br/>If `thumbImage` is provided, it will be scaled to this size.<br/>Units: points on iOS, dp on Android. | number | Android, iOS, Web |
| `maximumTrackImage` | Assigns a maximum track image. Only static images are supported. The leftmost pixel of the image will be stretched to fill the track. | Image<br/>.propTypes<br/>.source | iOS |
| `minimumTrackImage` | Assigns a minimum track image. Only static images are supported. The rightmost pixel of the image will be stretched to fill the track. | Image<br/>.propTypes<br/>.source | iOS |
| `thumbImage` | Sets an image for the thumb. Only static images are supported. Needs to be a URI of a local or network image; base64-encoded SVG is not supported. | Image<br/>.propTypes<br/>.source | |
Expand Down
17 changes: 17 additions & 0 deletions example/src/Examples.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -744,4 +744,21 @@ export const examples: Props[] = [
return <SliderExample disabled value={0.6} />;
},
},
{
title: 'Custom thumb size (no image)',
render() {
return <SliderExample thumbTintColor={'blue'} thumbSize={32} />;
},
},
{
title: 'Custom thumb size (scaled image)',
render() {
return (
<SliderExample
thumbImage={require('./resources/uie_thumb_big.png')}
thumbSize={60}
/>
);
},
},
];
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.util.Log;
Expand Down Expand Up @@ -74,6 +77,15 @@ public class ReactSlider extends AppCompatSeekBar {
/** Upper limit based on the SeekBar progress 0..total steps */
private int mUpperLimit;

/** Thumb size in pixels (0 = default) */
private int mThumbSizePx = 0;

/** Original thumb drawable URI */
@Nullable private String mThumbImageUri = null;

/** Cached thumb tint color */
@Nullable private Integer mThumbTintColor = null;

public ReactSlider(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
Expand Down Expand Up @@ -299,15 +311,88 @@ public BitmapDrawable call() {
return bitmapDrawable;
}

public void setThumbImage(final String uri) {
if (uri != null) {
setThumb(getBitmapDrawable(uri));
// Enable alpha channel for the thumbImage
public void setThumbImage(@Nullable final String uri) {
mThumbImageUri = uri;
updateThumbImage();
}

public void setThumbSize(final double size) {
float density = getResources().getDisplayMetrics().density;
mThumbSizePx = size > 0 ? Math.round((float) size * density) : 0;
Comment thread
BartoszKlonowski marked this conversation as resolved.
Outdated
updateThumbImage();
}

public void setThumbTintColor(@Nullable final Integer color) {
mThumbTintColor = color;
if (mThumbImageUri != null || mThumbSizePx > 0) {
updateThumbImage();
} else {
applyThumbTintColorFilter();
}
}

private void applyThumbTintColorFilter() {
if (getThumb() == null) {
return;
}

if (mThumbTintColor != null) {
getThumb().setColorFilter(mThumbTintColor, PorterDuff.Mode.SRC_IN);
} else {
getThumb().clearColorFilter();
}
}

private void updateThumbImage() {
if (mThumbImageUri != null) {
BitmapDrawable drawable = getBitmapDrawable(mThumbImageUri);
if (drawable != null) {
if (mThumbSizePx > 0) {
Bitmap originalBitmap = drawable.getBitmap();
Bitmap scaledBitmap =
Bitmap.createScaledBitmap(originalBitmap, mThumbSizePx, mThumbSizePx, true);
setThumb(new BitmapDrawable(getResources(), scaledBitmap));
} else {
setThumb(drawable);
}
applyThumbTintColorFilter();
// Enable alpha channel for the thumbImage
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setSplitTrack(false);
}
return;
}
}

if (mThumbSizePx > 0) {
Bitmap bitmap = Bitmap.createBitmap(mThumbSizePx, mThumbSizePx, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);

int fillColor =
mThumbTintColor != null
? mThumbTintColor
: (getThumbTintList() != null ? getThumbTintList().getDefaultColor() : 0xFFFFFFFF);

Paint fillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
fillPaint.setStyle(Paint.Style.FILL);
fillPaint.setColor(fillColor);
float radius = mThumbSizePx / 2f;
canvas.drawCircle(radius, radius, radius, fillPaint);

Paint strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
strokePaint.setStyle(Paint.Style.STROKE);
strokePaint.setStrokeWidth(1);
strokePaint.setColor(0x1A000000);
canvas.drawCircle(radius, radius, radius - 0.5f, strokePaint);

setThumb(new BitmapDrawable(getResources(), bitmap));
applyThumbTintColorFilter();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setSplitTrack(false);
}
} else {
setThumb(getThumb());
// No special sizing; keep existing thumb, only apply tint if needed.
applyThumbTintColorFilter();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ public void setThumbTintColor(ReactSlider view, Integer color) {
ReactSliderManagerImpl.setThumbTintColor(view, color);
}

@Override
@ReactProp(name = "thumbSize", defaultFloat = 0f)
public void setThumbSize(ReactSlider view, double size) {
Comment thread
BartoszKlonowski marked this conversation as resolved.
Outdated
ReactSliderManagerImpl.setThumbSize(view, size);
}

@Override
@ReactProp(name = "minimumTrackTintColor", customType = "Color")
public void setMinimumTrackTintColor(ReactSlider view, Integer color) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,7 @@ public static void setDisabled(ReactSlider view, boolean disabled) {
}

public static void setThumbTintColor(ReactSlider view, Integer color) {
if (view.getThumb() != null) {
if (color == null) {
view.getThumb().clearColorFilter();
} else {
view.getThumb().setColorFilter(color, PorterDuff.Mode.SRC_IN);
}
}
view.setThumbTintColor(color);
}

public static void setMinimumTrackTintColor(ReactSlider view, Integer color) {
Expand All @@ -101,6 +95,10 @@ public static void setThumbImage(ReactSlider view, @Nullable ReadableMap source)
view.setThumbImage(uri);
}

public static void setThumbSize(ReactSlider view, double size) {
Comment thread
BartoszKlonowski marked this conversation as resolved.
Outdated
view.setThumbSize(size);
}

public static void setMaximumTrackTintColor(ReactSlider view, Integer color) {
LayerDrawable drawable = (LayerDrawable) view.getProgressDrawable().getCurrent();
Drawable background = drawable.findDrawableByLayerId(android.R.id.background);
Expand Down
2 changes: 2 additions & 0 deletions package/ios/RNCSlider.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
@property (nonatomic, strong) UIImage *minimumTrackImage;
@property (nonatomic, strong) UIImage *maximumTrackImage;
@property (nonatomic, strong) UIImage *thumbImage;
@property (nonatomic, assign) CGFloat thumbSize;
@property (nonatomic, assign) bool tapToSeek;
@property (nonatomic, strong) NSString *accessibilityUnits;
@property (nonatomic, strong) NSArray *accessibilityIncrements;

- (float) discreteValue:(float)value;
- (void) setDisabled:(bool)disabled;
- (void) updateThumbImage;

@end
47 changes: 46 additions & 1 deletion package/ios/RNCSlider.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ @implementation RNCSlider
float _unclippedValue;
bool _minimumTrackImageSet;
bool _maximumTrackImageSet;
UIImage *_thumbImage;
CGFloat _thumbSize;
}

- (instancetype)init {
Expand Down Expand Up @@ -116,14 +118,57 @@ - (UIImage *)maximumTrackImage

- (void)setThumbImage:(UIImage *)thumbImage
{
[self setThumbImage:thumbImage forState:UIControlStateNormal];
_thumbImage = thumbImage;
[self updateThumbImage];
}

- (UIImage *)thumbImage
{
return [self thumbImageForState:UIControlStateNormal];
}

- (void)setThumbSize:(CGFloat)thumbSize
{
_thumbSize = thumbSize;
[self updateThumbImage];
}

- (void)updateThumbImage
{
UIImage *imageToSet = nil;

if (_thumbSize > 0) {
CGSize newSize = CGSizeMake(_thumbSize, _thumbSize);
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();

if (_thumbImage) {
[_thumbImage drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
} else {
UIColor *fillColor = self.thumbTintColor ?: [UIColor whiteColor];
CGContextSetFillColorWithColor(context, fillColor.CGColor);
CGContextFillEllipseInRect(context, CGRectMake(0, 0, newSize.width, newSize.height));

CGContextSetStrokeColorWithColor(context, [[UIColor colorWithWhite:0.0 alpha:0.1] CGColor]);
CGContextSetLineWidth(context, 0.5);
CGContextStrokeEllipseInRect(
context,
CGRectMake(0.25, 0.25, newSize.width - 0.5, newSize.height - 0.5));
}

imageToSet = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
} else if (_thumbImage) {
imageToSet = _thumbImage;
}

if (imageToSet) {
[self setThumbImage:imageToSet forState:UIControlStateNormal];
[self setThumbImage:imageToSet forState:UIControlStateHighlighted];
[self setThumbImage:imageToSet forState:UIControlStateSelected];
}
}

- (void)setInverted:(BOOL)inverted
{
if (inverted) {
Expand Down
1 change: 1 addition & 0 deletions package/ios/RNCSliderComponentView.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ typedef void (^RNCLoadImageFailureBlock)();
@property (nonatomic, strong) UIImage *minimumTrackImage;
@property (nonatomic, strong) UIImage *maximumTrackImage;
@property (nonatomic, strong) UIImage *thumbImage;
@property (nonatomic, assign) CGFloat thumbSize;
@property (nonatomic, assign) bool tapToSeek;
@property (nonatomic, strong) NSString *accessibilityUnits;
@property (nonatomic, strong) NSArray *accessibilityIncrements;
Expand Down
6 changes: 6 additions & 0 deletions package/ios/RNCSliderComponentView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &
if (oldScreenProps.thumbTintColor != newScreenProps.thumbTintColor) {
slider.thumbTintColor = RCTUIColorFromSharedColor(newScreenProps.thumbTintColor);
}
if (oldScreenProps.thumbSize != newScreenProps.thumbSize) {
slider.thumbSize = newScreenProps.thumbSize;
}
if (oldScreenProps.minimumTrackTintColor != newScreenProps.minimumTrackTintColor) {
slider.minimumTrackTintColor = RCTUIColorFromSharedColor(newScreenProps.minimumTrackTintColor);
}
Expand Down Expand Up @@ -236,6 +239,9 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &
[self->slider setThumbImage:nil];
}];
}
if (oldScreenProps.thumbTintColor != newScreenProps.thumbTintColor && slider.thumbSize > 0) {
Comment thread
bdtren marked this conversation as resolved.
Outdated
[slider updateThumbImage];
}
if (oldScreenProps.trackImage != newScreenProps.trackImage) {
[self loadImageFromImageSource:newScreenProps.trackImage completionBlock:^(NSError *error, UIImage *image) {
dispatch_async(dispatch_get_main_queue(), ^{
Expand Down
5 changes: 5 additions & 0 deletions package/src/RNCSliderNativeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ export interface NativeProps extends ViewProps {
testID?: string;
thumbImage?: ImageSource;
thumbTintColor?: ColorValue;
/**
* Sets the size (width and height) of the thumb, in points (dp on Android).
* If you also set `thumbImage`, the image will be scaled to this size.
*/
Comment thread
bdtren marked this conversation as resolved.
Outdated
thumbSize?: Double;
Comment thread
BartoszKlonowski marked this conversation as resolved.
Outdated
trackImage?: ImageSource;
value?: Float;
lowerLimit?: Float;
Expand Down
7 changes: 7 additions & 0 deletions package/src/Slider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,12 @@ type Props = ViewProps &
*/
thumbImage?: ImageSource;

/**
* Sets the size (width and height) of the thumb.
* If `thumbImage` is provided, it will be scaled to this size.
*/
thumbSize?: number;

/**
* If true the slider will be inverted.
* Default value is false.
Expand Down Expand Up @@ -340,6 +346,7 @@ const SliderComponent = (
? 'transparent'
: props.thumbTintColor
}
thumbSize={props.thumbSize}
Comment thread
bdtren marked this conversation as resolved.
Outdated
/>
</View>
);
Expand Down
12 changes: 12 additions & 0 deletions package/typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ export interface SliderPropsIOS extends ReactNative.ViewProps {
*/
thumbImage?: ReactNative.ImageURISource;

/**
* Sets the size (width and height) of the thumb.
* If `thumbImage` is provided, it will be scaled to this size.
*/
thumbSize?: number;

Comment thread
bdtren marked this conversation as resolved.
Outdated
/**
* Assigns a single image for the track. Only static images
* are supported. The center pixel of the image will be stretched
Expand Down Expand Up @@ -166,6 +172,12 @@ export interface SliderProps
*/
inverted?: boolean;

/**
* Sets the size (width and height) of the thumb.
* If `thumbImage` is provided, it will be scaled to this size.
*/
thumbSize?: number;

/**
* Component to be rendered for each step indicator.
*/
Expand Down
Loading