Support image props for Slider component, feature parity with pre-Fabric Slider

Summary: The biggest change is that (1) the image proxy/observer code from the Image component has been generalized, (2) the four image props for the Slider component are fully supported, (3) a handful of props that were ignored or buggy on iOS now perform as expected.

Reviewed By: shergin

Differential Revision: D13954892

fbshipit-source-id: bec8ad3407c39a1cb186d9541a73b509dccc92ce
This commit is contained in:
Joshua Gross 2019-02-05 17:26:34 -08:00 коммит произвёл Facebook Github Bot
Родитель 7f646a5b68
Коммит b6318acbab
14 изменённых файлов: 686 добавлений и 73 удалений

Просмотреть файл

@ -5,20 +5,11 @@
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <React/RCTViewComponentView.h>
#import "RCTViewComponentView.h"
#import <React/RCTImageResponseDelegate.h>
NS_ASSUME_NONNULL_BEGIN
@protocol RCTImageResponseDelegate <NSObject>
- (void)didReceiveImage:(UIImage *)image fromObserver:(void*)observer;
- (void)didReceiveProgress:(float)progress fromObserver:(void*)observer;
- (void)didReceiveFailureFromObserver:(void*)observer;
@end
/**
* UIView class for root <Image> component.
*/

Просмотреть файл

