Enable Slider component

Summary:
Enable Slider component in Fabric on Android.

{F151706188}

Reviewed By: mdvacca

Differential Revision: D14220147

fbshipit-source-id: 10b29112e950c8de98cba995839780c4f4e8d3b6
This commit is contained in:
Joshua Gross
2019-02-26 14:33:19 -08:00
committed by Facebook Github Bot
parent 57afad1c1f
commit 3c1114eea7
12 changed files with 255 additions and 4 deletions

View File

@@ -77,6 +77,7 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
sComponentNames.put("View", "RCTView");
sComponentNames.put("Image", "RCTImageView");
sComponentNames.put("ScrollView", "RCTScrollView");
sComponentNames.put("Slider", "RCTSlider");
sComponentNames.put("ReactPerformanceLoggerFlag", "ReactPerformanceLoggerFlag");
sComponentNames.put("Paragraph", "RCTText");
sComponentNames.put("Text", "RCText");

View File

@@ -14,6 +14,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.SeekBar;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.LayoutShadowNode;
import com.facebook.react.uimanager.ReactShadowNodeImpl;
@@ -192,4 +193,22 @@ public class ReactSliderManager extends SimpleViewManager<ReactSlider> {
ReactSlidingCompleteEvent.EVENT_NAME,
MapBuilder.of("registrationName", "onSlidingComplete"));
}
}
@Override
public long measure(
ReactContext context,
ReadableMap localData,
ReadableMap props,
float width,
YogaMeasureMode widthMode,
float height,
YogaMeasureMode heightMode) {
SeekBar reactSlider = new ReactSlider(context, null, STYLE);
final int spec = View.MeasureSpec.makeMeasureSpec(
ViewGroup.LayoutParams.WRAP_CONTENT,
View.MeasureSpec.UNSPECIFIED);
reactSlider.measure(spec, spec);
return YogaMeasureOutput.make(reactSlider.getMeasuredWidth(), reactSlider.getMeasuredHeight());
}
}

View File

