From 316383d709c007f8008d95d8d8e3a30da4f61014 Mon Sep 17 00:00:00 2001 From: Ted Janeczko Date: Thu, 22 Apr 2021 15:58:17 -0700 Subject: [PATCH 1/2] Add OnLayoutCalculated component lifecycle method --- .../litho/annotations/OnLayoutCalculated.java | 23 +++++++++++++++++++ .../facebook/litho/ComponentLifecycle.java | 7 ++++++ .../facebook/litho/DefaultInternalNode.java | 4 ++++ .../model/DelegateMethodDescriptions.java | 14 +++++++++++ 4 files changed, 48 insertions(+) create mode 100644 litho-annotations/src/main/java/com/facebook/litho/annotations/OnLayoutCalculated.java diff --git a/litho-annotations/src/main/java/com/facebook/litho/annotations/OnLayoutCalculated.java b/litho-annotations/src/main/java/com/facebook/litho/annotations/OnLayoutCalculated.java new file mode 100644 index 00000000000..2372be32fdb --- /dev/null +++ b/litho-annotations/src/main/java/com/facebook/litho/annotations/OnLayoutCalculated.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.facebook.litho.annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface OnLayoutCalculated {} diff --git a/litho-core/src/main/java/com/facebook/litho/ComponentLifecycle.java b/litho-core/src/main/java/com/facebook/litho/ComponentLifecycle.java index ee9f096643b..43d6443b383 100644 --- a/litho-core/src/main/java/com/facebook/litho/ComponentLifecycle.java +++ b/litho-core/src/main/java/com/facebook/litho/ComponentLifecycle.java @@ -394,6 +394,13 @@ protected void onBind(ComponentContext c, Object mountedContent) { */ protected void onBoundsDefined(ComponentContext c, ComponentLayout layout) {} + /** + * Called after the layout calculation is finished. + * + * @param c The {@link Context} used by this component. + */ + protected void onLayoutCalculated(ComponentContext c) {} + /** * Generate a tree of {@link ComponentLayout} representing the layout structure of the {@link * Component} and its sub-components. diff --git a/litho-core/src/main/java/com/facebook/litho/DefaultInternalNode.java b/litho-core/src/main/java/com/facebook/litho/DefaultInternalNode.java index cd4174c53c4..070dc89d470 100644 --- a/litho-core/src/main/java/com/facebook/litho/DefaultInternalNode.java +++ b/litho-core/src/main/java/com/facebook/litho/DefaultInternalNode.java @@ -411,6 +411,10 @@ && isLayoutDirectionRTL(c.getAndroidContext())) { mYogaNode.calculateLayout(width, height); + for (Component component : mComponents) { + component.onLayoutCalculated(mComponentContext); + } + return this; } diff --git a/litho-processor/src/main/java/com/facebook/litho/specmodels/model/DelegateMethodDescriptions.java b/litho-processor/src/main/java/com/facebook/litho/specmodels/model/DelegateMethodDescriptions.java index d3a81ccef9e..c4cbd7f0b6f 100644 --- a/litho-processor/src/main/java/com/facebook/litho/specmodels/model/DelegateMethodDescriptions.java +++ b/litho-processor/src/main/java/com/facebook/litho/specmodels/model/DelegateMethodDescriptions.java @@ -46,6 +46,7 @@ import com.facebook.litho.annotations.OnCreateMountContentPool; import com.facebook.litho.annotations.OnCreateTransition; import com.facebook.litho.annotations.OnDetached; +import com.facebook.litho.annotations.OnLayoutCalculated; import com.facebook.litho.annotations.OnError; import com.facebook.litho.annotations.OnLoadStyle; import com.facebook.litho.annotations.OnMeasure; @@ -162,6 +163,18 @@ public final class DelegateMethodDescriptions { .build())) .build(); + public static final DelegateMethodDescription ON_LAYOUT_CALCULATED = + DelegateMethodDescription.newBuilder() + .annotations(ImmutableList.of(AnnotationSpec.builder(Override.class).build())) + .accessType(Modifier.PROTECTED) + .returnType(TypeName.VOID) + .name("onLayoutCalculated") + .definedParameterTypes( + ImmutableList.of(ClassNames.COMPONENT_CONTEXT)) + .optionalParameterTypes( + ImmutableList.of(PROP, TREE_PROP, STATE, INJECT_PROP, CACHED_VALUE)) + .build(); + public static final DelegateMethodDescription ON_CREATE_INITIAL_STATE = DelegateMethodDescription.newBuilder() .annotations(ImmutableList.of(AnnotationSpec.builder(Override.class).build())) @@ -521,6 +534,7 @@ public int compare(Class lhs, Class layoutSpecDelegateMethodsMap.put(ShouldUpdate.class, SHOULD_UPDATE); layoutSpecDelegateMethodsMap.put(OnAttached.class, ON_ATTACHED); layoutSpecDelegateMethodsMap.put(OnDetached.class, ON_DETACHED); + layoutSpecDelegateMethodsMap.put(OnLayoutCalculated.class, ON_LAYOUT_CALCULATED); LAYOUT_SPEC_DELEGATE_METHODS_MAP = Collections.unmodifiableMap(layoutSpecDelegateMethodsMap); Map, DelegateMethodDescription> mountSpecDelegateMethodsMap = From b1cd30ab72d5da3d0ba260a2da5b0a637f72cc56 Mon Sep 17 00:00:00 2001 From: Ted Janeczko Date: Fri, 23 Apr 2021 10:07:55 -0700 Subject: [PATCH 2/2] Add tests --- .../main/java/com/facebook/litho/LifecycleStep.java | 1 + .../litho/widget/LayoutSpecLifecycleTesterSpec.java | 6 ++++++ .../com/facebook/litho/LayoutSpecLifecycleTest.java | 10 +++++++--- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/litho-it/src/main/java/com/facebook/litho/LifecycleStep.java b/litho-it/src/main/java/com/facebook/litho/LifecycleStep.java index 05a9ff76475..5c09e6f4d1a 100644 --- a/litho-it/src/main/java/com/facebook/litho/LifecycleStep.java +++ b/litho-it/src/main/java/com/facebook/litho/LifecycleStep.java @@ -26,6 +26,7 @@ public enum LifecycleStep { ON_PREPARE, ON_MEASURE, ON_BOUNDS_DEFINED, + ON_LAYOUT_CALCULATED, ON_CREATE_MOUNT_CONTENT, ON_MOUNT, ON_UNMOUNT, diff --git a/litho-it/src/main/java/com/facebook/litho/widget/LayoutSpecLifecycleTesterSpec.java b/litho-it/src/main/java/com/facebook/litho/widget/LayoutSpecLifecycleTesterSpec.java index b7a8780919b..24b3426a43c 100644 --- a/litho-it/src/main/java/com/facebook/litho/widget/LayoutSpecLifecycleTesterSpec.java +++ b/litho-it/src/main/java/com/facebook/litho/widget/LayoutSpecLifecycleTesterSpec.java @@ -42,6 +42,7 @@ import com.facebook.litho.annotations.OnCreateTreeProp; import com.facebook.litho.annotations.OnDetached; import com.facebook.litho.annotations.OnEvent; +import com.facebook.litho.annotations.OnLayoutCalculated; import com.facebook.litho.annotations.OnUpdateState; import com.facebook.litho.annotations.OnUpdateStateWithTransition; import com.facebook.litho.annotations.Param; @@ -113,6 +114,11 @@ static void onDetached(ComponentContext c, @Prop List st steps.add(new StepInfo(LifecycleStep.ON_DETACHED)); } + @OnLayoutCalculated + static void onLayoutCalculated(ComponentContext c, @Prop List steps) { + steps.add(new StepInfo(LifecycleStep.ON_LAYOUT_CALCULATED)); + } + @OnUpdateState static void updateState(@Param List stepsAsParam) { stepsAsParam.add(new StepInfo(LifecycleStep.ON_UPDATE_STATE)); diff --git a/litho-it/src/test/java/com/facebook/litho/LayoutSpecLifecycleTest.java b/litho-it/src/test/java/com/facebook/litho/LayoutSpecLifecycleTest.java index 72db2472339..c69861a28b9 100644 --- a/litho-it/src/test/java/com/facebook/litho/LayoutSpecLifecycleTest.java +++ b/litho-it/src/test/java/com/facebook/litho/LayoutSpecLifecycleTest.java @@ -69,6 +69,7 @@ public void lifecycle_onSetRootWithLayout_shouldCallLifecycleMethods() { LifecycleStep.ON_CALCULATE_CACHED_VALUE, LifecycleStep.ON_CREATE_LAYOUT, LifecycleStep.ON_CREATE_TRANSITION, + LifecycleStep.ON_LAYOUT_CALCULATED, LifecycleStep.ON_ATTACHED); ComponentsConfiguration.isAnimationDisabled = true; } @@ -108,7 +109,8 @@ public void lifecycle_subsequentSetRoot_shouldCallLifecycleMethod() { .containsExactly( LifecycleStep.ON_CREATE_TREE_PROP, LifecycleStep.ON_CALCULATE_CACHED_VALUE, - LifecycleStep.ON_CREATE_LAYOUT); + LifecycleStep.ON_CREATE_LAYOUT, + LifecycleStep.ON_LAYOUT_CALCULATED); } @Test @@ -132,7 +134,8 @@ public void lifecycle_updateState_shouldCallLifecycleMethod() { LifecycleStep.ON_UPDATE_STATE, LifecycleStep.ON_CREATE_TREE_PROP, LifecycleStep.ON_CALCULATE_CACHED_VALUE, - LifecycleStep.ON_CREATE_LAYOUT); + LifecycleStep.ON_CREATE_LAYOUT, + LifecycleStep.ON_LAYOUT_CALCULATED); ComponentsConfiguration.isReconciliationEnabled = true; } @@ -158,7 +161,8 @@ public void lifecycle_updateStateWithTransition_shouldCallLifecycleMethod() { LifecycleStep.ON_UPDATE_STATE_WITH_TRANSITION, LifecycleStep.ON_CREATE_TREE_PROP, LifecycleStep.ON_CALCULATE_CACHED_VALUE, - LifecycleStep.ON_CREATE_LAYOUT); + LifecycleStep.ON_CREATE_LAYOUT, + LifecycleStep.ON_LAYOUT_CALCULATED); ComponentsConfiguration.isReconciliationEnabled = true; }