@ -12,49 +12,17 @@
#import <react/components/image/ImageProps.h>
#import <react/components/image/ImageShadowNode.h>
#import <react/imagemanager/ImageRequest.h>
#import <react/imagemanager/ImageResponse.h>
#import <react/imagemanager/ImageResponseObserver.h>
#import <react/imagemanager/RCTImagePrimitivesConversions.h>
#import <React/RCTImageResponseObserverProxy.h>
#import "RCTConversions.h"
#import "MainQueueExecutor.h"
using namespace facebook::react;
class ImageResponseObserverProxy: public ImageResponseObserver {
public:
ImageResponseObserverProxy(void* delegate): delegate_((__bridge id<RCTImageResponseDelegate>)delegate) {}
void didReceiveImage(const ImageResponse &imageResponse) override {
UIImage *image = (__bridge UIImage *)imageResponse.getImage().get();
void *this_ = this;
dispatch_async(dispatch_get_main_queue(), ^{
[delegate_ didReceiveImage:image fromObserver:this_];
});
}
void didReceiveProgress (float p) override {
void *this_ = this;
dispatch_async(dispatch_get_main_queue(), ^{
[delegate_ didReceiveProgress:p fromObserver:this_];
});
}
void didReceiveFailure() override {
void *this_ = this;
dispatch_async(dispatch_get_main_queue(), ^{
[delegate_ didReceiveFailureFromObserver:this_];
});
}
private:
id<RCTImageResponseDelegate> delegate_;
};
@implementation RCTImageComponentView {
UIImageView *_imageView;
SharedImageLocalData _imageLocalData;
std::shared_ptr<const ImageResponseObserverCoordinator> _coordinator;
std::unique_ptr<ImageResponseObserverProxy> _imageResponseObserverProxy;
std::unique_ptr<RCTImageResponseObserverProxy> _imageResponseObserverProxy;
}
- (instancetype)initWithFrame:(CGRect)frame
@ -68,7 +36,7 @@ private:
_imageView.contentMode = (UIViewContentMode)RCTResizeModeFromImageResizeMode(defaultProps->resizeMode);
_imageResponseObserverProxy = std::make_unique<ImageResponseObserverProxy>((__bridge void *)self);
_imageResponseObserverProxy = std::make_unique<RCTImageResponseObserverProxy>((__bridge void *)self);
self.contentView = _imageView;
}
@ -110,12 +78,18 @@ private:
- (void)updateLocalData:(SharedLocalData)localData
oldLocalData:(SharedLocalData)oldLocalData
{
SharedImageLocalData previousData = _imageLocalData;
_imageLocalData = std::static_pointer_cast<const ImageLocalData>(localData);
assert(_imageLocalData);
self.coordinator = _imageLocalData->getImageRequest().getObserverCoordinator();
bool havePreviousData = previousData != nullptr;
// Loading actually starts a little before this
std::static_pointer_cast<const ImageEventEmitter>(_eventEmitter)->onLoadStart();
if (!havePreviousData || _imageLocalData->getImageSource() != previousData->getImageSource()) {
self.coordinator = _imageLocalData->getImageRequest().getObserverCoordinator();
// Loading actually starts a little before this, but this is the first time we know
// the image is loading and can fire an event from this component
std::static_pointer_cast<const ImageEventEmitter>(_eventEmitter)->onLoadStart();
}
}
- (void)setCoordinator:(std::shared_ptr<const ImageResponseObserverCoordinator>)coordinator {

Просмотреть файл

@ -10,12 +10,31 @@
#import <react/components/slider/SliderEventEmitter.h>
#import <react/components/slider/SliderProps.h>
#import <react/components/slider/SliderShadowNode.h>
#import <react/components/slider/SliderLocalData.h>
#import <React/RCTImageResponseObserverProxy.h>
#import "MainQueueExecutor.h"
using namespace facebook::react;
@implementation RCTSliderComponentView {
UISlider *_sliderView;
float _prevValue;
float _previousValue;
SharedSliderLocalData _sliderLocalData;
UIImage *_trackImage;
UIImage *_minimumTrackImage;
UIImage *_maximumTrackImage;
UIImage *_thumbImage;
std::shared_ptr<const ImageResponseObserverCoordinator> _trackImageCoordinator;
std::unique_ptr<RCTImageResponseObserverProxy> _trackImageResponseObserverProxy;
std::shared_ptr<const ImageResponseObserverCoordinator> _minimumTrackImageCoordinator;
std::unique_ptr<RCTImageResponseObserverProxy> _minimumTrackImageResponseObserverProxy;
std::shared_ptr<const ImageResponseObserverCoordinator> _maximumTrackImageCoordinator;
std::unique_ptr<RCTImageResponseObserverProxy> _maximumTrackImageResponseObserverProxy;
std::shared_ptr<const ImageResponseObserverCoordinator> _thumbImageCoordinator;
std::unique_ptr<RCTImageResponseObserverProxy> _thumbImageResponseObserverProxy;
}
- (instancetype)initWithFrame:(CGRect)frame
@ -29,9 +48,19 @@ using namespace facebook::react;
[_sliderView addTarget:self
action:@selector(onChange:)
forControlEvents:UIControlEventValueChanged];
[_sliderView addTarget:self
action:@selector(sliderTouchEnd:)
forControlEvents:(UIControlEventTouchUpInside |
UIControlEventTouchUpOutside |
UIControlEventTouchCancel)];
_sliderView.value = defaultProps->value;
_trackImageResponseObserverProxy = std::make_unique<RCTImageResponseObserverProxy>((__bridge void *)self);
_minimumTrackImageResponseObserverProxy = std::make_unique<RCTImageResponseObserverProxy>((__bridge void *)self);
_maximumTrackImageResponseObserverProxy = std::make_unique<RCTImageResponseObserverProxy>((__bridge void *)self);
_thumbImageResponseObserverProxy = std::make_unique<RCTImageResponseObserverProxy>((__bridge void *)self);
self.contentView = _sliderView;
}
@ -55,7 +84,17 @@ using namespace facebook::react;
// `value`
if (oldSliderProps.value != newSliderProps.value) {
_sliderView.value = newSliderProps.value;
_prevValue = newSliderProps.value;
_previousValue = newSliderProps.value;
}
// `minimumValue`
if (oldSliderProps.minimumValue != newSliderProps.minimumValue) {
_sliderView.minimumValue = newSliderProps.minimumValue;
}
// `maximumValue`
if (oldSliderProps.maximumValue != newSliderProps.maximumValue) {
_sliderView.maximumValue = newSliderProps.maximumValue;
}
// `disabled`
@ -79,14 +118,178 @@ using namespace facebook::react;
}
}
- (void)onChange:(UISlider *)sender
- (void)updateLocalData:(SharedLocalData)localData
oldLocalData:(SharedLocalData)oldLocalData
{
if (_prevValue == sender.value) {
return;
}
_prevValue = sender.value;
SharedSliderLocalData previousData = _sliderLocalData;
_sliderLocalData = std::static_pointer_cast<const SliderLocalData>(localData);
assert(_sliderLocalData);
bool havePreviousData = previousData != nullptr;
std::dynamic_pointer_cast<const SliderEventEmitter>(_eventEmitter)->onValueChange(sender.value);
if (!havePreviousData || _sliderLocalData->getTrackImageSource() != previousData->getTrackImageSource()) {
self.trackImageCoordinator = _sliderLocalData->getTrackImageRequest().getObserverCoordinator();
}
if (!havePreviousData || _sliderLocalData->getMinimumTrackImageSource() != previousData->getMinimumTrackImageSource()) {
self.minimumTrackImageCoordinator = _sliderLocalData->getMinimumTrackImageRequest().getObserverCoordinator();
}
if (!havePreviousData || _sliderLocalData->getMaximumTrackImageSource() != previousData->getMaximumTrackImageSource()) {
self.maximumTrackImageCoordinator = _sliderLocalData->getMaximumTrackImageRequest().getObserverCoordinator();
}
if (!havePreviousData || _sliderLocalData->getThumbImageSource() != previousData->getThumbImageSource()) {
self.thumbImageCoordinator = _sliderLocalData->getThumbImageRequest().getObserverCoordinator();
}
}
- (void)setTrackImageCoordinator:(std::shared_ptr<const ImageResponseObserverCoordinator>)coordinator {
if (_trackImageCoordinator) {
_trackImageCoordinator->removeObserver(_trackImageResponseObserverProxy.get());
}
_trackImageCoordinator = coordinator;
if (_trackImageCoordinator != nullptr) {
_trackImageCoordinator->addObserver(_trackImageResponseObserverProxy.get());
}
}
- (void)setMinimumTrackImageCoordinator:(std::shared_ptr<const ImageResponseObserverCoordinator>)coordinator {
if (_minimumTrackImageCoordinator) {
_minimumTrackImageCoordinator->removeObserver(_minimumTrackImageResponseObserverProxy.get());
}
_minimumTrackImageCoordinator = coordinator;
if (_minimumTrackImageCoordinator != nullptr) {
_minimumTrackImageCoordinator->addObserver(_minimumTrackImageResponseObserverProxy.get());
}
}
- (void)setMaximumTrackImageCoordinator:(std::shared_ptr<const ImageResponseObserverCoordinator>)coordinator {
if (_maximumTrackImageCoordinator) {
_maximumTrackImageCoordinator->removeObserver(_maximumTrackImageResponseObserverProxy.get());
}
_maximumTrackImageCoordinator = coordinator;
if (_maximumTrackImageCoordinator != nullptr) {
_maximumTrackImageCoordinator->addObserver(_maximumTrackImageResponseObserverProxy.get());
}
}
- (void)setThumbImageCoordinator:(std::shared_ptr<const ImageResponseObserverCoordinator>)coordinator {
if (_thumbImageCoordinator) {
_thumbImageCoordinator->removeObserver(_thumbImageResponseObserverProxy.get());
}
_thumbImageCoordinator = coordinator;
if (_thumbImageCoordinator != nullptr) {
_thumbImageCoordinator->addObserver(_thumbImageResponseObserverProxy.get());
}
}
- (void)setTrackImage:(UIImage *)trackImage {
if ([trackImage isEqual:_trackImage]) {
return;
}
_trackImage = trackImage;
_minimumTrackImage = nil;
_maximumTrackImage = nil;
CGFloat width = trackImage.size.width / 2;
UIImage *minimumTrackImage = [trackImage resizableImageWithCapInsets:(UIEdgeInsets){
0, width, 0, width
} resizingMode:UIImageResizingModeStretch];
UIImage *maximumTrackImage = [trackImage resizableImageWithCapInsets:(UIEdgeInsets){
0, width, 0, width
} resizingMode:UIImageResizingModeStretch];
[_sliderView setMinimumTrackImage:minimumTrackImage forState:UIControlStateNormal];
[_sliderView setMaximumTrackImage:maximumTrackImage forState:UIControlStateNormal];
}
-(void)setMinimumTrackImage:(UIImage *)minimumTrackImage {
if ([minimumTrackImage isEqual:_minimumTrackImage] && _trackImage == nil) {
return;
}
_trackImage = nil;
_minimumTrackImage = minimumTrackImage;
_minimumTrackImage = [_minimumTrackImage resizableImageWithCapInsets:(UIEdgeInsets) {
0, _minimumTrackImage.size.width, 0, 0
} resizingMode:UIImageResizingModeStretch];
[_sliderView setMinimumTrackImage:_minimumTrackImage forState:UIControlStateNormal];
}
-(void)setMaximumTrackImage:(UIImage *)maximumTrackImage {
if ([maximumTrackImage isEqual:_maximumTrackImage] && _trackImage == nil) {
return;
}
_trackImage = nil;
_maximumTrackImage = maximumTrackImage;
_maximumTrackImage = [_maximumTrackImage resizableImageWithCapInsets:(UIEdgeInsets) {
0, 0, 0, _maximumTrackImage.size.width
} resizingMode:UIImageResizingModeStretch];
[_sliderView setMaximumTrackImage:_maximumTrackImage forState:UIControlStateNormal];
}
-(void)setThumbImage:(UIImage *)thumbImage {
if ([thumbImage isEqual:_thumbImage]) {
return;
}
_thumbImage = thumbImage;
[_sliderView setThumbImage:thumbImage forState:UIControlStateNormal];
}
- (void)onChange:(UISlider *)sender
{
[self onChange:sender withContinuous:YES];
}
- (void)sliderTouchEnd:(UISlider *)sender
{
[self onChange:sender withContinuous:NO];
}
- (void)onChange:(UISlider *)sender withContinuous:(BOOL)continuous
{
float value = sender.value;
const auto &props = *std::static_pointer_cast<const SliderProps>(_props);
if (props.step > 0 && value <= (props.maximumValue - props.minimumValue)) {
value = MAX(props.minimumValue,
MIN(props.maximumValue,
props.minimumValue + round((value - props.minimumValue) / props.step) * props.step
)
);
[_sliderView setValue:value animated:YES];
}
if (continuous && _previousValue != value) {
std::dynamic_pointer_cast<const SliderEventEmitter>(_eventEmitter)->onValueChange(value);
}
if (!continuous) {
std::dynamic_pointer_cast<const SliderEventEmitter>(_eventEmitter)->onSlidingComplete(value);
}
_previousValue = value;
}
#pragma mark - RCTImageResponseDelegate
- (void)didReceiveImage:(UIImage *)image fromObserver:(void *)observer
{
if (observer == _trackImageResponseObserverProxy.get()) {
self.trackImage = image;
} else if (observer == _minimumTrackImageResponseObserverProxy.get()) {
self.minimumTrackImage = image;
} else if (observer == _maximumTrackImageResponseObserverProxy.get()) {
self.maximumTrackImage = image;
} else if (observer == _thumbImageResponseObserverProxy.get()) {
self.thumbImage = image;
}
}
- (void)didReceiveProgress:(float)progress fromObserver:(void *)observer {
}
- (void)didReceiveFailureFromObserver:(void *)observer {
}
@end

