Fabric: Support for `onLayout` event

Summary: `onLayout` event is fired when some layoutable node got inserted or updated (with changed layout) during commit phase.

Reviewed By: fkgozali

Differential Revision: D8119826

fbshipit-source-id: 831003c88fe5c4358a80328aa715be80e484b52e
This commit is contained in:
Valentin Shergin 2018-05-24 18:23:13 -07:00 committed by Facebook Github Bot
parent 0be26092a5
commit 9b7f6abd87
4 changed files with 64 additions and 0 deletions

View File

@ -76,6 +76,8 @@ void ShadowTree::complete(UnsharedRootShadowNode newRootShadowNode) {
);
if (commit(newRootShadowNode)) {
emitLayoutEvents(instructions);
if (delegate_) {
delegate_->shadowTreeDidCommit(shared_from_this(), instructions);
}
@ -93,6 +95,46 @@ bool ShadowTree::commit(const SharedRootShadowNode &newRootShadowNode) {
return true;
}
void ShadowTree::emitLayoutEvents(const TreeMutationInstructionList &instructions) {
for (auto &&instruction : instructions) {
auto &&type = instruction.getType();
// Only `Insertion` and `Replacement` instructions can affect layout metrics.
if (
type == TreeMutationInstruction::Insertion ||
type == TreeMutationInstruction::Replacement
) {
auto &&newShadowNode = instruction.getNewChildNode();
auto &&eventHandlers = newShadowNode->getEventHandlers();
auto &&viewEventHandlers = std::dynamic_pointer_cast<const ViewEventHandlers>(eventHandlers);
// Checking if particular shadow node supports `onLayout` event (part of `ViewEventHandlers`).
if (viewEventHandlers) {
// Now we know that both (old and new) shadow nodes must be `LayoutableShadowNode` subclasses.
assert(std::dynamic_pointer_cast<const LayoutableShadowNode>(newShadowNode));
// TODO(T29661055): Consider using `std::reinterpret_pointer_cast`.
auto &&newLayoutableShadowNode =
std::dynamic_pointer_cast<const LayoutableShadowNode>(newShadowNode);
// In case if we have `oldShadowNode`, we have to check that layout metrics have changed.
if (type == TreeMutationInstruction::Replacement) {
auto &&oldShadowNode = instruction.getOldChildNode();
assert(std::dynamic_pointer_cast<const LayoutableShadowNode>(oldShadowNode));
// TODO(T29661055): Consider using `std::reinterpret_pointer_cast`.
auto &&oldLayoutableShadowNode =
std::dynamic_pointer_cast<const LayoutableShadowNode>(oldShadowNode);
if (oldLayoutableShadowNode->getLayoutMetrics() == newLayoutableShadowNode->getLayoutMetrics()) {
continue;
}
}
viewEventHandlers->onLayout(newLayoutableShadowNode->getLayoutMetrics());
}
}
}
}
#pragma mark - Delegate
void ShadowTree::setDelegate(ShadowTreeDelegate *delegate) {

View File

@ -76,6 +76,7 @@ private:
UnsharedRootShadowNode cloneRootShadowNode(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const;
void complete(UnsharedRootShadowNode newRootShadowNode);
bool commit(const SharedRootShadowNode &newRootShadowNode);
void emitLayoutEvents(const TreeMutationInstructionList &instructions);
const Tag rootTag_;
SharedRootShadowNode rootShadowNode_;

View File

@ -24,5 +24,19 @@ void ViewEventHandlers::onAccessibilityMagicTap() const {
dispatchEvent("magicTap");
}
#pragma mark - Layout
void ViewEventHandlers::onLayout(const LayoutMetrics &layoutMetrics) const {
folly::dynamic payload = folly::dynamic::object();
auto &&frame = layoutMetrics.frame;
payload["layout"] = folly::dynamic::object
("x", frame.origin.x)
("y", frame.origin.y)
("width", frame.size.width)
("height", frame.size.height);
dispatchEvent("layout", payload);
}
} // namespace react
} // namespace facebook

View File

@ -9,6 +9,7 @@
#include <memory>
#include <fabric/core/EventHandlers.h>
#include <fabric/core/LayoutMetrics.h>
namespace facebook {
namespace react {
@ -24,9 +25,15 @@ public:
using EventHandlers::EventHandlers;
#pragma mark - Accessibility
void onAccessibilityAction(const std::string &name) const;
void onAccessibilityTap() const;
void onAccessibilityMagicTap() const;
#pragma mark - Layout
void onLayout(const LayoutMetrics &layoutMetrics) const;
};
} // namespace react