@@ -96,6 +96,7 @@ public class ReactTextViewManager
return MapBuilder.of("topTextLayout", MapBuilder.of("registrationName", "onTextLayout"));
}
@Override
public long measure(
ReactContext context,
ReadableMap localData,

View File

@@ -25,11 +25,19 @@ class ImageComponentDescriptor final
SharedEventDispatcher eventDispatcher,
const SharedContextContainer &contextContainer)
: ConcreteComponentDescriptor(eventDispatcher),
// TODO (39486757): implement image manager on Android, currently Android does
// not have an ImageManager so this will crash
#ifndef ANDROID
imageManager_(
contextContainer
? contextContainer->getInstance<SharedImageManager>(
"ImageManager")
: nullptr) {}
: nullptr) {
}
#else
imageManager_(nullptr) {
}
#endif
void adopt(UnsharedShadowNode shadowNode) const override {
ConcreteComponentDescriptor::adopt(shadowNode);

View File

@@ -6,6 +6,7 @@ load(
"fb_xplat_cxx_test",
"get_apple_compiler_flags",
"get_apple_inspector_flags",
"react_native_target",
"react_native_xplat_target",
"rn_xplat_cxx_library",
"subdir_glob",
@@ -17,7 +18,10 @@ rn_xplat_cxx_library(
name = "slider",
srcs = glob(
["**/*.cpp"],
exclude = glob(["tests/**/*.cpp"]),
exclude = glob([
"tests/**/*.cpp",
"platform/**/*.cpp",
]),
),
headers = [],
header_namespace = "",
@@ -33,8 +37,38 @@ rn_xplat_cxx_library(
"-std=c++14",
"-Wall",
],
fbandroid_deps = [
react_native_target("jni/react/jni:jni"),
],
fbandroid_exported_headers = subdir_glob(
[
("", "*.h"),
("platform/android", "*.h"),
],
prefix = "react/components/slider",
),
fbandroid_headers = glob(
["platform/android/*.h"],
),
fbandroid_srcs = glob(
["platform/android/*.cpp"],
),
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
force_static = True,
ios_exported_headers = subdir_glob(
[
("", "*.h"),
("platform/ios", "*.h"),
],
prefix = "react/components/slider",
),
ios_headers = glob(
["platform/ios/*.h"],
),
ios_srcs = glob(
["platform/ios/*.cpp"],
),
macosx_tests_override = [],
platforms = (ANDROID, APPLE),
preprocessor_flags = [
@@ -56,6 +90,7 @@ rn_xplat_cxx_library(
react_native_xplat_target("fabric/components/view:view"),
react_native_xplat_target("fabric/graphics:graphics"),
react_native_xplat_target("fabric/imagemanager:imagemanager"),
react_native_xplat_target("fabric/uimanager:uimanager"),
],
)

View File

@@ -7,6 +7,7 @@
#pragma once
#include <react/components/slider/SliderMeasurementsManager.h>
#include <react/components/slider/SliderShadowNode.h>
#include <react/core/ConcreteComponentDescriptor.h>
@@ -23,11 +24,20 @@ class SliderComponentDescriptor final
SharedEventDispatcher eventDispatcher,
const SharedContextContainer &contextContainer)
: ConcreteComponentDescriptor(eventDispatcher),
// TODO (39486757): implement image manager on Android, currently Android does
// not have an ImageManager so this will crash
#ifndef ANDROID
imageManager_(
contextContainer
? contextContainer->getInstance<SharedImageManager>(
"ImageManager")
: nullptr) {}
: nullptr),
#else
imageManager_(nullptr),
#endif
measurementsManager_(
std::make_shared<SliderMeasurementsManager>(contextContainer)) {
}
void adopt(UnsharedShadowNode shadowNode) const override {
ConcreteComponentDescriptor::adopt(shadowNode);
@@ -39,10 +49,19 @@ class SliderComponentDescriptor final
// `SliderShadowNode` uses `ImageManager` to initiate image loading and
// communicate the loading state and results to mounting layer.
sliderShadowNode->setImageManager(imageManager_);
// `SliderShadowNode` uses `SliderMeasurementsManager` to
// provide measurements to Yoga.
sliderShadowNode->setSliderMeasurementsManager(measurementsManager_);
// All `SliderShadowNode`s must have leaf Yoga nodes with properly
// setup measure function.
sliderShadowNode->enableMeasurement();
}
private:
const SharedImageManager imageManager_;
const std::shared_ptr<SliderMeasurementsManager> measurementsManager_;
};
} // namespace react

View File