Просмотреть файл

@ -0,0 +1,20 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@protocol RCTImageResponseDelegate <NSObject>
- (void)didReceiveImage:(UIImage *)image fromObserver:(void*)observer;
- (void)didReceiveProgress:(float)progress fromObserver:(void*)observer;
- (void)didReceiveFailureFromObserver:(void*)observer;
@end
NS_ASSUME_NONNULL_END

Просмотреть файл

@ -0,0 +1,32 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#import "RCTImageResponseDelegate.h"
#import "RCTImageResponseDelegate.h"
#include <react/imagemanager/ImageResponseObserver.h>
NS_ASSUME_NONNULL_BEGIN
namespace facebook {
namespace react {
class RCTImageResponseObserverProxy: public ImageResponseObserver {
public:
RCTImageResponseObserverProxy(void* delegate);
void didReceiveImage(const ImageResponse &imageResponse) override;
void didReceiveProgress (float p) override;
void didReceiveFailure() override;
private:
id<RCTImageResponseDelegate> delegate_;
};
}
}
NS_ASSUME_NONNULL_END

Просмотреть файл

@ -0,0 +1,41 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTImageResponseObserverProxy.h"
#import <react/imagemanager/ImageResponseObserver.h>
#import <react/imagemanager/ImageResponse.h>
namespace facebook {
namespace react {
RCTImageResponseObserverProxy::RCTImageResponseObserverProxy(void* delegate): delegate_((__bridge id<RCTImageResponseDelegate>)delegate) {}
void RCTImageResponseObserverProxy::didReceiveImage(const ImageResponse &imageResponse) {
UIImage *image = (__bridge UIImage *)imageResponse.getImage().get();
void *this_ = this;
dispatch_async(dispatch_get_main_queue(), ^{
[delegate_ didReceiveImage:image fromObserver:this_];
});
}
void RCTImageResponseObserverProxy::didReceiveProgress (float p) {
void *this_ = this;
dispatch_async(dispatch_get_main_queue(), ^{
[delegate_ didReceiveProgress:p fromObserver:this_];
});
}
void RCTImageResponseObserverProxy::didReceiveFailure() {
void *this_ = this;
dispatch_async(dispatch_get_main_queue(), ^{
[delegate_ didReceiveFailureFromObserver:this_];
});
}
} // namespace react
} // namespace facebook

