Support View Manager Commands
Summary: Supporting View Manager Commands on the new UIManager in Fabric. This is needed for things like scrollTo on ScrollView. Reviewed By: JoshuaGross Differential Revision: D16175575 fbshipit-source-id: a74effdf7e47b56a150a4e3fb6c4d787659e0250
This commit is contained in:
Родитель
5ca10c7caa
Коммит
6f09dc03bf
|
@ -102,6 +102,11 @@ typedef NS_OPTIONS(NSInteger, RNComponentViewUpdateMask) {
|
|||
- (void)updateLayoutMetrics:(facebook::react::LayoutMetrics const &)layoutMetrics
|
||||
oldLayoutMetrics:(facebook::react::LayoutMetrics const &)oldLayoutMetrics;
|
||||
|
||||
/*
|
||||
* Called when receiving a command
|
||||
*/
|
||||
- (void)handleCommand:(NSString const *)commandName args:(NSArray const *)args;
|
||||
|
||||
/*
|
||||
* Called right after all update methods were called for a particular component view.
|
||||
* Useful for performing updates that require knowledge of several independent aspects of the compound mounting change
|
||||
|
|
|
@ -32,10 +32,15 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
- (void)scheduleTransaction:(facebook::react::MountingCoordinator::Shared const &)mountingCoordinator;
|
||||
|
||||
/**
|
||||
* Dispatch a command to be performed on the main thread.
|
||||
* Can be called from any thread.
|
||||
*/
|
||||
- (void)dispatchCommand:(ReactTag)reactTag commandName:(NSString *)commandName args:(NSArray *)args;
|
||||
|
||||
- (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag
|
||||
changedProps:(NSDictionary *)props
|
||||
componentDescriptor:(const facebook::react::ComponentDescriptor &)componentDescriptor;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -225,6 +225,22 @@ static void RNPerformMountInstructions(ShadowViewMutationList const &mutations,
|
|||
});
|
||||
}
|
||||
|
||||
- (void)dispatchCommand:(ReactTag)reactTag commandName:(NSString *)commandName args:(NSArray *)args
|
||||
{
|
||||
if (RCTIsMainQueue()) {
|
||||
// Already on the proper thread, so:
|
||||
// * No need to do a thread jump;
|
||||
// * No need to allocate a block.
|
||||
[self synchronouslyDispatchCommandOnUIThread:reactTag commandName:commandName args:args];
|
||||
return;
|
||||
}
|
||||
|
||||
RCTExecuteOnMainQueue(^{
|
||||
RCTAssertMainQueue();
|
||||
[self synchronouslyDispatchCommandOnUIThread:reactTag commandName:commandName args:args];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)mountMutations:(MountingCoordinator::Shared const &)mountingCoordinator
|
||||
{
|
||||
SystraceSection s("-[RCTMountingManager mountMutations:]");
|
||||
|
@ -253,4 +269,13 @@ static void RNPerformMountInstructions(ShadowViewMutationList const &mutations,
|
|||
[componentView updateProps:newProps oldProps:oldProps];
|
||||
}
|
||||
|
||||
- (void)synchronouslyDispatchCommandOnUIThread:(ReactTag)reactTag
|
||||
commandName:(NSString *)commandName
|
||||
args:(NSArray *)args
|
||||
{
|
||||
RCTAssertMainQueue();
|
||||
UIView<RCTComponentViewProtocol> *componentView = [_componentViewRegistry componentViewByTag:reactTag];
|
||||
[componentView handleCommand:commandName args:args];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -60,6 +60,11 @@ using namespace facebook::react;
|
|||
// Default implementation does nothing.
|
||||
}
|
||||
|
||||
- (void)handleCommand:(NSString *)commandName args:(NSArray *)args
|
||||
{
|
||||
// Default implementation does nothing.
|
||||
}
|
||||
|
||||
- (void)updateLayoutMetrics:(LayoutMetrics const &)layoutMetrics
|
||||
oldLayoutMetrics:(LayoutMetrics const &)oldLayoutMetrics
|
||||
{
|
||||
|
|
|
@ -28,6 +28,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (void)schedulerDidFinishTransaction:(facebook::react::MountingCoordinator::Shared const &)mountingCoordinator;
|
||||
|
||||
- (void)schedulerDidDispatchCommand:(facebook::react::ShadowView const &)shadowView
|
||||
commandName:(std::string const &)commandName
|
||||
args:(folly::dynamic const)args;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,6 +34,15 @@ class SchedulerDelegateProxy : public SchedulerDelegate {
|
|||
// Preemptive allocation of native views on iOS does not require this call.
|
||||
}
|
||||
|
||||
void schedulerDidDispatchCommand(
|
||||
const ShadowView &shadowView,
|
||||
const std::string &commandName,
|
||||
const folly::dynamic args) override
|
||||
{
|
||||
RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_;
|
||||
[scheduler.delegate schedulerDidDispatchCommand:shadowView commandName:commandName args:args];
|
||||
}
|
||||
|
||||
private:
|
||||
void *scheduler_;
|
||||
};
|
||||
|
|
|
@ -321,6 +321,17 @@ using namespace facebook::react;
|
|||
[_mountingManager scheduleTransaction:mountingCoordinator];
|
||||
}
|
||||
|
||||
- (void)schedulerDidDispatchCommand:(facebook::react::ShadowView const &)shadowView
|
||||
commandName:(std::string const &)commandName
|
||||
args:(folly::dynamic const)args
|
||||
{
|
||||
ReactTag tag = shadowView.tag;
|
||||
NSString *commandStr = [[NSString alloc] initWithUTF8String:commandName.c_str()];
|
||||
NSArray *argsArray = convertFollyDynamicToId(args);
|
||||
|
||||
[self->_mountingManager dispatchCommand:tag commandName:commandStr args:argsArray];
|
||||
}
|
||||
|
||||
- (void)addObserver:(id<RCTSurfacePresenterObserver>)observer
|
||||
{
|
||||
std::unique_lock<better::shared_mutex> lock(_observerListMutex);
|
||||
|
|
|
@ -248,6 +248,11 @@ inline local_ref<ReadableMap::javaobject> castReadableMap(
|
|||
return make_local(reinterpret_cast<ReadableMap::javaobject>(nativeMap.get()));
|
||||
}
|
||||
|
||||
inline local_ref<ReadableArray::javaobject> castReadableArray(
|
||||
local_ref<ReadableNativeArray::javaobject> nativeArray) {
|
||||
return make_local(reinterpret_cast<ReadableArray::javaobject>(nativeArray.get()));
|
||||
}
|
||||
|
||||
// TODO: this method will be removed when binding for components are code-gen
|
||||
local_ref<JString> getPlatformComponentName(const ShadowView &shadowView) {
|
||||
local_ref<JString> componentName;
|
||||
|
@ -672,6 +677,31 @@ void Binding::schedulerDidRequestPreliminaryViewAllocation(
|
|||
isLayoutableShadowNode);
|
||||
}
|
||||
|
||||
void Binding::schedulerDidDispatchCommand(
|
||||
const ShadowView &shadowView,
|
||||
std::string const &commandName,
|
||||
folly::dynamic const args) {
|
||||
|
||||
jni::global_ref<jobject> localJavaUIManager = getJavaUIManager();
|
||||
if (!localJavaUIManager) {
|
||||
LOG(ERROR) << "Binding::schedulerDidDispatchCommand: JavaUIManager disappeared";
|
||||
return;
|
||||
}
|
||||
|
||||
static auto dispatchCommand =
|
||||
jni::findClassStatic(UIManagerJavaDescriptor)
|
||||
->getMethod<void(
|
||||
jint, jstring, ReadableArray::javaobject)>(
|
||||
"dispatchCommand");
|
||||
|
||||
local_ref<JString> command = make_jstring(commandName);
|
||||
|
||||
local_ref<ReadableArray::javaobject> argsArray = castReadableArray(
|
||||
ReadableNativeArray::newObjectCxxArgs(args));
|
||||
|
||||
dispatchCommand(localJavaUIManager, shadowView.tag, command.get(), argsArray.get());
|
||||
}
|
||||
|
||||
void Binding::registerNatives() {
|
||||
registerHybrid(
|
||||
{makeNativeMethod("initHybrid", Binding::initHybrid),
|
||||
|
|
|
@ -82,6 +82,11 @@ class Binding : public jni::HybridClass<Binding>, public SchedulerDelegate {
|
|||
const SurfaceId surfaceId,
|
||||
const ShadowView &shadowView);
|
||||
|
||||
void schedulerDidDispatchCommand(
|
||||
const ShadowView &shadowView,
|
||||
std::string const &commandName,
|
||||
folly::dynamic const args);
|
||||
|
||||
void setPixelDensity(float pointScaleFactor);
|
||||
|
||||
void uninstallFabricUIManager();
|
||||
|
|
|
@ -258,5 +258,17 @@ void Scheduler::uiManagerDidCreateShadowNode(
|
|||
}
|
||||
}
|
||||
|
||||
void Scheduler::uiManagerDispatchCommand(
|
||||
const SharedShadowNode &shadowNode,
|
||||
std::string const &commandName,
|
||||
folly::dynamic const args) {
|
||||
SystraceSection s("Scheduler::uiManagerDispatchCommand");
|
||||
|
||||
if (delegate_) {
|
||||
auto shadowView = ShadowView(*shadowNode);
|
||||
delegate_->schedulerDidDispatchCommand(shadowView, commandName, args);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
|
|
|
@ -86,6 +86,10 @@ class Scheduler final : public UIManagerDelegate, public ShadowTreeDelegate {
|
|||
const SharedShadowNodeUnsharedList &rootChildNodes) override;
|
||||
void uiManagerDidCreateShadowNode(
|
||||
const SharedShadowNode &shadowNode) override;
|
||||
void uiManagerDispatchCommand(
|
||||
const SharedShadowNode &shadowNode,
|
||||
std::string const &commandName,
|
||||
folly::dynamic const args) override;
|
||||
|
||||
#pragma mark - ShadowTreeDelegate
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ class SchedulerDelegate {
|
|||
public:
|
||||
/*
|
||||
* Called right after Scheduler computed (and laid out) a new updated version
|
||||
* of the tree and calculated a set of mutations which are suffisient
|
||||
* of the tree and calculated a set of mutations which are sufficient
|
||||
* to construct a new one.
|
||||
*/
|
||||
virtual void schedulerDidFinishTransaction(
|
||||
|
@ -35,6 +35,11 @@ class SchedulerDelegate {
|
|||
SurfaceId surfaceId,
|
||||
const ShadowView &shadowView) = 0;
|
||||
|
||||
virtual void schedulerDidDispatchCommand(
|
||||
const ShadowView &shadowView,
|
||||
std::string const &commandName,
|
||||
folly::dynamic const args) = 0;
|
||||
|
||||
virtual ~SchedulerDelegate() noexcept = default;
|
||||
};
|
||||
|
||||
|
|
|
@ -167,6 +167,15 @@ void UIManager::updateState(
|
|||
});
|
||||
}
|
||||
|
||||
void UIManager::dispatchCommand(
|
||||
const SharedShadowNode &shadowNode,
|
||||
std::string const &commandName,
|
||||
folly::dynamic const args) const {
|
||||
if (delegate_) {
|
||||
delegate_->uiManagerDispatchCommand(shadowNode, commandName, args);
|
||||
}
|
||||
}
|
||||
|
||||
void UIManager::setShadowTreeRegistry(ShadowTreeRegistry *shadowTreeRegistry) {
|
||||
shadowTreeRegistry_ = shadowTreeRegistry;
|
||||
}
|
||||
|
|
|
@ -75,6 +75,11 @@ class UIManager {
|
|||
const SharedShadowNode &shadowNode,
|
||||
const StateData::Shared &rawStateData) const;
|
||||
|
||||
void dispatchCommand(
|
||||
const SharedShadowNode &shadowNode,
|
||||
std::string const &commandName,
|
||||
folly::dynamic const args) const;
|
||||
|
||||
ShadowTreeRegistry *shadowTreeRegistry_;
|
||||
SharedComponentDescriptorRegistry componentDescriptorRegistry_;
|
||||
UIManagerDelegate *delegate_;
|
||||
|
|
|
@ -141,7 +141,7 @@ jsi::Value UIManagerBinding::get(
|
|||
runtime,
|
||||
uiManager.createNode(
|
||||
tagFromValue(runtime, arguments[0]),
|
||||
componentNameFromValue(runtime, arguments[1]),
|
||||
stringFromValue(runtime, arguments[1]),
|
||||
surfaceIdFromValue(runtime, arguments[2]),
|
||||
RawProps(runtime, arguments[3]),
|
||||
eventTargetFromValue(runtime, arguments[4], arguments[0])));
|
||||
|
@ -332,6 +332,25 @@ jsi::Value UIManagerBinding::get(
|
|||
});
|
||||
}
|
||||
|
||||
if (methodName == "dispatchCommand") {
|
||||
return jsi::Function::createFromHostFunction(
|
||||
runtime,
|
||||
name,
|
||||
3,
|
||||
[&uiManager](
|
||||
jsi::Runtime &runtime,
|
||||
const jsi::Value &thisValue,
|
||||
const jsi::Value *arguments,
|
||||
size_t count) -> jsi::Value {
|
||||
uiManager.dispatchCommand(
|
||||
shadowNodeFromValue(runtime, arguments[0]),
|
||||
stringFromValue(runtime, arguments[1]),
|
||||
commandArgsFromValue(runtime, arguments[2]));
|
||||
|
||||
return jsi::Value::undefined();
|
||||
});
|
||||
}
|
||||
|
||||
// Legacy API
|
||||
if (methodName == "measureLayout") {
|
||||
return jsi::Function::createFromHostFunction(
|
||||
|
|
|
@ -20,7 +20,7 @@ class UIManagerDelegate {
|
|||
public:
|
||||
/*
|
||||
* Called right after the new/updated Shadow Node tree is constructed.
|
||||
* The tree is not layed out and not sealed at this time.
|
||||
* The tree is not laid out and not sealed at this time.
|
||||
*/
|
||||
virtual void uiManagerDidFinishTransaction(
|
||||
SurfaceId surfaceId,
|
||||
|
@ -28,12 +28,20 @@ class UIManagerDelegate {
|
|||
|
||||
/*
|
||||
* Called each time when UIManager constructs a new Shadow Node. Receiver
|
||||
* maight use this to preluminary optimistically allocate a new native view
|
||||
* might use this to optimistically allocate a new native view
|
||||
* instances.
|
||||
*/
|
||||
virtual void uiManagerDidCreateShadowNode(
|
||||
const SharedShadowNode &shadowNode) = 0;
|
||||
|
||||
/*
|
||||
* Called when UIManager wants to dispatch a command to the mounting layer.
|
||||
*/
|
||||
virtual void uiManagerDispatchCommand(
|
||||
const SharedShadowNode &shadowNode,
|
||||
std::string const &commandName,
|
||||
folly::dynamic const args) = 0;
|
||||
|
||||
virtual ~UIManagerDelegate() noexcept = default;
|
||||
};
|
||||
|
||||
|
|
|
@ -83,11 +83,17 @@ inline static SurfaceId surfaceIdFromValue(
|
|||
return (SurfaceId)value.getNumber();
|
||||
}
|
||||
|
||||
inline static std::string componentNameFromValue(
|
||||
inline static std::string stringFromValue(
|
||||
jsi::Runtime &runtime,
|
||||
const jsi::Value &value) {
|
||||
return value.getString(runtime).utf8(runtime);
|
||||
}
|
||||
|
||||
inline static folly::dynamic commandArgsFromValue(
|
||||
jsi::Runtime &runtime,
|
||||
const jsi::Value &value) {
|
||||
return jsi::dynamicFromValue(runtime, value);
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
|
|
Загрузка…
Ссылка в новой задаче