@@ -21,6 +21,12 @@ void SliderShadowNode::setImageManager(const SharedImageManager &imageManager) {
imageManager_ = imageManager;
}
void SliderShadowNode::setSliderMeasurementsManager(
const std::shared_ptr<SliderMeasurementsManager> &measurementsManager) {
ensureUnsealed();
measurementsManager_ = measurementsManager;
}
void SliderShadowNode::updateLocalData() {
const auto &newTrackImageSource = getTrackImageSource();
const auto &newMinimumTrackImageSource = getMinimumTrackImageSource();
@@ -86,6 +92,14 @@ ImageSource SliderShadowNode::getThumbImageSource() const {
#pragma mark - LayoutableShadowNode
Size SliderShadowNode::measure(LayoutConstraints layoutConstraints) const {
if (measurementsManager_->shouldMeasureSlider()) {
return measurementsManager_->measure(layoutConstraints);
}
return {};
}
void SliderShadowNode::layout(LayoutContext layoutContext) {
updateLocalData();
ConcreteViewShadowNode::layout(layoutContext);

View File

@@ -8,6 +8,7 @@
#pragma once
#include <react/components/slider/SliderEventEmitter.h>
#include <react/components/slider/SliderMeasurementsManager.h>
#include <react/components/slider/SliderProps.h>
#include <react/components/view/ConcreteViewShadowNode.h>
#include <react/imagemanager/ImageManager.h>
@@ -31,8 +32,13 @@ class SliderShadowNode final : public ConcreteViewShadowNode<
// Associates a shared `ImageManager` with the node.
void setImageManager(const SharedImageManager &imageManager);
// Associates a shared `SliderMeasurementsManager` with the node.
void setSliderMeasurementsManager(
const std::shared_ptr<SliderMeasurementsManager> &measurementsManager);
#pragma mark - LayoutableShadowNode
Size measure(LayoutConstraints layoutConstraints) const override;
void layout(LayoutContext layoutContext) override;
private:
@@ -45,6 +51,7 @@ class SliderShadowNode final : public ConcreteViewShadowNode<
ImageSource getThumbImageSource() const;
SharedImageManager imageManager_;
std::shared_ptr<SliderMeasurementsManager> measurementsManager_;
};
} // namespace react

View File

@@ -0,0 +1,61 @@
/**
* 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 "SliderMeasurementsManager.h"
#include <fb/fbjni.h>
#include <react/core/conversions.h>
#include <react/jni/ReadableNativeMap.h>
using namespace facebook::jni;
namespace facebook {
namespace react {
const bool SliderMeasurementsManager::shouldMeasureSlider() const {
return true;
}
Size SliderMeasurementsManager::measure(
LayoutConstraints layoutConstraints) const {
const jni::global_ref<jobject> &fabricUIManager =
contextContainer_->getInstance<jni::global_ref<jobject>>(
"FabricUIManager");
static auto measure =
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
->getMethod<jlong(
jstring,
ReadableMap::javaobject,
ReadableMap::javaobject,
jint,
jint,
jint,
jint)>("measure");
auto minimumSize = layoutConstraints.minimumSize;
auto maximumSize = layoutConstraints.maximumSize;
int minWidth = (int)minimumSize.width;
int minHeight = (int)minimumSize.height;
int maxWidth = (int)maximumSize.width;
int maxHeight = (int)maximumSize.height;
local_ref<JString> componentName = make_jstring("RCTSlider");
return yogaMeassureToSize(measure(
fabricUIManager,
componentName.get(),
nullptr,
nullptr,
minWidth,
maxWidth,
minHeight,
maxHeight));
}
} // namespace react
} // namespace facebook

View File

@@ -0,0 +1,33 @@
/**
* 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/ConcreteComponentDescriptor.h>
#include <react/core/LayoutConstraints.h>
#include <react/uimanager/ContextContainer.h>
namespace facebook {
namespace react {
/**
* Class that manages slider measurements across platforms.
* On iOS it is a noop, since the height is passed in from JS on iOS only.
*/
class SliderMeasurementsManager {
public:
SliderMeasurementsManager(const SharedContextContainer &contextContainer)
: contextContainer_(contextContainer) {}
const bool shouldMeasureSlider() const;
Size measure(LayoutConstraints layoutConstraints) const;
private:
const SharedContextContainer contextContainer_;
};
} // namespace react
} // namespace facebook

View File

@@ -0,0 +1,24 @@
/**
* 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 "SliderMeasurementsManager.h"
namespace facebook {
namespace react {
const bool SliderMeasurementsManager::shouldMeasureSlider() const {
return false;
}
Size SliderMeasurementsManager::measure(
LayoutConstraints layoutConstraints) const {
assert(false); // should never reach this point
return {};
}
} // namespace react
} // namespace facebook

View File

@@ -0,0 +1,29 @@
/**
* 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/ConcreteComponentDescriptor.h>
#include <react/core/LayoutConstraints.h>
#include <react/uimanager/ContextContainer.h>
namespace facebook {
namespace react {
/**
* Class that manages slider measurements across platforms.
* On iOS it is a noop, since the height is passed in from JS on iOS only.
*/
class SliderMeasurementsManager {
public:
SliderMeasurementsManager(const SharedContextContainer &contextContainer) {}
const bool shouldMeasureSlider() const;
Size measure(LayoutConstraints layoutConstraints) const;
};
} // namespace react
} // namespace facebook