Просмотреть файл

@ -55,8 +55,10 @@ rn_xplat_cxx_library(
"xplat//yoga:yoga",
react_native_xplat_target("fabric/debug:debug"),
react_native_xplat_target("fabric/core:core"),
react_native_xplat_target("fabric/graphics:graphics"),
react_native_xplat_target("fabric/components/image:image"),
react_native_xplat_target("fabric/components/view:view"),
react_native_xplat_target("fabric/graphics:graphics"),
react_native_xplat_target("fabric/imagemanager:imagemanager"),
],
)

Просмотреть файл

@ -13,7 +13,37 @@
namespace facebook {
namespace react {
using SliderComponentDescriptor = ConcreteComponentDescriptor<SliderShadowNode>;
/*
* Descriptor for <Slider> component.
*/
class SliderComponentDescriptor final
: public ConcreteComponentDescriptor<SliderShadowNode> {
public:
SliderComponentDescriptor(
SharedEventDispatcher eventDispatcher,
const SharedContextContainer &contextContainer)
: ConcreteComponentDescriptor(eventDispatcher),
imageManager_(
contextContainer
? contextContainer->getInstance<SharedImageManager>(
"ImageManager")
: nullptr) {}
void adopt(UnsharedShadowNode shadowNode) const override {
ConcreteComponentDescriptor::adopt(shadowNode);
assert(std::dynamic_pointer_cast<SliderShadowNode>(shadowNode));
auto sliderShadowNode =
std::static_pointer_cast<SliderShadowNode>(shadowNode);
// `SliderShadowNode` uses `ImageManager` to initiate image loading and
// communicate the loading state and results to mounting layer.
sliderShadowNode->setImageManager(imageManager_);
}
private:
const SharedImageManager imageManager_;
};
} // namespace react
} // namespace facebook

