Integrate AndroidSwitch into Fabric on Android
Summary: In this diff we integrate the Switch component on Android in Fabric. Since the component has a custom measure function, we need to write some C++ to call the measure method in Java. The component isn't fully functional yet (setNativeProps isn't supported in Fabric) and has some problems with measuring itself. I will fix the component in the next diffs in this stack. Reviewed By: JoshuaGross Differential Revision: D17571258 fbshipit-source-id: be4e201495b9b197ddec44ee3484357bfb6225a8
This commit is contained in:
Родитель
6aae8e0756
Коммит
d0dd1aed29
|
@ -43,6 +43,6 @@ type NativeProps = $ReadOnly<{|
|
|||
onChange?: BubblingEventHandler<SwitchChangeEvent>,
|
||||
|}>;
|
||||
|
||||
export default (codegenNativeComponent<NativeProps>(
|
||||
'AndroidSwitch',
|
||||
): HostComponent<NativeProps>);
|
||||
export default (codegenNativeComponent<NativeProps>('AndroidSwitch', {
|
||||
interfaceOnly: true,
|
||||
}): HostComponent<NativeProps>);
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
// switchview because switch is a keyword
|
||||
package com.facebook.react.views.switchview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.widget.CompoundButton;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.uimanager.LayoutShadowNode;
|
||||
import com.facebook.react.uimanager.SimpleViewManager;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
|
@ -177,4 +179,21 @@ public class ReactSwitchManager extends SimpleViewManager<ReactSwitch>
|
|||
protected ViewManagerDelegate<ReactSwitch> getDelegate() {
|
||||
return mDelegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long measure(
|
||||
Context context,
|
||||
ReadableMap localData,
|
||||
ReadableMap props,
|
||||
ReadableMap state,
|
||||
float width,
|
||||
YogaMeasureMode widthMode,
|
||||
float height,
|
||||
YogaMeasureMode heightMode) {
|
||||
ReactSwitch view = new ReactSwitch(context);
|
||||
view.setShowText(false);
|
||||
int measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
|
||||
view.measure(measureSpec, measureSpec);
|
||||
return YogaMeasureOutput.make(view.getMeasuredWidth(), view.getMeasuredHeight());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
|
||||
load(
|
||||
"//tools/build_defs/oss:rn_defs.bzl",
|
||||
"ANDROID",
|
||||
"APPLE",
|
||||
"CXX",
|
||||
"YOGA_CXX_TARGET",
|
||||
"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",
|
||||
)
|
||||
|
||||
APPLE_COMPILER_FLAGS = get_apple_compiler_flags()
|
||||
|
||||
rn_xplat_cxx_library(
|
||||
name = "androidswitch",
|
||||
srcs = glob(
|
||||
["**/*.cpp"],
|
||||
exclude = glob(["tests/**/*.cpp"]),
|
||||
),
|
||||
headers = glob(
|
||||
["**/*.h"],
|
||||
exclude = glob(["tests/**/*.h"]),
|
||||
),
|
||||
header_namespace = "",
|
||||
exported_headers = subdir_glob(
|
||||
[
|
||||
("", "*.h"),
|
||||
("androidswitch", "*.h"),
|
||||
],
|
||||
prefix = "react/components/androidswitch",
|
||||
),
|
||||
compiler_flags = [
|
||||
"-fexceptions",
|
||||
"-frtti",
|
||||
"-std=c++14",
|
||||
"-Wall",
|
||||
],
|
||||
cxx_tests = [":tests"],
|
||||
fbandroid_deps = [
|
||||
react_native_target("jni/react/jni:jni"),
|
||||
],
|
||||
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
|
||||
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
|
||||
force_static = True,
|
||||
platforms = (ANDROID, APPLE, CXX),
|
||||
preprocessor_flags = [
|
||||
"-DLOG_TAG=\"ReactNative\"",
|
||||
"-DWITH_FBSYSTRACE=1",
|
||||
],
|
||||
visibility = ["PUBLIC"],
|
||||
deps = [
|
||||
"fbsource//xplat/fbsystrace:fbsystrace",
|
||||
"fbsource//xplat/folly:headers_only",
|
||||
"fbsource//xplat/folly:memory",
|
||||
"fbsource//xplat/folly:molly",
|
||||
"fbsource//xplat/third-party/glog:glog",
|
||||
YOGA_CXX_TARGET,
|
||||
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/view:view"),
|
||||
react_native_xplat_target("fabric/uimanager:uimanager"),
|
||||
"fbsource//xplat/js/react-native-github:generated_components-rncore",
|
||||
],
|
||||
)
|
||||
|
||||
fb_xplat_cxx_test(
|
||||
name = "tests",
|
||||
srcs = glob(["tests/**/*.cpp"]),
|
||||
headers = glob(["tests/**/*.h"]),
|
||||
compiler_flags = [
|
||||
"-fexceptions",
|
||||
"-frtti",
|
||||
"-std=c++14",
|
||||
"-Wall",
|
||||
],
|
||||
contacts = ["oncall+react_native@xmail.facebook.com"],
|
||||
platforms = (
|
||||
# `Apple` and `Android` flavors are disabled because the module depends on `textlayoutmanager` which requires real an Emulator/Simulator to run.
|
||||
# At the same time, the code of tests does not rely on the simulator capabilities and it would be wasteful to add `fbandroid_use_instrumentation_test = True`.
|
||||
# (Beware of this option though.)
|
||||
# ANDROID,
|
||||
# APPLE,
|
||||
CXX
|
||||
),
|
||||
deps = [
|
||||
"fbsource//xplat/folly:molly",
|
||||
"fbsource//xplat/third-party/gmock:gtest",
|
||||
":androidswitch",
|
||||
],
|
||||
)
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* 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 "AndroidSwitchMeasurementsManager.h"
|
||||
#include "AndroidSwitchShadowNode.h"
|
||||
|
||||
#include <react/core/ConcreteComponentDescriptor.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
/*
|
||||
* Descriptor for <AndroidSwitch> component.
|
||||
*/
|
||||
class AndroidSwitchComponentDescriptor final
|
||||
: public ConcreteComponentDescriptor<AndroidSwitchShadowNode> {
|
||||
public:
|
||||
AndroidSwitchComponentDescriptor(
|
||||
EventDispatcher::Weak eventDispatcher,
|
||||
ContextContainer::Shared const &contextContainer)
|
||||
: ConcreteComponentDescriptor(eventDispatcher),
|
||||
measurementsManager_(std::make_shared<AndroidSwitchMeasurementsManager>(
|
||||
contextContainer)) {}
|
||||
|
||||
void adopt(UnsharedShadowNode shadowNode) const override {
|
||||
ConcreteComponentDescriptor::adopt(shadowNode);
|
||||
|
||||
assert(std::dynamic_pointer_cast<AndroidSwitchShadowNode>(shadowNode));
|
||||
auto androidSwitchShadowNode =
|
||||
std::static_pointer_cast<AndroidSwitchShadowNode>(shadowNode);
|
||||
|
||||
// `AndroidSwitchShadowNode` uses `AndroidSwitchMeasurementsManager` to
|
||||
// provide measurements to Yoga.
|
||||
androidSwitchShadowNode->setAndroidSwitchMeasurementsManager(
|
||||
measurementsManager_);
|
||||
|
||||
// All `AndroidSwitchShadowNode`s must have leaf Yoga nodes with properly
|
||||
// setup measure function.
|
||||
androidSwitchShadowNode->enableMeasurement();
|
||||
}
|
||||
|
||||
private:
|
||||
const std::shared_ptr<AndroidSwitchMeasurementsManager> measurementsManager_;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* 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 "AndroidSwitchMeasurementsManager.h"
|
||||
|
||||
#include <fb/fbjni.h>
|
||||
#include <react/core/conversions.h>
|
||||
#include <react/jni/ReadableNativeMap.h>
|
||||
|
||||
using namespace facebook::jni;
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
Size AndroidSwitchMeasurementsManager::measure(
|
||||
LayoutConstraints layoutConstraints) const {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (hasBeenMeasured_) {
|
||||
return cachedMeasurement_;
|
||||
}
|
||||
}
|
||||
|
||||
const jni::global_ref<jobject> &fabricUIManager =
|
||||
contextContainer_->at<jni::global_ref<jobject>>("FabricUIManager");
|
||||
|
||||
static auto measure =
|
||||
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
|
||||
->getMethod<jlong(
|
||||
jstring,
|
||||
ReadableMap::javaobject,
|
||||
ReadableMap::javaobject,
|
||||
ReadableMap::javaobject,
|
||||
jfloat,
|
||||
jfloat,
|
||||
jfloat,
|
||||
jfloat)>("measure");
|
||||
|
||||
auto minimumSize = layoutConstraints.minimumSize;
|
||||
auto maximumSize = layoutConstraints.maximumSize;
|
||||
|
||||
local_ref<JString> componentName = make_jstring("AndroidSwitch");
|
||||
|
||||
auto measurement = yogaMeassureToSize(measure(
|
||||
fabricUIManager,
|
||||
componentName.get(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
minimumSize.width,
|
||||
maximumSize.width,
|
||||
minimumSize.height,
|
||||
maximumSize.height));
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
cachedMeasurement_ = measurement;
|
||||
return measurement;
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -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/utils/ContextContainer.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
class AndroidSwitchMeasurementsManager {
|
||||
public:
|
||||
AndroidSwitchMeasurementsManager(
|
||||
const ContextContainer::Shared &contextContainer)
|
||||
: contextContainer_(contextContainer) {}
|
||||
|
||||
Size measure(LayoutConstraints layoutConstraints) const;
|
||||
|
||||
private:
|
||||
const ContextContainer::Shared contextContainer_;
|
||||
mutable std::mutex mutex_;
|
||||
mutable bool hasBeenMeasured_ = false;
|
||||
mutable Size cachedMeasurement_{};
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* 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 "AndroidSwitchShadowNode.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
extern const char AndroidSwitchComponentName[] = "AndroidSwitch";
|
||||
|
||||
void AndroidSwitchShadowNode::setAndroidSwitchMeasurementsManager(
|
||||
const std::shared_ptr<AndroidSwitchMeasurementsManager>
|
||||
&measurementsManager) {
|
||||
ensureUnsealed();
|
||||
measurementsManager_ = measurementsManager;
|
||||
}
|
||||
|
||||
#pragma mark - LayoutableShadowNode
|
||||
|
||||
Size AndroidSwitchShadowNode::measure(
|
||||
LayoutConstraints layoutConstraints) const {
|
||||
return measurementsManager_->measure(layoutConstraints);
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* 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 "AndroidSwitchMeasurementsManager.h"
|
||||
|
||||
#include <react/components/rncore/EventEmitters.h>
|
||||
#include <react/components/rncore/Props.h>
|
||||
#include <react/components/view/ConcreteViewShadowNode.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
extern const char AndroidSwitchComponentName[];
|
||||
|
||||
/*
|
||||
* `ShadowNode` for <AndroidSwitch> component.
|
||||
*/
|
||||
class AndroidSwitchShadowNode final : public ConcreteViewShadowNode<
|
||||
AndroidSwitchComponentName,
|
||||
AndroidSwitchProps,
|
||||
AndroidSwitchEventEmitter> {
|
||||
public:
|
||||
using ConcreteViewShadowNode::ConcreteViewShadowNode;
|
||||
|
||||
// Associates a shared `AndroidSwitchMeasurementsManager` with the node.
|
||||
void setAndroidSwitchMeasurementsManager(
|
||||
const std::shared_ptr<AndroidSwitchMeasurementsManager>
|
||||
&measurementsManager);
|
||||
|
||||
#pragma mark - LayoutableShadowNode
|
||||
|
||||
Size measure(LayoutConstraints layoutConstraints) const override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<AndroidSwitchMeasurementsManager> measurementsManager_;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
Загрузка…
Ссылка в новой задаче