diff --git a/docs/_data/nav_docs.yml b/docs/_data/nav_docs.yml index e3e1654429c..340bdc7912c 100644 --- a/docs/_data/nav_docs.yml +++ b/docs/_data/nav_docs.yml @@ -47,16 +47,6 @@ items: - id: debugging - id: dev-options -- title: Widgets - items: - - id: widgets-card - - id: widgets-edittext - - id: widgets-horizontalscroll - - id: widgets-image - - id: widgets-progress - - id: widgets-recycler - - id: widgets-solidcolor - - id: widgets-text - title: Contributing items: - id: contributing diff --git a/docs/_docs/accessibility.md b/docs/_docs/accessibility.md index 944e8605df9..d8b72449c4b 100644 --- a/docs/_docs/accessibility.md +++ b/docs/_docs/accessibility.md @@ -40,7 +40,7 @@ This is only applicable for components which mount drawables, since if the compo ## Extra accessibility nodes -On more complex mount specs that need to expose extra nodes to the accessibility framework, you'll have to implement three extra methods: +On more complex mount specs that need to expose extra nodes to the accessibility framework, you'll have to implement three extra methods with the following annotations: - **GetExtraAccessibilityNodesCount**: Returns number of extra accessibility nodes exposed by the component. - **OnPopulateExtraAccessibilityNode**: Populates the extra accessibility node with the given bounds. @@ -96,7 +96,7 @@ Text.create(c) .onInitializeAccessiblityNodeInfoHandler(MyComponent.onInitializeAccessibilityNodeInfoEvent(c)) ``` -One of the best features of `AccessibilityDelegate`s in general is their reusability even across different types of `View`s. This can also be achieved within the Components framework by creating a wrapper spec that takes in a component and adds the desired event handlers. For example, let's say we want to have a Component that appends "please" to every `AccessibilityEvent` that it announces. +One of the best features of `AccessibilityDelegate`s in general is their reusability even across different types of `View`s. This can also be achieved within Litho by creating a wrapper spec that takes in a component and adds the desired event handlers. For example, let's say we want to have a Component that appends "please" to every `AccessibilityEvent` that it announces. ```java @LayoutSpec diff --git a/docs/_docs/best-practices.md b/docs/_docs/best-practices.md index f1f7f5f6cd1..11df21d120b 100644 --- a/docs/_docs/best-practices.md +++ b/docs/_docs/best-practices.md @@ -56,7 +56,7 @@ class MyComponentSpec { ## Props vs State -Litho components have two types of data models: Props and State. It's important to understand the difference between the two to know when you need to use each of them. +Litho components have two types of data models: [Props](/docs/props) and [State](/docs/state). It's important to understand the difference between the two to know when you need to use each of them. Props are for passing data down the tree from a component to its children. They are useful for defining the static part of a component's model, because props cannot be changed. @@ -77,6 +77,6 @@ Let's take the example of a list of radio buttons, where you cannot have multipl Components are esentially functions that receive data as parameters and are immutable. When the props or state of a component change, the framework will create a new component instance with the updated information, because the previous component cannot be mutated. -While the component itself is immutable, it is easy to make it not thread safe by using mutable objects for props and state. Litho computes layout on a background thread, and if the objects that make up a component's props or state are mutated from another thread, then this may result in rendering different outputs for the same component. +While the component itself is immutable, it is easy to make it not thread safe by using mutable objects for props and state. Litho computes [layout on a background thread](/docs/asynchronous-layout), and if the objects that make up a component's props or state are mutated from another thread, then this may result in rendering different outputs for the same component. You must keep your props and state either as primitive types which are inherently immutable, or if that's not possible make sure that the objects that you are using are immutable. diff --git a/docs/_docs/codegen.md b/docs/_docs/codegen.md index c35b4b210d8..6caf017e05b 100644 --- a/docs/_docs/codegen.md +++ b/docs/_docs/codegen.md @@ -5,7 +5,7 @@ layout: docs permalink: /docs/codegen --- -As explained in [Writing Components](/docs/writing-components), Litho relies on code generation in order to create *Components* from *Component Specs*. This process utilises intermediate *ComponentSpec* representations called *SpecModels*, which are immutable java objects. +As explained in [Writing Components](/docs/writing-components), Litho relies on code generation in order to create *Components* from *Component Specs*. This process utilises intermediate *ComponentSpec* representations called [SpecModels](/javadoc/com/facebook/litho/specmodels/model/SpecModel), which are immutable java objects. Code generation comprises three main steps: @@ -14,12 +14,12 @@ Code generation comprises three main steps: - Component generation from a given Spec Model. #### Spec Model Creation -Spec models are created at compile time using an annotation processor, which is a tool in javac for scanning and processing annotations. The Components annotation processor will process the annotations, methods and fields on your Component Specs and create a Spec Model for each one. +Spec models are created at compile time using an annotation processor, which is a tool in javac for scanning and processing annotations. The Litho annotation processor will process the annotations, methods and fields on your Component Specs and create a Spec Model for each one. In the future, we will add the ability to create Spec Models in other ways. For example, we want to be able to create Spec Models directly in Android Studio/Intellij, which would allow us to generate Components without having to build the source code. #### Spec Model Validation -Spec Models have a method called `validate()`, which returns a list of `SpecModelValidationError`s. If this list is empty then the Spec is well-formed and may be used to generate a valid Component. If not, then it will contain a list of errors that need fixing up before a valid Component may be generated. +Spec Models have a method called `validate()`, which returns a list of [SpecModelValidationErrors](/javadoc/com/facebook/litho/specmodels/model/SpecModelValidationError). If this list is empty then the Spec is well-formed and may be used to generate a valid Component. If not, then it will contain a list of errors that need fixing up before a valid Component may be generated. #### Component Generation If the validation step on a Spec Model is successful, then the `generate` method may be called. This will create a [Javapoet](https://github.com/square/javapoet) `TypeSpec` which can then be easily used to create a Component class file. diff --git a/docs/_docs/custom-layout.md b/docs/_docs/custom-layout.md index c1edca3f5f3..8f954418603 100644 --- a/docs/_docs/custom-layout.md +++ b/docs/_docs/custom-layout.md @@ -6,7 +6,7 @@ permalink: /docs/custom-layout.html --- Litho relies on [Yoga](https://facebook.github.io/yoga/), a powerful layout engine that is able to create very complex UIs, for layout calculations. However, there are few exceptions where Yoga is not enough and you may need to implement your own measuring and layout. -Litho provides a custom layout API for accessing size information while the [ComponentTree](link to javadoc) is being created and measured, as well as the possibility to measure a component in isolation. +Litho provides a custom layout API for accessing size information while the [ComponentTree](/javadoc/com/facebook/litho/ComponentTree) is being created and measured, as well as the possibility to measure a component in isolation. > **IMPORTANT**: This API comes with a **non-negligible** performance overhead. Therefore, it is advisable to only use it when it is absolutely necessary. @@ -51,7 +51,7 @@ In the following example, a `Text` component is measured to check if the given t ```java @LayoutSpec -public class MyComponentSpec { +class MyComponentSpec { @OnCreateLayoutWithSizeSpec static ComponentLayout onCreateLayoutWithSizeSpec( diff --git a/docs/_docs/dev-options.md b/docs/_docs/dev-options.md index d7ff06011e0..875b9b06790 100644 --- a/docs/_docs/dev-options.md +++ b/docs/_docs/dev-options.md @@ -6,7 +6,7 @@ permalink: /docs/developer-options --- In addition to Stetho we also provide two compile time flags for visualizing the component hierarchy of your application. These are similar to Android's show view bounds internal setting but because Litho does not always use Android Views we have implemented our own to make it more helpful. -Within the `ComponentsConfiguration` class there are two fields which control this. +Within the [ComponentsConfiguration](/javadoc/com/facebook/litho/config/ComponentsConfiguration) class there are two fields which control this. ### debugHighlightInteractiveBounds Highlight the interactive bounds of components as well as their expanded touch bounds, if present. diff --git a/docs/_docs/events-overview.md b/docs/_docs/events-overview.md index ca344d6d626..80e86dcbd77 100644 --- a/docs/_docs/events-overview.md +++ b/docs/_docs/events-overview.md @@ -5,11 +5,11 @@ layout: docs permalink: /docs/events-overview --- -The framework provides a general-purpose API to connect components through events. Events are declared as a POJO with an `@Event` annotation. By convention we name suffix Event class names with *Event*. Event declarations may not be inner classes of your `LayoutSpec` or `MountSpec`. This is by design as specs are supposed to be a private concept and events can be used across multiple components. +The framework provides a general-purpose API to connect components through events. Events are declared as a POJO with an `@Event` annotation. By convention we suffix Event class names with *Event*. Event declarations may not be inner classes of your `LayoutSpec` or `MountSpec`. This is by design as specs are supposed to be a private concept and events can be used across multiple components. ```java @Event -private class ColorChangedEvent { +public class ColorChangedEvent { public int color; } ``` @@ -18,7 +18,7 @@ In this example we will assume we have a component called `ColorComponent`. To i ```java @LayoutSpec(events = { ColorChangedEvent.class }) -public class ColorComponentSpec { +class ColorComponentSpec { ... @OnCreateLayout static ComponentLayout onCreateLayout( @@ -36,7 +36,7 @@ public class ColorComponentSpec { For an event of type `FooEvent`, this will auto-generate a matching `dispatchFooEvent` method and an event identifier that will used by event callbacks. -The `dispatchFooEvent` method takes an `EventHandler` as the first argument followed by the list of attributes defined in your `@Event` class. An `EventHandler` is essentially a generic listener interface to connect components through events. The convention is to have an `EventHandler` prop for each event exposed by your component. +The `dispatchFooEvent` method takes an [EventHandler](/javadoc/com/facebook/litho/EventHandler) as the first argument followed by the list of attributes defined in your `@Event` class. An `EventHandler` is essentially a generic listener interface to connect components through events. The convention is to have an `EventHandler` prop for each event exposed by your component. In the example above, `ColorComponent` takes a `colorChangedHandler` as prop and dispatches the `ColorChangedEvent` to it with the generated `dispatchColorChangedEvent()` method. @@ -52,7 +52,7 @@ For example, here's how a component would define a handler for the `ColorChanged ```java @LayoutSpec -public class MyComponentSpec { +class MyComponentSpec { @OnCreateLayout static ComponentLayout onCreateLayout( @@ -86,7 +86,7 @@ As you can see, `@OnEvent` callbacks have access to all component props just lik ```java @LayoutSpec -public class FacePileComponentSpec { +class FacePileComponentSpec { @OnCreateLayout static ComponentLayout onCreateLayout( diff --git a/docs/_docs/events-touch-handling.md b/docs/_docs/events-touch-handling.md index 761b434fc86..e525be1069f 100644 --- a/docs/_docs/events-touch-handling.md +++ b/docs/_docs/events-touch-handling.md @@ -12,21 +12,34 @@ This means all layout builders have an `EventHandler` prop named `clickHandler`, For example, setting a click handler on any component is as simple as: ```java -Text.create(c) - .text(title) - .withLayout() - .clickHandler(MyComponent.onClick(c)) +@LayoutSpec +class MyComponentSpec { + + @OnCreateLayout + static ComponentLayout onCreateLayout( + ComponentContext c, + @Prop String title) { + return Text.create(c) + .text(title) + .withLayout() + .clickHandler(MyComponent.onClick(c)) + } +} ``` And the callback within MyComponentSpec would look like this: ```java -@OnEvent(ClickEvent.class) -static void onClick( - ComponentContext c, - @FromEvent View view, - @Prop String someProp) { - // Handle click here. +@LayoutSpec +class MyComponentSpec { +... + @OnEvent(ClickEvent.class) + static void onClick( + ComponentContext c, + @FromEvent View view, + @Prop String someProp) { + // Handle click here. + } } ``` diff --git a/docs/_docs/inc-mount.md b/docs/_docs/inc-mount.md index 9b3a95be33b..5ee182c0c4c 100644 --- a/docs/_docs/inc-mount.md +++ b/docs/_docs/inc-mount.md @@ -7,7 +7,7 @@ permalink: /docs/inc-mount ## Manual incremental mount -If you're not using `RecyclerComponent`, you can still integrate incremental mount in your existing UI implementation. You'll have to explicitly notify the framework every time the `ComponentView`'s visible region changes, by calling: +If you're not using the [Recycler](javadoc/com/facebook/litho/widget/Recycler) component, you can still integrate [incremental mount](/docs/intro#incremental-mount) in your existing UI implementation. You'll have to explicitly notify the framework every time the `ComponentView`'s visible region changes, by calling: ```java myComponentView.performIncrementalMount(); diff --git a/docs/_docs/layout-specs.md b/docs/_docs/layout-specs.md index 6e07b33b76e..1df4b8bc287 100644 --- a/docs/_docs/layout-specs.md +++ b/docs/_docs/layout-specs.md @@ -7,7 +7,7 @@ permalink: /docs/layout-specs A *layout spec* is the logical equivalent of a composite view on Android. It simply groups existing components together in an immutable layout tree. -Implementing a layout spec is very simple: you only need to write one method annotated with `@OnCreateLayout` which returns an immutable tree of `ComponentLayout` objects. +Implementing a layout spec is very simple: you only need to write one method annotated with `@OnCreateLayout` which returns an immutable tree of [ComponentLayout](/javadoc/com/facebook/litho/ComponentLayout) objects. Let's start with a simple example: @@ -17,14 +17,14 @@ public class MyComponentSpec { @OnCreateLayout static ComponentLayout onCreateLayout( ComponentContext c, - @Prop Uri imageUri, + @Prop int color, @Prop String title) { return Row.create(c) .alignItems(CENTER) .child( - FrescoComponent.create(c) - .uri(imageUri) + SolidColor.create(c) + .colorRes(color) .withLayout() .widthDip(40) .heightDip(40)) @@ -41,21 +41,21 @@ public class MyComponentSpec { As you can see, layout spec classes use the `@LayoutSpec` annotation. -The method annotated with `@OnCreateLayout` must have `ComponentContext` as its first argument followed by a list of arguments annotated with `@Prop`. The annotation processor will validate this and other invariants in the API at build time. +The method annotated with `@OnCreateLayout` must have [ComponentContext](/javadoc/com/facebook/litho/ComponentContext) as its first argument followed by a list of arguments annotated with `@Prop`. The annotation processor will validate this and other invariants in the API at build time. In the example above, the layout tree has a root *Container* with two children stacked horizontally (`Row.create`) and vertically centered (`Align.CENTER`). -The first child is a `FrescoImage` component that takes an `uri` prop and has a 40dp width and height. +The first child is a [SolidColor](/javadoc/com/facebook/litho/widget/SolidColor) component that takes a `colorRes` prop and has a 40dp width and height. ```java -DraweeComponent.create(c) +SolidColor.create(c) .uri(imageUri) .withLayout() .width(40) .height(40) ``` -The second child is a `Text` component that takes a prop named `text` and fills the remaining horizontal space available in `MyComponent` by using `grow(1f)` (equivalent to Android's `layoutWeight` from `LinearLayout`). The text size is defined in `my_text_size` dimension resource. +The second child is a [Text](/javadoc/com/facebook/litho/widget/Text) component that takes a prop named `text` and fills the remaining horizontal space available in `MyComponent` by using `grow(1f)` (equivalent to Android's `layoutWeight` from `LinearLayout`). The text size is defined in `my_text_size` dimension resource. ```java Text.create(c) diff --git a/docs/_docs/mount-specs.md b/docs/_docs/mount-specs.md index a82be0c104b..ed25cf8ebce 100644 --- a/docs/_docs/mount-specs.md +++ b/docs/_docs/mount-specs.md @@ -129,20 +129,21 @@ Just like `@OnPrepare`, the `@OnMeasure` method can also generate inter-stage ou ## ShouldUpdate -A MountSpec can define a method annotated with `@ShouldUpdate` to avoid remeasuring/remounting upon updates. -Invocations of `@ShouldUpdate` are dependent on whether a Component is a pure render function. -A Component is a pure render function if the result of the rendering only depends on its props and states. This means that the Component shouldn't be accessing any mutable global variable during `@OnMount`. +A MountSpec can define a method annotated with `@ShouldUpdate` to avoid remeasuring and remounting upon updates. +Invocations of `@ShouldUpdate` are dependent on whether a Component is a **pure render function**. A Component is a pure render function if the result of the rendering only depends on its props and states. This means that the Component shouldn't be accessing any mutable global variable during `@OnMount`. A `@MountSpec` can be defined as pure render by using the pureRender parameter of the `@MountSpec` annotation. -Only pureRender Components can assume that when props do not change remounting won't be needed. A `@ShouldUpdate` function can be defined as follows: +Only pure render Components can assume that when props do not change remounting won't be needed. A `@ShouldUpdate` function can be defined as follows: + ``` java @ShouldUpdate(onMount = true) public boolean shouldUpdate(Diff someStringProp) { return !someStringProp.getPrevious().equals(someStringProp.getNext()); } ``` -The parameters taken from shouldUpdate are Diff of Props or State. A Diff is an object containing the value of a `@Prop` or a `@State` in the old components hierarchy and the value of the same `@Prop`/`@State` in the new components hierarchy. -In this example this component was defining a `@Prop` String someStringProp. ShouldUpdate will receive a Diff to be able to compare the old and new value of this `@Prop`. `@ShouldUpdate` has to take into consideration any prop and any state that are used at OnMount time. It can safely ignore `@Prop`/`@State` that are only used at OnBind/OnUnbind time as these two methods will be executed regardless. +The parameters taken from `shouldUpdate` are [Diffs](/javadoc/com/facebook/litho/Diff) of Props or State. A Diff is an object containing the value of a `@Prop` or a `@State` in the old components hierarchy and the value of the same `@Prop`or `@State` in the new components hierarchy. +In this example this component was defining **someStringProp** as a String `@Prop`. `shouldUpdate` will receive a `Diff` to be able to compare the old and new value of this `@Prop`. +`shouldUpdate` has to take into consideration any prop and any states that are used at `@OnMount` time. It can safely ignore props and states that are only used at '@OnMount/@OnUnbind` time as these two methods will be executed regardless. -The onMount attribute on the `@ShouldUpdate` annotation controls whether this shouldUpdate check can happen at mount time. By default Components will try to do this reconciliation at layout time but if layout diffing is turned off it might be useful to set onMount to true in order to execute this check at mount time instead. The onMount attribute is set to false by default as the equality check might be heavy itself and make mount performances worse. +The `onMount` attribute on the `@ShouldUpdate` annotation controls whether this `shouldUpdate` check can happen at mount time. By default, Litho will try to do this reconciliation at layout time, but if layout diffing is turned off it might be useful to set onMount to true in order to execute this check at mount time instead. The `onMount` attribute is set to false by default as the equality check might be heavy itself and make mount performances worse. -`@ShouldUpdate` is currently only supported in `@MountSpec`. We have plans to expand the support to complex layouts in the future but at the moment a `@ShouldUpdate` annotated method in a `@LayoutSpec` would have no effect. +`@ShouldUpdate` annotated methods are currently only supported in `@MountSpec`. We have plans to expand the support to complex layouts in the future but at the moment a `@ShouldUpdate` annotated method in a `@LayoutSpec` would have no effect. diff --git a/docs/_docs/props.md b/docs/_docs/props.md index 5d6f5f77111..95dc3b5453e 100644 --- a/docs/_docs/props.md +++ b/docs/_docs/props.md @@ -5,7 +5,7 @@ layout: docs permalink: /docs/props --- -Components use a unidirectional data flow with immutable inputs. Following the name established by React, the inputs that a `Component` takes are known as *props*. +Litho uses a unidirectional data flow with immutable inputs. Following the name established by [React](https://facebook.github.io/react/), the inputs that a `Component` takes are known as *props*. ## Defining and using Props The props for a given `Component` are the union of all arguments annotated with `@Prop` in your spec methods. You can access the value of the props in all the methods that declare it as an `@Prop` parameter. @@ -118,7 +118,7 @@ public class MyComponentSpec { } ``` -With the changes above, `MyComponent`'s builder will contain //Res//, //Attr//, //Dip//, and //Px// methods for the annotated props according to their resource types. So you'll be able to do the following: +With the changes above, `MyComponent`'s builder will contain *Res*, *Attr*, *Dip*, and *Px* methods for the annotated props according to their resource types. So you'll be able to do the following: ```java MyComponent.create(c) @@ -132,4 +132,4 @@ Other supported resource types are `ResType.STRING_ARRAY`, `ResType.INT`, `ResTy ## Immutability The props of a Component are read-only. The Component's parent passes down values for the props when it creates the Component and they cannot change throughout the lifecycle of the Component. If the props values must be updated, the parent has to create a new Component and pass down new values for the props. -The props objects should be made immutable. Due to background layout, props may be accessed on multiple threads. Props immutability ensures that no thread safety issues enter into your component hierarchy. +The props objects should be made immutable. Due to [background layout](/docs/asynchronous-layout), props may be accessed on multiple threads. Props immutability ensures that no thread safety issues enter into your component hierarchy. diff --git a/docs/_docs/recycler-component.md b/docs/_docs/recycler-component.md index f03ae24ab3a..e437eacd6dc 100644 --- a/docs/_docs/recycler-component.md +++ b/docs/_docs/recycler-component.md @@ -4,14 +4,13 @@ title: RecyclerComponent layout: docs permalink: /docs/recycler-component --- -#Recycler Component -RecyclerView is one of the fundamental building blocks for any Android application that contain a scrolling list of items. -Recycler Component exposes very similar functionalities while taking advantage of features such as background layout and incremental mount. +[RecyclerView](https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html) is one of the fundamental building blocks for any Android application that contain a scrolling list of items. The +[Recycler](/javadoc/com/facebook/litho/widget/Recycler) component exposes very similar functionalities while taking advantage of features such as background layout and incremental mount. -### Create a Recycler Component +### Create a Recycler component -You can use Recycler as any other component in the framework by building it and adding it as a child in your layout. +You can use `Recycler` as you would use any other component in the framework by building it and adding it as a child in your layout. ``` java @OnCreateLayout @@ -27,10 +26,10 @@ static ComponentLayout onCreateLayout( This code will render a Recycler component that will display the content of recyclerBinder. ### RecyclerBinder -RecyclerBinder is the entry point to manipulate list-like UIs with Components. +[RecyclerBinder](/javadoc/com/facebook/litho/widget/RecyclerBinder) is the entry point to manipulate list-like UIs with Components. It keeps a list of all the components contained in the list and as the user scrolls through the list it computes layouts for items that are about to become visible. -RecyclerBinder is the part of Litho that: +`RecyclerBinder` is the part of Litho that: - Serves as an Adapter for a RecyclerView - Defines the layout to use in the RecyclerView (ex Linear, Grid) @@ -75,7 +74,7 @@ recyclerBinder.insertItemAt( #### RecyclerBinder Async operations RecyclerBinder also supports async operations. -Inserting or updating an item asynchronously, means that if the item is in the range for which we would need to compute a layout, the Binder will wait until the layout is ready before notifying the RecyclerView of any change. +Inserting or updating an item asynchronously means that if the item is in the range for which we would need to compute a layout, the Binder will wait until the layout is ready before notifying the RecyclerView of any change. To use async operations you would write something like: ``` java @@ -84,13 +83,13 @@ To use async operations you would write something like: recyclerBinder.removeItemAsync(position); recyclerBinder.moveItemAsync(fromPosition, toPosition); ``` -RecyclerBinder is guaranteed to respect the ordering in which the async operations were invoked so something like: +RecyclerBinder is guaranteed to respect the ordering in which the async operations were invoked. Take the example below: ``` java recyclerBinder.insertItemAtAsync(0, component); recyclerBinder.removeItemAsync(1); ``` -would mean that remove is only executed after component has been inserted at position 0 and it will actually remove the item that was in position 0 before component was inserted. +In this example, `remove` is only executed after `component` has been inserted at position 0 and it will actually remove the item that was in position 0 before `component` was inserted. Operating with synchronous operations on the other hand, means that an item will be immediately inserted, even if its insertion position is inside the range of active components. This potentially means that the framework would be forced to compute a layout synchronously on the UI thread when that component needs to be put on screen. diff --git a/docs/_docs/state.md b/docs/_docs/state.md index fec49a3aad6..a81411ddf86 100644 --- a/docs/_docs/state.md +++ b/docs/_docs/state.md @@ -223,4 +223,4 @@ static void onCreateInitialState(Output foo) { The first time FooComponent is rendered, its child `Text` component will display *first foo*, even if `foo` is lazily updated with another value. When a regular state update or receiving new props will trigger a new layout calculation, the lazy state update will be applied and the `Text` will render *updated foo*. ## Immutability -Because of background layout, `State` can be accessed at anytime by multiple threads. To ensure thread safety, `State` objects should be immutable (and if for some rare reason this is not possible, then at least thread safe). The simplest solution is to express your state in terms of primitives since primitives are by definition immutable. +Because of [background layout](/docs/asynchronous-layout), `State` can be accessed at anytime by multiple threads. To ensure thread safety, `State` objects should be immutable (and if for some rare reason this is not possible, then at least thread safe). The simplest solution is to express your state in terms of primitives since primitives are by definition immutable. diff --git a/docs/_docs/styles.md b/docs/_docs/styles.md index 0c29942de18..e00038fdf57 100644 --- a/docs/_docs/styles.md +++ b/docs/_docs/styles.md @@ -45,7 +45,7 @@ Then you can collect the values of these attributes in your `@OnLoadStyle` metho ```java @OnLoadStyle -protected void onLoadStyle( +void onLoadStyle( ComponentContext c, Output prop1, Output prop2) { diff --git a/docs/_docs/tree-props.md b/docs/_docs/tree-props.md index d1888e375ff..6625b35e5c9 100644 --- a/docs/_docs/tree-props.md +++ b/docs/_docs/tree-props.md @@ -5,10 +5,9 @@ layout: docs permalink: /docs/tree-props --- -# TreeProps -`@TreeProp` are props which are automatically and silently passed from a parent component to its children. +`@TreeProp` are [props](/docs/props) which are automatically and silently passed from a parent component to its children. -`@TreeProp` are a convenient way to share contextual data or utilities in a tree without having to explicitly pass `@Prop` to every component. +`TreeProps` are a convenient way to share contextual data or utilities in a tree without having to explicitly pass `@Prop` to every component in your hierarchy. A good candidate, for example, is a prefetcher which fetches network images ahead of render time. The prefetcher is widely used since images are common. The prefetcher implementation might be something we define for any Component that needs to use it without having to pass it as `@Prop` in the entire tree. @@ -45,9 +44,9 @@ The child component can access the TreeProp value through a param annotated with ``` java @LayoutSpec -public class ChildComponentSpec { +class ChildComponentSpec { @OnCreateLayout - protected static ComponentLayout onCreateLayout( + static ComponentLayout onCreateLayout( ComponentContext context, @TreeProp Prefetcher prefetcher, @Prop Uri imageUri) { diff --git a/docs/_docs/unit-testing.md b/docs/_docs/unit-testing.md index 2ed3299a186..ae9bc75b265 100644 --- a/docs/_docs/unit-testing.md +++ b/docs/_docs/unit-testing.md @@ -5,22 +5,22 @@ layout: docs permalink: /docs/unit-testing.html --- -The Components framework provides testing helpers exposed through fluid +Litho provides testing helpers exposed through fluid AssertJ methods. They are available as: -- `ComponentAssert` for assertions that are run against either Component builders +- [ComponentAssert](/javadoc/com/facebook/litho/testing/assertj/ComponentAssert) for assertions that are run against either Component builders or Components. -- `ComponentViewAssert` for assertions against mounted Components. +- [ComponentViewAssert](/javadoc/com/facebook/litho/testing/assertj/ComponentViewAssert) for assertions against mounted Components. In order to use any of the testing capabilities, you need include the optional `litho-testing` package in your build. It is available as `com.facebook.litho:litho-testing:+`. -Under the hood, these asserts are implemented through these helpers, -that are also available in case that more complicated use cases need +Under the hood, these asserts are implemented through the helpers below, +which are also available in case more complicated use cases need to be reconstructed: -- `ComponentTestHelper`: Allows simple and short creation of views that are +- [ComponentTestHelper](/javadoc/com/facebook/litho/testing/ComponentTestHelper): Allows simple and short creation of views that are created and mounted in a similar way to how they are in real apps. - `ComponentQueries`: Utility class to query the state of components. @@ -35,7 +35,7 @@ that displays a like icon and a short description. * > 3 likers => Comma separated number denoting the like count */ @LayoutSpec -public class LikersComponentSpec { +class LikersComponentSpec { @OnCreateLayout protected static ComponentLayout onCreateLayout( @@ -46,7 +46,7 @@ public class LikersComponentSpec { .alignItems(FLEX_START) .child( Image.create(c) - .srcRes(R.drawable.like)) + .srcRes(R.drawable.like)) .child( Text.create(c) .text(formatLikers(likers)) @@ -123,7 +123,7 @@ or on the `ComponentBuilder` before it is consumed by `build()`. ``` Generally, this should be enough, but if you need more control, -you can also manually mount a Component with `ComponentTestHelper` +you can also manually mount a Component with [ComponentTestHelper](/javadoc/com/facebook/litho/testing/ComponentTestHelper) and verify the state of it through `ComponentQueries`. ```java @@ -147,7 +147,7 @@ and verify the state of it through `ComponentQueries`. ## Testing Sub-Component Rendering Instead of performing assertions on the content rendered by your Component, it might be useful to test for the rendering of sub-components instead. -`SubComponent` is a convenience class that allows for easier comparison of Component +[SubComponent](/javadoc/com/facebook/litho/testing/SubComponent) is a convenience class that allows for easier comparison of Component types. You can, again, use AssertJ to verify the presence or absence of the subcomponents. diff --git a/docs/_docs/using-components.md b/docs/_docs/using-components.md index b76b76c228f..7d4f1a3e6c9 100644 --- a/docs/_docs/using-components.md +++ b/docs/_docs/using-components.md @@ -4,26 +4,43 @@ title: Using Components layout: docs permalink: /docs/using-components --- -Generated component classes provide a simple builder with the props you defined in your component *spec*. In order to use the generated component in your UI, you'll need two things: a `ComponentTree` and a `ComponentView`. +Generated component classes provide a simple builder with the props you defined in your component *spec*. In order to use the generated component in your UI, you'll need two things a [ComponentView](/javadoc/com/facebook/litho/ComponentView), which is an Android `ViewGroup` that is able to render components. -`ComponentTree` manages your component's lifecycle in a thread-safe way. You can create and make calls to it from any thread. `ComponentView` is an Android `ViewGroup` that is able to render components. - -You can display a component by creating a `ComponentTree` and setting it on a `ComponentView` as follows: +You can assign a component to be rendered by a `ComponentView` as follows: ```java -ComponentView view = new ComponentView(context); - -ComponentTree component = ComponentTree.create( - context, - MyComponent.create() +Component component = MyComponent.create() .title("My title") - .imageUri(Uri.parse("http://example.com/myimage"))) - .build(); - -view.setComponent(component); + .imageUri(Uri.parse("http://example.com/myimage")) + .build(); +ComponentView view = ComponentView.create(context, component); ``` -In this example, `MyComponent` will be laid out by the hosting `ComponentView` once it gets attached to a view tree. +In this example, `MyComponent` will be laid out by the hosting `ComponentView`, which you can use in your application as you would normally use an Android View. See the [tutorial](/docs/tutorial#hello-world) for an example on how to use it in an Activity. > IMPORTANT: The ComponentView from this example, if directly used in your view hierarchy as is, will perform layout synchronously on the main thread. For more information about performing layout off the main thread, see [Async Layout](/docs/architecture#async-layout). + +## Extra +We saw how you can create a root component and pass it to a `ComponentView`, which will take care of creating a [ComponentTree](/javadoc/com/facebook/litho/ComponentTree) with the given root. ComponentTree manages your component's lifecycle in a thread-safe way. You can create and make calls to it from any thread. +You shouldn't typically need to do this, but there are situations where you might want to create and manage your own `ComponentTree`, such as turning off [incremental mount](/docs/intro#incremental-mount). +This is how you can create a `ComponentTree`, pass it a component root and attach it to a 'ComponentView'. The `ComponentTree`'s `create()` method returns a [Builder](/javadoc/com/facebook/litho/ComponentTree.Builder) which exposes configuration methods for the ComponentTree. + +```java +@Override +public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final ComponentView componentView = new ComponentView(this); + final ComponentContext context = new ComponentContext(this); + + final Component text = Text.create(context) + .text("Hello World") + .textSizeDip(50) + .build(); + final ComponentTree componentTree = ComponentTree.create(context, text).build(); + + componentView.setComponentTree(componentTree); + setContentView(componentView); +} +``` diff --git a/docs/_docs/visibility_handling.md b/docs/_docs/visibility_handling.md index 45accb7e2aa..01163573f0c 100644 --- a/docs/_docs/visibility_handling.md +++ b/docs/_docs/visibility_handling.md @@ -9,17 +9,17 @@ permalink: /docs/visibility-handling The framework currently supports four types of Visibility Event: -- **Visible Event**: this event is triggered when at least one pixel of the Component is visible. +- [Visible Event](/javadoc/com/facebook/litho/VisibleEvent): this event is triggered when at least one pixel of the Component is visible. -- **Invisible Event**: this event is triggered when the Component no longer has any pixels on the screen. +- [Invisible Event](/javadoc/com/facebook/litho/InvisibleEvent): this event is triggered when the Component no longer has any pixels on the screen. -- **Focused Visible Event**: this event is triggered when either the Component occupies at least half of the viewport, or, if the Component is smaller than half the viewport, when it is fully visible. +- [Focused Visible Event](/javadoc/com/facebook/litho/FocusedVisibleEvent): this event is triggered when either the Component occupies at least half of the viewport, or, if the Component is smaller than half the viewport, when it is fully visible. -- **Full Impression Visible Event**: this event is triggered when the entire Component has passed through the viewport at some point. +- [Full Impression Visible Event](/javadoc/com/facebook/litho/FullImpressionVisibleEvent): this event is triggered when the entire Component has passed through the viewport at some point. ### Usage ### -Visibility Ranges require [incremental mount](/docs/inc-mount#manual-incremental-mount) to be enabled on the relevant Component. +Visibility ranges require [incremental mount](/docs/inc-mount#manual-incremental-mount) to be enabled on the relevant Component. To register visibility event handlers for a component you can follow the same [steps](/docs/events-overview) as for setting any other event handler. diff --git a/docs/_docs/widgets-card.md b/docs/_docs/widgets-card.md deleted file mode 100644 index 67115dc499c..00000000000 --- a/docs/_docs/widgets-card.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -docid: widgets-card -title: Card -layout: docs -permalink: /docs/widgets-card.html ---- -The `Card` component expects another component as a `@Prop` and it will render it into a card-like UI with border and shadow. - -`@Prop` | Optional | Default | Notes ---- | --- | --- | --- -cardBackgroundColor | [x] | Color.WHITE -clippingColor | [x] | Color.WHITE -content | [ ] | | The component to be wrapped with this Card layout. -cornerRadius | [x] | -1 -elevation | [x] | -1 -shadowStartColor | [x] | 0x37000000 -shadowEndColor | [x] | 0x03000000 diff --git a/docs/_docs/widgets-edittext.md b/docs/_docs/widgets-edittext.md deleted file mode 100644 index d27c840e675..00000000000 --- a/docs/_docs/widgets-edittext.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -docid: widgets-edittext -title: EditText -layout: docs -permalink: /docs/widgets-edittext.html ---- -The `EditText` component renders an Android [EditText](https://developer.android.com/reference/android/widget/EditText.html). - -`@Prop` | Optional | Default ---- | --- | --- | -editable | [x] | true | -ellipsize | [x] | | -extraSpacing | [x] | | -gravity | [x] | Gravity.CENTER_VERTICAL \| Gravity.START | -highlightColor | [x] | | -hint | [x] | | -hintColor | [x] | | -hintColorStateList | [x] | | -isSingleLine | [x] | | -linkColor | [x] | | -maxLength | [x] | Integer.MAX_VALUE | -maxLines | [x] | Integer.MAX_VALUE | -minLines | [x] | Integer.MIN_VALUE | -shadowColor | [x] | Color.GRAY | -shadowDx | [x] | | -shadowDy | [x] | | -shadowRadius | [x] | | -spacingMultiplier | [x] | | -text | [x] | | -textAlignment | [x] | Alignment.ALIGN_NORMAL | -textColor | [x] | | -textColorStateList | [x] | | -textSize | [x] | 13px | -textStyle | [x] | | -typeface | [x] | Typeface.DEFAULT | -selection | [x] | | diff --git a/docs/_docs/widgets-horizontalscroll.md b/docs/_docs/widgets-horizontalscroll.md deleted file mode 100644 index 1d04d6a0606..00000000000 --- a/docs/_docs/widgets-horizontalscroll.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -docid: widgets-horizontalscroll -title: HorizontalScroll -layout: docs -permalink: /docs/widgets-horizontalscroll.html ---- -The `HorizontalScroll` component renders an Android [HorizontalScrollView](https://developer.android.com/reference/android/widget/HorizontalScrollView.html). - -`@Prop` | Optional | Default | Notes ---- | --- | --- | --- -contentProps | [ ] | | The component content to be horizontally scrollable. -scrollbarEnabled | [x] | true | diff --git a/docs/_docs/widgets-image.md b/docs/_docs/widgets-image.md deleted file mode 100644 index 72fcfe3c80c..00000000000 --- a/docs/_docs/widgets-image.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -docid: widgets-image -title: Image -layout: docs -permalink: /docs/widgets-image.html ---- -The `Image` component is able to render a drawable. - -`@Prop` | Optional | Default | Notes ---- | --- | --- | --- -scaleType | [x] | | -src | [ ] | | Drawable to be rendered. diff --git a/docs/_docs/widgets-progress.md b/docs/_docs/widgets-progress.md deleted file mode 100644 index 402d8a1db91..00000000000 --- a/docs/_docs/widgets-progress.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -docid: widgets-progress -title: Progress -layout: docs -permalink: /docs/widgets-progress.html ---- -The `Progress` component renders an Android [ProgressBar](https://developer.android.com/reference/android/widget/ProgressBar.html). - -`@Prop` | Optional | Default | ---- | --- | --- | -color | [x] | Color.TRANSPARENT | -indeterminateDrawable | [x] | | diff --git a/docs/_docs/widgets-recycler.md b/docs/_docs/widgets-recycler.md deleted file mode 100644 index e7b53437090..00000000000 --- a/docs/_docs/widgets-recycler.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -docid: widgets-recycler -title: Recycler -layout: docs -permalink: /docs/widgets-recycler.html ---- -The `Recycler` component renders an Android [SwipeRefreshLayout](https://developer.android.com/reference/android/support/v4/widget/SwipeRefreshLayout.html) with a [RecyclerView](https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html) as child. Since this component needs a bit more insight to be used correctly, we have a specific guide for it: TODO LINK - -`@Prop` | Optional | Default | Notes ---- | --- | --- | --- -binder | [ ] | | Refer to TODO LINK -refreshHandler | [x] | | `EventHandler` to catch onRefresh events. -hasFixedSize | [x] | true | -clipToPadding | [x] | | -scrollBarStyle | [x] | View.SCROLLBARS\_INSIDE\_OVERLAY | -itemDecoration | [x] | | -recyclerViewId | [x] | View.NO\_ID | Id to be set to the underlying RecyclerView. -itemAnimator | [x] | NoUpdateItemAnimator | This is a standard DefaultItemAnimator with disabled change animations. -recyclerEventsController | [x] | | A controller to trigger events from outside the component hierarchy such as: scroll to top or scroll to position. -onScrollListener | [x] | | \ No newline at end of file diff --git a/docs/_docs/widgets-solidcolor.md b/docs/_docs/widgets-solidcolor.md deleted file mode 100644 index 99e39347504..00000000000 --- a/docs/_docs/widgets-solidcolor.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -docid: widgets-solidcolor -title: SolidColor -layout: docs -permalink: /docs/widgets-solidcolor.html ---- -The `SolidColor` component uses an `Image` component under the hood to render a solid color. - -`@Prop` | Optional | Default | ---- | --- | --- | -color | [ ] | | diff --git a/docs/_docs/widgets-text.md b/docs/_docs/widgets-text.md deleted file mode 100644 index 36654761bc9..00000000000 --- a/docs/_docs/widgets-text.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -docid: widgets-text -title: Text -layout: docs -permalink: /docs/widgets-text.html ---- -The `Text` component renders an Android [TextView](https://developer.android.com/reference/android/widget/TextView.html). - -`@Prop` | Optional | Default | Notes ---- | --- | --- | --- -accessibleClickableSpans | [x] | false | If a `ClickableSpan` is given as a text `@Prop`, this flag makes the `Text` component use the clickable span information for accessibily. -ellipsize | [x] | | -extraSpacing | [x] | | -glyphWarming | [x] | false | Schedules a [Layout](https://developer.android.com/reference/android/text/Layout.html) to be drawn in the background. This warms up the Glyph cache for that Layout. -highlightColor | [x] | | -isSingleLine | [x] | | -linkColor | [x] | | -maxLines | [x] | Integer.MAX_VALUE | -maxEms | [x] | | -maxWidth | [x] | Integer.MAX_VALUE | -minLines | [x] | Integer.MIN_VALUE | -minEms | [x] | | -minWidth | [x] | | -shadowColor | [x] | Color.GRAY | -shadowDx | [x] | | -shadowDy | [x] | | -shadowRadius | [x] | | -shouldIncludeFontPadding | [x] | true | -spacingMultiplier | [x] | | -text | [ ] | | -textAlignment | [x] | ALIGN_NORMAL | -textColor | [x] | | -textColorStateList | [x] | | -textSize | [x] | 13px | -textStyle | [x] | | -typeface | [x] | Typeface.DEFAULT | -verticalGravity | [x] | TOP | \ No newline at end of file diff --git a/docs/_docs/writing-components.md b/docs/_docs/writing-components.md index afe9bc3174a..795659a8a5e 100644 --- a/docs/_docs/writing-components.md +++ b/docs/_docs/writing-components.md @@ -15,7 +15,7 @@ For now, let's just have a look at the overall structure of a *layout spec*: ```java @LayoutSpec -public class MyComponentSpec { +class MyComponentSpec { @OnCreateLayout static ComponentLayout onCreateLayout( ComponentContext c, @@ -35,11 +35,11 @@ A few things to note: ## Spec, Lifecycle, and Component classes -A component spec class will be processed to generate a `ComponentLifecycle` subclass with the same name as the spec but without the *Spec* suffix. For example, a `MyComponentSpec` spec generates a `MyComponent` class. +A component spec class will be processed to generate a [ComponentLifecycle](/javadoc/com/facebook/litho/ComponentLifecycle) subclass with the same name as the spec but without the *Spec* suffix. For example, a `MyComponentSpec` spec generates a `MyComponent` class. The generated `ComponentLifecycle` class is what you are going to [use in your product](/docs/using-components). The spec class will be used as a delegate in the generated code at runtime. -The only API exposed by the generated class is a `create(...)` method that returns the appropriate [`Component.Builder`](linktojavadoc) for the `@Prop`s that you declared in your spec class. +The only API exposed by the generated class is a `create(...)` method that returns the appropriate [`Component.Builder`](/javadoc/com/facebook/litho/Component.Builder.html) for the `@Prop`s that you declared in your spec class. At runtime, all component instances of a certain type share the same `ComponentLifecycle` reference. This means that there will only be one spec instance per component type, not per component instance.