Просмотреть файл

@ -0,0 +1,68 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "SliderLocalData.h"
#include <react/components/image/conversions.h>
#include <react/debug/debugStringConvertibleUtils.h>
namespace facebook {
namespace react {
ImageSource SliderLocalData::getTrackImageSource() const {
return trackImageSource_;
}
const ImageRequest &SliderLocalData::getTrackImageRequest() const {
return trackImageRequest_;
}
ImageSource SliderLocalData::getMinimumTrackImageSource() const {
return minimumTrackImageSource_;
}
const ImageRequest &SliderLocalData::getMinimumTrackImageRequest() const {
return minimumTrackImageRequest_;
}
ImageSource SliderLocalData::getMaximumTrackImageSource() const {
return maximumTrackImageSource_;
}
const ImageRequest &SliderLocalData::getMaximumTrackImageRequest() const {
return maximumTrackImageRequest_;
}
ImageSource SliderLocalData::getThumbImageSource() const {
return thumbImageSource_;
}
const ImageRequest &SliderLocalData::getThumbImageRequest() const {
return thumbImageRequest_;
}
#pragma mark - DebugStringConvertible
#if RN_DEBUG_STRING_CONVERTIBLE
std::string SliderLocalData::getDebugName() const {
return "SliderLocalData";
}
SharedDebugStringConvertibleList SliderLocalData::getDebugProps() const {
return {
debugStringConvertibleItem("trackImageSource", trackImageSource_),
debugStringConvertibleItem(
"minimumTrackImageSource", minimumTrackImageSource_),
debugStringConvertibleItem(
"maximumTrackImageSource", maximumTrackImageSource_),
debugStringConvertibleItem("thumbImageSource", thumbImageSource_),
};
}
#endif
} // namespace react
} // namespace facebook

Просмотреть файл

@ -0,0 +1,108 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/core/LocalData.h>
#include <react/imagemanager/ImageRequest.h>
#include <react/imagemanager/primitives.h>
namespace facebook {
namespace react {
class SliderLocalData;
using SharedSliderLocalData = std::shared_ptr<const SliderLocalData>;
/*
* LocalData for <Slider> component.
* Represents the image request state and (possible) retrieved image bitmap.
*/
class SliderLocalData : public LocalData {
public:
SliderLocalData(
const ImageSource &trackImageSource,
ImageRequest trackImageRequest,
const ImageSource &minimumTrackImageSource,
ImageRequest minimumTrackImageRequest,
const ImageSource &maximumTrackImageSource,
ImageRequest maximumTrackImageRequest,
const ImageSource &thumbImageSource,
ImageRequest thumbImageRequest)
: trackImageSource_(trackImageSource),
trackImageRequest_(std::move(trackImageRequest)),
minimumTrackImageSource_(minimumTrackImageSource),
minimumTrackImageRequest_(std::move(minimumTrackImageRequest)),
maximumTrackImageSource_(maximumTrackImageSource),
maximumTrackImageRequest_(std::move(maximumTrackImageRequest)),
thumbImageSource_(thumbImageSource),
thumbImageRequest_(std::move(thumbImageRequest)){};
/*
* Returns stored ImageSource object.
*/
ImageSource getTrackImageSource() const;
/*
* Exposes for reading stored `ImageRequest` object.
* `ImageRequest` object cannot be copied or moved from `ImageLocalData`.
*/
const ImageRequest &getTrackImageRequest() const;
/*
* Returns stored ImageSource object.
*/
ImageSource getMinimumTrackImageSource() const;
/*
* Exposes for reading stored `ImageRequest` object.
* `ImageRequest` object cannot be copied or moved from `ImageLocalData`.
*/
const ImageRequest &getMinimumTrackImageRequest() const;
/*
* Returns stored ImageSource object.
*/
ImageSource getMaximumTrackImageSource() const;
/*
* Exposes for reading stored `ImageRequest` object.
* `ImageRequest` object cannot be copied or moved from `ImageLocalData`.
*/
const ImageRequest &getMaximumTrackImageRequest() const;
/*
* Returns stored ImageSource object.
*/
ImageSource getThumbImageSource() const;
/*
* Exposes for reading stored `ImageRequest` object.
* `ImageRequest` object cannot be copied or moved from `ImageLocalData`.
*/
const ImageRequest &getThumbImageRequest() const;
#pragma mark - DebugStringConvertible
#if RN_DEBUG_STRING_CONVERTIBLE
std::string getDebugName() const override;
SharedDebugStringConvertibleList getDebugProps() const override;
#endif
private:
ImageSource trackImageSource_;
ImageRequest trackImageRequest_;
ImageSource minimumTrackImageSource_;
ImageRequest minimumTrackImageRequest_;
ImageSource maximumTrackImageSource_;
ImageRequest maximumTrackImageRequest_;
ImageSource thumbImageSource_;
ImageRequest thumbImageRequest_;
};
} // namespace react
} // namespace facebook

Просмотреть файл

@ -6,6 +6,7 @@
*/
#include <react/components/slider/SliderProps.h>
#include <react/components/image/conversions.h>
#include <react/core/propsConversions.h>
namespace facebook {
@ -16,24 +17,54 @@ SliderProps::SliderProps(
const RawProps &rawProps)
: ViewProps(sourceProps, rawProps),
value(convertRawProp(rawProps, "value", sourceProps.value, value)),
steps(convertRawProp(rawProps, "steps", sourceProps.steps, steps)),
minimumValue(convertRawProp(
rawProps,
"minimumValue",
sourceProps.minimumValue,
minimumValue)),
maximumValue(convertRawProp(
rawProps,
"maximumValue",
sourceProps.maximumValue,
maximumValue)),
step(convertRawProp(rawProps, "step", sourceProps.step, step)),
disabled(
convertRawProp(rawProps, "disabled", sourceProps.disabled, disabled)),
minimumTrackTintColor(convertRawProp(
rawProps,
"minimumTintColor",
sourceProps.thumbTintColor,
thumbTintColor)),
"minimumTrackTintColor",
sourceProps.minimumTrackTintColor,
minimumTrackTintColor)),
maximumTrackTintColor(convertRawProp(
rawProps,
"maximumTintColor",
sourceProps.thumbTintColor,
thumbTintColor)),
"maximumTrackTintColor",
sourceProps.maximumTrackTintColor,
maximumTrackTintColor)),
thumbTintColor(convertRawProp(
rawProps,
"thumbTintColor",
sourceProps.thumbTintColor,
thumbTintColor)) {}
thumbTintColor)),
trackImage(convertRawProp(
rawProps,
"trackImage",
sourceProps.trackImage,
trackImage)),
minimumTrackImage(convertRawProp(
rawProps,
"minimumTrackImage",
sourceProps.minimumTrackImage,
minimumTrackImage)),
maximumTrackImage(convertRawProp(
rawProps,
"maximumTrackImage",
sourceProps.maximumTrackImage,
maximumTrackImage)),
thumbImage(convertRawProp(
rawProps,
"thumbImage",
sourceProps.thumbImage,
thumbImage)) {}
} // namespace react
} // namespace facebook

Просмотреть файл

@ -5,8 +5,11 @@
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/components/view/ViewProps.h>
#include <react/graphics/Color.h>
#include <react/imagemanager/primitives.h>
namespace facebook {
namespace react {
@ -19,14 +22,22 @@ class SliderProps final : public ViewProps {
#pragma mark - Props
const float value{false};
const float steps{false};
const float value{0};
const float minimumValue{0};
const float maximumValue{1};
const float step{0};
const bool disabled{false};
const SharedColor minimumTrackTintColor{};
const SharedColor maximumTrackTintColor{};
// Android only
const SharedColor thumbTintColor;
// iOS only
const ImageSource trackImage{};
const ImageSource minimumTrackImage{};
const ImageSource maximumTrackImage{};
const ImageSource thumbImage{};
};
} // namespace react

Просмотреть файл

@ -7,10 +7,89 @@
#include "SliderShadowNode.h"
#include <react/components/slider/SliderLocalData.h>
#include <react/components/slider/SliderShadowNode.h>
#include <react/core/LayoutContext.h>
namespace facebook {
namespace react {
extern const char SliderComponentName[] = "Slider";
void SliderShadowNode::setImageManager(const SharedImageManager &imageManager) {
ensureUnsealed();
imageManager_ = imageManager;
}
void SliderShadowNode::updateLocalData() {
const auto &newTrackImageSource = getTrackImageSource();
const auto &newMinimumTrackImageSource = getMinimumTrackImageSource();
const auto &newMaximumTrackImageSource = getMaximumTrackImageSource();
const auto &newThumbImageSource = getThumbImageSource();
const auto &localData = getLocalData();
if (localData) {
assert(std::dynamic_pointer_cast<const SliderLocalData>(localData));
auto currentLocalData =
std::static_pointer_cast<const SliderLocalData>(localData);
auto trackImageSource = currentLocalData->getTrackImageSource();
auto minimumTrackImageSource =
currentLocalData->getMinimumTrackImageSource();
auto maximumTrackImageSource =
currentLocalData->getMaximumTrackImageSource();
auto thumbImageSource = currentLocalData->getThumbImageSource();
bool anyChanged = newTrackImageSource != trackImageSource ||
newMinimumTrackImageSource != minimumTrackImageSource ||
newMaximumTrackImageSource != maximumTrackImageSource ||
newThumbImageSource != thumbImageSource;
if (!anyChanged) {
return;
}
}
// Now we are about to mutate the Shadow Node.
ensureUnsealed();
// It is not possible to copy or move image requests from SliderLocalData,
// so instead we recreate any image requests (that may already be in-flight?)
// TODO: check if multiple requests are cached or if it's a net loss
const auto &newLocalData = std::make_shared<SliderLocalData>(
newTrackImageSource,
imageManager_->requestImage(newTrackImageSource),
newMinimumTrackImageSource,
imageManager_->requestImage(newMinimumTrackImageSource),
newMaximumTrackImageSource,
imageManager_->requestImage(newMaximumTrackImageSource),
newThumbImageSource,
imageManager_->requestImage(newThumbImageSource));
setLocalData(newLocalData);
}
ImageSource SliderShadowNode::getTrackImageSource() const {
return getProps()->trackImage;
}
ImageSource SliderShadowNode::getMinimumTrackImageSource() const {
return getProps()->minimumTrackImage;
}
ImageSource SliderShadowNode::getMaximumTrackImageSource() const {
return getProps()->maximumTrackImage;
}
ImageSource SliderShadowNode::getThumbImageSource() const {
return getProps()->thumbImage;
}
#pragma mark - LayoutableShadowNode
void SliderShadowNode::layout(LayoutContext layoutContext) {
updateLocalData();
ConcreteViewShadowNode::layout(layoutContext);
}
} // namespace react
} // namespace facebook

Просмотреть файл

@ -10,6 +10,8 @@
#include <react/components/slider/SliderEventEmitter.h>
#include <react/components/slider/SliderProps.h>
#include <react/components/view/ConcreteViewShadowNode.h>
#include <react/imagemanager/ImageManager.h>
#include <react/imagemanager/primitives.h>
namespace facebook {
namespace react {
@ -19,10 +21,31 @@ extern const char SliderComponentName[];
/*
* `ShadowNode` for <Slider> component.
*/
using SliderShadowNode = ConcreteViewShadowNode<
SliderComponentName,
SliderProps,
SliderEventEmitter>;
class SliderShadowNode final : public ConcreteViewShadowNode<
SliderComponentName,
SliderProps,
SliderEventEmitter> {
public:
using ConcreteViewShadowNode::ConcreteViewShadowNode;
// Associates a shared `ImageManager` with the node.
void setImageManager(const SharedImageManager &imageManager);
#pragma mark - LayoutableShadowNode
void layout(LayoutContext layoutContext) override;
private:
// (Re)Creates a `LocalData` object (with `ImageRequest`) if needed.
void updateLocalData();
ImageSource getTrackImageSource() const;
ImageSource getMinimumTrackImageSource() const;
ImageSource getMaximumTrackImageSource() const;
ImageSource getThumbImageSource() const;
SharedImageManager imageManager_;
};
} // namespace react
} // namespace facebook