facebook / litho Goto Github PK
View Code? Open in Web Editor NEWA declarative framework for building efficient UIs on Android.
Home Page: https://fblitho.com
License: Apache License 2.0
A declarative framework for building efficient UIs on Android.
Home Page: https://fblitho.com
License: Apache License 2.0
Issue:
StickyHeader is not visible after scrolling back.
Steps to reproduce:
Create a RecyclerBinder and add components that are sticky.
Expect the sticky header to be visible
Code Available here: Recycler Spec
At the moment we have the file name in square brackets as the first line of the sample code in "Getting Started". Can we get it as some kind of title, separate from code?
The widget_attrs.xml
is currently part of litho-core
but should obviously live in litho-widget
.
It's not as easy as moving it to the other package and updating the references to com.facebook.litho.widget.R
as we create another cycle since litho-testing
depends on some of the styleable attributes defined in there.
We need to find a way to untangle this. Another stand-alone resource package sounds like something we would want to avoid. Get creative!
We already have support for specifying border width and border color on a component. Now we would like to have an ability to specify the border radius which will draw curved edges on the component. The API might look like this:
Row.create(c)
.child(
Row.create(c)
....)
.child(
Text.create(c)
.text("Sample with border radius")
.textSizeDip(14))
.child(
Row.create(c)
....)
.borderColor(Color.BLUE)
.borderWidthDip(YogaEdge.BOTTOM, 33)
.borderRadiusDip(TOPLEFT, 2)
.borderRadiusDip(TOPRIGHT, 2)
.build();
Or you can specify one value for all edges something like:
Row.create(c)
.....
.borderRadiusDip(ALL, 2)
.build();
Besides specifying radius in Dip, you should be able to specify it in pixel value, resource attribute, dimension, similar to how borderWidth is defined.
Point of contact: @muraziz
Scroll down and scroll up. The star of the first cannot be seen. When the second sticky header hits the top, then scroll down. The first star is visible again
We need a way to specify the enabled
selector state of a component so that background and foreground drawables can adopt the correct state. This would most likely be another method on the ComponentLayout.Builder
interface. It would also have to be transfers to the drawables on the component.
Point of contact: @muraziz
I use Huawei mobile phones,Android 4.2.2and 7.0 are crash
build.gradle
// Litho compile 'com.facebook.litho:litho-core:0.2.0' compile 'com.facebook.litho:litho-widget:0.2.0' provided 'com.facebook.litho:litho-annotations:0.2.0' annotationProcessor 'com.facebook.litho:litho-processor:0.2.0' // SoLoader compile 'com.facebook.soloader:soloader:0.2.0' // Optional // For debugging debugCompile 'com.facebook.litho:litho-stetho:0.2.0' // For integration with Fresco compile 'com.facebook.litho:litho-fresco:0.2.0' // For testing testCompile 'com.facebook.litho:litho-testing:0.2.0'
Activity:
final ComponentContext c = new ComponentContext(this); final LithoView lithoView = LithoView.create( this /* context */, Text.create(c) .text("Hello, World!") .textSizeDip(50) .build()); setContentView(lithoView);
Application:
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); SoLoader.init(this, false); } }
AndroidManifest.xml:
application android:name=".MyApplication"
I use Meizu Mx4 pro is normal ,Android version 5.1
Once we have JavaDocs, add a link at the end of the unit testing docs (#21).
InternalNode#build() (https://github.com/facebook/litho/blob/master/litho-core/src/main/java/com/facebook/litho/InternalNode.java#L1467) just does return this
, which implies that we can mutate a ComponentLayout.ContainerBuilder's result after calling build()
on it. Add an internal flag and throw an exception if there is an attempt to mutate it after building the layout.
Point of contact: @muraziz
Text Recycler。。。。。。。。。。
Install and run sample
on Nexus 6 with Android 5.0. The application crashes on startup.
04-19 13:11:26.200 893-2754/? I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.facebook.samples.litho/.DemoListActivity bnds=[781,953][998,1170] (has extras)} from uid 10095 on display 0
04-19 13:11:26.286 893-1411/? I/ActivityManager: Start proc com.facebook.samples.litho for activity com.facebook.samples.litho/.DemoListActivity: pid=31261 uid=10106 gids={50106, 9997, 3003, 1028, 1015} abi=armeabi-v7a
04-19 13:11:26.293 31261-31261/? I/art: Late-enabling -Xcheck:jni
04-19 13:11:26.408 31261-31261/? V/fb-UnpackingSoSource: locked dso store /data/data/com.facebook.samples.litho/lib-main
04-19 13:11:26.409 31261-31261/? V/fb-UnpackingSoSource: deps mismatch on deps store: regenerating
04-19 13:11:26.409 31261-31261/? V/fb-UnpackingSoSource: so store dirty: regenerating
04-19 13:11:26.437 31261-31261/? D/ApkSoSource: not allowing consideration of lib/armeabi-v7a/libfb_jpegturbo.so: deferring to libdir
04-19 13:11:26.437 31261-31261/? D/ApkSoSource: not allowing consideration of lib/armeabi-v7a/libgnustl_shared.so: deferring to libdir
04-19 13:11:26.437 31261-31261/? D/ApkSoSource: not allowing consideration of lib/armeabi-v7a/libimagepipeline.so: deferring to libdir
04-19 13:11:26.437 31261-31261/? D/ApkSoSource: not allowing consideration of lib/armeabi-v7a/liblib_fb_fbjni.so: deferring to libdir
04-19 13:11:26.437 31261-31261/? D/ApkSoSource: not allowing consideration of lib/armeabi-v7a/libyoga.so: deferring to libdir
04-19 13:11:26.437 31261-31261/? D/ApkSoSource: not allowing consideration of lib/armeabi-v7a/libyogacore.so: deferring to libdir
04-19 13:11:26.438 31261-31261/? V/fb-UnpackingSoSource: regenerating DSO store com.facebook.soloader.ApkSoSource
04-19 13:11:26.439 31261-31261/? V/fb-UnpackingSoSource: starting syncer worker
04-19 13:11:26.447 31261-31261/? V/fb-UnpackingSoSource: releasing dso store lock for /data/data/com.facebook.samples.litho/lib-main (from syncer thread)
04-19 13:11:26.447 31261-31261/? V/fb-UnpackingSoSource: not releasing dso store lock for /data/data/com.facebook.samples.litho/lib-main (syncer thread started)
04-19 13:11:26.456 31261-31279/? I/stetho: Listening on @stetho_com.facebook.samples.litho_devtools_remote
04-19 13:11:26.485 31261-31261/? W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
04-19 13:11:26.674 31261-31281/? D/OpenGLRenderer: Render dirty regions requested: true
04-19 13:11:26.680 31261-31261/? D/Atlas: Validating map...
04-19 13:11:26.734 31261-31261/? E/libEGL: call to OpenGL ES API with no current context (logged once per thread)
04-19 13:11:26.734 31261-31261/? E/libEGL: call to OpenGL ES API with no current context (logged once per thread)
04-19 13:11:26.734 31261-31261/? E/libEGL: call to OpenGL ES API with no current context (logged once per thread)
04-19 13:11:26.735 31261-31261/? A/libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 31261 (k.samples.litho)
04-19 13:11:26.839 12429-12429/? I/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
04-19 13:11:26.839 12429-12429/? I/DEBUG: Build fingerprint: 'google/shamu/shamu:5.0/LRX21O/1570415:user/release-keys'
04-19 13:11:26.839 12429-12429/? I/DEBUG: Revision: '33696'
04-19 13:11:26.839 12429-12429/? I/DEBUG: ABI: 'arm'
04-19 13:11:26.840 12429-12429/? I/DEBUG: pid: 31261, tid: 31261, name: k.samples.litho >>> com.facebook.samples.litho <<<
04-19 13:11:26.840 12429-12429/? I/DEBUG: signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
04-19 13:11:26.851 12429-12429/? I/DEBUG: r0 00000000 r1 00000020 r2 ffffffff r3 b6fd432c
04-19 13:11:26.851 12429-12429/? I/DEBUG: r4 00000000 r5 ab746794 r6 bebf0b24 r7 ab746780
04-19 13:11:26.851 12429-12429/? I/DEBUG: r8 b678f628 r9 b6fd5df4 sl 00000055 fp 00000055
04-19 13:11:26.851 12429-12429/? I/DEBUG: ip b6fd19b8 sp bebf0b18 lr b676782d pc b6fb905c cpsr 000f0030
04-19 13:11:26.851 12429-12429/? I/DEBUG: backtrace:
04-19 13:11:26.851 12429-12429/? I/DEBUG: #00 pc 0005005c /system/lib/libc.so (__strchr_chk+11)
04-19 13:11:26.851 12429-12429/? I/DEBUG: #01 pc 00021829 /system/lib/libhwui.so (android::uirenderer::Extensions::findExtensions(char const*, android::SortedVector<android::String8>&) const+12)
04-19 13:11:26.851 12429-12429/? I/DEBUG: #02 pc 000218a9 /system/lib/libhwui.so (android::uirenderer::Extensions::Extensions()+64)
04-19 13:11:26.851 12429-12429/? I/DEBUG: #03 pc 00022463 /system/lib/libhwui.so
04-19 13:11:26.851 12429-12429/? I/DEBUG: #04 pc 0001b1a3 /system/lib/libhwui.so (android::uirenderer::Caches::Caches()+50)
04-19 13:11:26.851 12429-12429/? I/DEBUG: #05 pc 000189df /system/lib/libhwui.so (android::Singleton<android::uirenderer::Caches>::getInstance()+34)
04-19 13:11:26.851 12429-12429/? I/DEBUG: #06 pc 0001fc23 /system/lib/libhwui.so (android::uirenderer::DisplayListRenderer::DisplayListRenderer()+98)
04-19 13:11:26.851 12429-12429/? I/DEBUG: #07 pc 0007a027 /system/lib/libandroid_runtime.so
04-19 13:11:26.851 12429-12429/? I/DEBUG: #08 pc 00019f09 /data/dalvik-cache/arm/system@[email protected]
The application doesn't crash.
No special code is needed. Just ./gradlew :sample:installDebug
on a cloned project.
Consider the following layout:
Row.create(c)
.child(FullBleedPhotoComponent.create(c)
....)
.child(Text.create(c)
.text(textWithClickableSpan)
.withLayout()
.positionType(ABSOLUTE)
...)
.build();
Let's consider that FullBleedPhotoComponent
is a mount spec defined in FullBleedPhotoComponentSpec
that mounts a view stretching fully to its parent bounds and has click listener. And let's say we need to draw text that has ClickableSpan
on top of FullBleedPhotoComponent
. As we can see from the layout definition above the Text
component is laid out in absolute position meaning the Text will be displayed on top of FullBleedPhotoComponent
.
The issue with this scenario is that if we click Text
the touch goes first to the view mounted by FullBleedPhotoComponent
and its click listener is fired instead of Text
's ClickableSpan
.
As we can see from the layout above Text
component is mounting its content (TextDrawable
) directly to its parent host which is ComponentView
. Correspondingly, when we add ClickableSpan
text to Text
component its click handler is registered with ComponentView
and in the view hierarchy FullBleedPhotoComponent
's view comes before its parent ComponentView
, therefore when we click Text touch event goes first to FullBleedPhotoComponent
's view where it is consumed.
We can add .wrapInView()
to Text
component so that its content lives in a separate view (ComponentHost
) instead of living in its parent (ComponentView
). In such case in the View hierarchy the wrapped view of Text
component will be the first to get touch event which will result in desired behavior.
We should be able to detect this case and wrap the Text
internally (short-term) or handle touch events by ourselves which is super complicated (long term).
Point of contact: @muraziz
It would be awesome if Litho supports converting existing XML layouts we painstakingly created. We can design our layouts in the XML & preview it in Android Studio layout editor & use it with Litho.
Currently there is no way to specify the default value of a ResType
prop using resource ids.
Say you declare a prop like the following
@Prop(optional = true, resType = ResType.DIMEN_SIZE) int textSize
You would like to be able to declare its default value as being a dimension resource.
@PropDefault protected static final int textSize = R.dimen.text_size_medium;
However that currently would not work as it would parse the resource id as an actual size value and not grab the size associated with the id.
This would most likely be solved by adding resType
to the @PropDefault
annotation.
@PropDefault(resType = ResType.DIMEN_SIZE) protected static final int textSize = R.dimen.text_size_medium;
Point of contact: @emilsjolander
We want to align with web behavior here and not clip bounds of any child. Right now since we might have ComponentHosts wrapping MountItems we might end clipping bounds in some cases.
In cases where there a drawable is not wrapped in a ComponentHost on the other hand we don't clip.
Let's get rid of this inconsistency by never clipping bounds within a LithoView.
We might also want to expose an API to re-enable bounds clipping in some cases.
Point of Contact: @pasqualeanatriello
Sync state updates should be posted on the main thread instead of executed immediately.
If a sync state update is triggered while we're executing a layout calculation, then the state update would trigger another layout calculation. We should instead post any sync state updates on the main thread and wait for the current layout calculation to be finished before starting a new one.
Point of contact: @mihaelao
Buck fetch is unable to download android support libraries.
To repro, run buck fetch sample
Buck should fetch binaries.
Buck exits error code 1, with errors
Not using buckd because watchman isn't installed.
Unable to download: mvn:com.android.support:support-core-utils:aar:25.3.1
Unable to download: mvn:com.android.support:support-core-ui:aar:25.3.1
Unable to download: mvn:com.android.support:support-annotations:jar:25.3.1
Unable to download: mvn:com.android.support:support-fragment:aar:25.3.1
Unable to download: mvn:com.android.support:support-v4:aar:25.3.1
Unable to download: mvn:com.android.support:recyclerview-v7:aar:25.3.1
Unable to download: mvn:com.android.support:appcompat-v7:aar:25.3.1
Unable to download: mvn:com.android.support:support-vector-drawable:aar:25.3.1
Unable to download: mvn:com.android.support:support-compat:aar:25.3.1
BUILD FAILED: //lib/android-support:android-support-compat.aar failed with exit code -1:
curl
[-] PROCESSING BUCK FILES...FINISHED 1.0s [100%] 🐳 New buck daemon
[-] DOWNLOADING... (0.00 B/S AVG, TOTAL: 0.00 B, 0 Artifacts)
[-] BUILDING...FINISHED 11.2s [100%] (23/23 JOBS, 0 UPDATED, 0 [0.0%] CACHE MISS)
Buck doctor output: http://filebin.ca/3JauRmg0MBd4/defect_report2771786254819049122.zip
Buck version buck version 22a78d57a01d6d3b7a107fff010721f4a756037d
OS: Ubuntu 14.04
Lint doesn't have the highest opinion of us at the moment and we had to disable abortOnError
as a consequence. Some of the issues are just noise, others are signal.
We should suppress those that we're okay with in code and fix the ones we're not.
This is a good task for new contributors.
Don't trigger state updates if the old value and new value of the state is the same.
Two ideas for this:
stateUpdates
on the ComponentTree
, we could call shouldUpdate on each Component and if it is false for all of them, then we should return without calculating a new layout.We could have a StateContainer
comparison and don't enqueue incoming StateUpdates
if the state value doesn't change.
Point of contact: @mihaelao
Debugging accessibility hierarchies for Litho is specially difficult since unless it's explicitly overridden, we'll never set a class name in onInitializeAccessibilityNodeInfo
, which results in the node being labelled with a generic View
class name. We should instead figure out a way to report the name of the spec that's being rendered or at the very least default to label the node as ComponentHost
so it's clear that said node represents a Component
.
Point of contact: @muraziz
Create a new API in TextSpec to give callback about the text that's highlighted and change highlight text background. This should be similar to how Android EditText handles text selection.
To achieve that first we need to get (x, y) coordinates of a touch event, and then get the start, end offset of the text that's under (x,y).
For the first part we can do something similar as in TextView
's getOffsetForPosition()
API (https://developer.android.com/reference/android/widget/TextView.html#getOffsetForPosition(float, float)). When we have start, end offset of the text, it shouldn't be hard to highlight corresponding portion of the text.
For the API side we might create a new event, something like TextHighlightEvent
and provide corresponding prop to TextSpec
.
Point of contact: @muraziz
If we know that the size of a subtree is not changing when we update its state, then we definitely don't need to relayout the whole tree, which should save a lot of work.
We could check for the prefix of the global key of a root and if we don't have any pending state updates for it then just copy everything from the old tree.
Point of contact: @mihaelao
I have a simple LayoutSpec
that returns a single Text
item. Defining it in Kotlin:
@LayoutSpec
class CurrentWeatherTopSpec {
companion object {
@JvmStatic
@OnCreateLayout
fun onCreateLayout(c: ComponentContext): ComponentLayout {
return Column.create(c)
.child(Row.create(c)
.child(
Text.create(c)
.text("Current Weather")
.build()
).build())
.build()
}
}
}
Nothing gets generated. No CurrentWeatherTopLayout
file created. If I create the same code in Java, it gets generated:
@LayoutSpec
class CurrentWeatherTopSpec {
@OnCreateLayout
static ComponentLayout onCreateLayout(ComponentContext context) {
return Column.create(c)
.child(Row.create(c)
.child(
Text.create(c)
.text("Current Weather")
.build()
).build())
.build();
}
}
I'd expect the corresponding generated component class.
Is this a bug or something I am doing wrong here?
I guess my real question here is what does Litho use to determine if the class is a proper @LayoutSpec
. Also FYI im using kapt
and using it for java files works fine, but when in Kotlin the processor does not work.
Right now we only cache one measure in DiffNode. This means that if a node is measured twice we still end up measuring as the first of the two measurements won't match the content of DiffNode. We need to store all the measurements a node went through during a layout pass and check them in order.
Point of contact: @pasqualeanatriello
compile 'com.facebook.litho:litho-core:0.2.0'
compile 'com.facebook.litho:litho-widget:0.2.0'
provided 'com.facebook.litho:litho-annotations:0.2.0'
annotationProcessor 'com.facebook.litho:litho-processor:0.2.0'
// SoLoader
compile 'com.facebook.soloader:soloader:0.2.0'
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final ComponentContext context = new ComponentContext(this);
final Component component = Text.create(context)
.text("Hello World")
.textSizeDip(50)
.build();
setContentView(LithoView.create(context, component));
}
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, false);
}
}
App should display hello world
Stacktrace: https://pastebin.com/yjSNTe6T
The Event api gives us the ability for child components to give callback to their parents. However in some cases we have the need for components to trigger actions on their children. The typical example is to issue a scrollToTop
command on a Recycler
component.
Let's call this Triggers, i.e. the ability perform imperative commands on mounted views/drawables in a type-safe way. This API would look very similar to the Event API but act in the inverse direction.
Point of contact: @muraziz
Row
and Column
are great APIs as they make the direction of the container explicit. However this causes some confusion when wanting a container with only a single child as both Row
and Column
will work. Therefor we would like to introduce some Container.Builder
type which only accepts one child (possibly only 1 relative positioned child and however many absolute children).
I can think of two possible APIs:
SingleChildContainer.create(c)
.child(...)
.child(...) // throws exception
...;
or
MyComponent.create(c)
.prop1(...)
.withContainer()
....;
Point of contact: @emilsjolander
Using an Nexus 6P on Android 7.1.2:
./gradlew :sample:installDebug
No crash
04-19 15:26:47.672 30649-30649/com.facebook.samples.litho E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.facebook.samples.litho, PID: 30649
java.lang.NoClassDefFoundError: Failed resolution of: Lcom/facebook/litho/annotations/Prop;
at com.facebook.litho.ComponentStethoNodeDescriptor.onGetStyles(ComponentStethoNodeDescriptor.java:193)
at com.facebook.litho.ComponentStethoNodeDescriptor.onGetStyles(ComponentStethoNodeDescriptor.java:26)
at com.facebook.stetho.inspector.elements.AbstractChainedDescriptor.getStyles(AbstractChainedDescriptor.java:154)
at com.facebook.stetho.inspector.elements.Document.getElementStyles(Document.java:153)
at com.facebook.stetho.inspector.protocol.module.CSS$2$1.store(CSS.java:144)
at com.facebook.litho.ComponentStethoNodeDescriptor.onGetStyleRuleNames(ComponentStethoNodeDescriptor.java:152)
at com.facebook.litho.ComponentStethoNodeDescriptor.onGetStyleRuleNames(ComponentStethoNodeDescriptor.java:26)
at com.facebook.stetho.inspector.elements.AbstractChainedDescriptor.getStyleRuleNames(AbstractChainedDescriptor.java:145)
at com.facebook.stetho.inspector.elements.Document.getElementStyleRuleNames(Document.java:147)
at com.facebook.stetho.inspector.protocol.module.CSS$2.run(CSS.java:118)
at com.facebook.stetho.common.android.HandlerUtil$2.onRun(HandlerUtil.java:90)
at com.facebook.stetho.common.android.HandlerUtil$2.onRun(HandlerUtil.java:87)
at com.facebook.stetho.common.android.HandlerUtil$WaitableRunnable.run(HandlerUtil.java:109)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6121)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.facebook.litho.annotations.Prop" on path: DexPathList[[zip file "/data/app/com.facebook.samples.litho-1/base.apk"],nativeLibraryDirectories=[/data/app/com.facebook.samples.litho-1/lib/arm64, /system/fake-libs64, /data/app/com.facebook.samples.litho-1/base.apk!/lib/arm64-v8a, /system/lib64, /vendor/lib64]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:380)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
at com.facebook.litho.ComponentStethoNodeDescriptor.onGetStyles(ComponentStethoNodeDescriptor.java:193)
at com.facebook.litho.ComponentStethoNodeDescriptor.onGetStyles(ComponentStethoNodeDescriptor.java:26)
at com.facebook.stetho.inspector.elements.AbstractChainedDescriptor.getStyles(AbstractChainedDescriptor.java:154)
at com.facebook.stetho.inspector.elements.Document.getElementStyles(Document.java:153)
at com.facebook.stetho.inspector.protocol.module.CSS$2$1.store(CSS.java:144)
at com.facebook.litho.ComponentStethoNodeDescriptor.onGetStyleRuleNames(ComponentStethoNodeDescriptor.java:152)
at com.facebook.litho.ComponentStethoNodeDescriptor.onGetStyleRuleNames(ComponentStethoNodeDescriptor.java:26)
at com.facebook.stetho.inspector.elements.AbstractChainedDescriptor.getStyleRuleNames(AbstractChainedDescriptor.java:145)
at com.facebook.stetho.inspector.elements.Document.getElementStyleRuleNames(Document.java:147)
at com.facebook.stetho.inspector.protocol.module.CSS$2.run(CSS.java:118)
at com.facebook.stetho.common.android.HandlerUtil$2.onRun(HandlerUtil.java:90)
at com.facebook.stetho.common.android.HandlerUtil$2.onRun(HandlerUtil.java:87)
at com.facebook.stetho.common.android.HandlerUtil$WaitableRunnable.run(HandlerUtil.java:109)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6121)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
The annotation processor currently has hidden support for dependency injection through DependencyInjectionHelper.
Because of this implementation detail, the generated component classes instantiate the specs object in the generated code, e.g.:
private ListItemSpec mSpec = new ListItemSpec();
This is quite unexpected. I expect that ListItemSpec never gets instantiated and the generated components will just call the static methods on the spec class directly.
I discovered this because I like to add private constructors to my utility classes, e.g.:
@LayoutSpec
final class ListItemSpec {
...
private ListItemSpec() {
throw new AssertionError("No instances.");
}
}
This limitation also prevents Spec classes from being kotlin object
s, e.g.:
Currently you must write:
@LayoutSpec
class ListItemSpec {
companion object {
@JvmStatic
@OnCreateLayout
fun onCreateLayout(
c: ComponentContext,
...): ComponentLayout {
...
}
}
}
vs. what you could write (slightly more succinct):
@LayoutSpec
object ListItemSpec {
@JvmStatic
@OnCreateLayout
fun onCreateLayout(
c: ComponentContext,
...): ComponentLayout {
...
}
}
I'd like to suggest an alternative approach for DI:
Keep the static methods in the specs and delete DependencyInjectionHelper
(and all related code). If your spec needs dependencies, for whatever reason, you could pass an "Injector" through the Context as a system service. This is a relatively common pattern; you can see an example in the u2020 app.
Example usage would look like this:
@OnCreateLayout
static ComponentLayout onCreateLayout(
ComponentContext c,
...) {
Injector injector = Injector.obtain(c);
Dep1 dep1 = injector.getDep1();
Dep2 dep2 = injector.getDep2();
// etc
...
}
Feel free to close if you have alternative plans for this or don't agree with the proposal. Also let me know if you want help with the implementation 👍
Right now we only apply styles if the user explicitly sets one in the component's create() method. However, we want to be able to set this in the Component itself so that you can make components automatically gather styles from the theme.
The work here is to automatically get the theme off the context and set the appropriate props on mount items (Text
, etc) if they are not otherwise overridden.
Point of contact @emilsjolander
We should have a pool of StateUpdate
objects instead of allocating a new one for each state update creation. The state update objects don't live past a layout calculation, so we can recycle them then. Each generated lifecycle would need a pool instance types to their specific StateUpdate
subclass and instead of calling new StateUpdate()
we would need to acquire / release these objects from / to the pool. This is very similar to how we currently generate pools for the specific builder objects.
Point of contact: @mihaelao
I want to achieve that developing a RecyclerView with video playing function .
When calling Layout.create(c, component)
after the component has been measured, it causes the subsequent attribute (including the click handler) to be lost.
What happens is that we end up with two internal nodes for the same components and it doesn't work out well. The problem relates to returning early when we call LayoutState.collectResults()
and InternalNode.isNestedTreeHolder()
returns true, which is the case when we already have a cached layout for the component associated with the node.
Point of contact: @marco-cova
java.lang.UnsatisfiedLinkError: dlopen failed: "/data/data/com.nullcognition.litho/lib-main/libgnustl_shared.so" is 32-bit instead of 64-bit
Create a project, import all gradle dependencies(uncomment testing dep.), add App application class, change manifest application name to App class, init SoLoader in App, add Testing your Installation code, run.
Now, when you run the app you should see “Hello World!” displayed on the screen.
https://github.com/ersin-ertan/android-ui/tree/master/litho
SoLoader issue for 32 and 64-bit @rspencer01
Device: Galaxy Tab S2
There are Views in Android that only accept some attributes when the view is created and can't be changed after that (e.g. android:textCursorDrawable
in EditText
). We need a way to pass down these attribute sets into @OnCreateMountContent
to allow android widgets to be constructed with them.
Point of contact: @emilsjolander
At Installation section of the README, the getting started link points to http://fblitho.com/getting-started
which isn't available. Maybe it should be this page: http://fblitho.com/docs/getting-started
?
Should be landed on getting started page.
Use the following code inside @OnCreateLayout
:
Column.create(c).widthDip(72).heightDip(72).child(
Image.create(c).drawableRes(R.drawable.ic_launcher).scaleType(ImageView.ScaleType.CENTER_CROP)
).backgroundColor(Color.RED)
.build();
FYI: Adding alignItems(YogaAlign.STRETCH)
and/or alignContent(YogaAlign.STRETCH)
does not change the result in any way.
The following image is what is rendered on device:
When scaleType
is set to CENTER Litho generates the following:
The image should be spread accross the parent Column as marked by the red region (scaleType CENTER_CROP):
The image should be centered inside the view (scaleType CENTER):
See above minimal code sample to reproduce.
So that we don't force users to explicitly call build() when updating a RecyclerBinder
.
Point of contact: @pasqualeanatriello
We need an API for acquiring Views for measuring. This api would allow us to do things like:
@OnMeasure
protected static void onMeasure(
ComponentContext c,
ComponentLayout layout,
int widthSpec,
int heightSpec,
Size size) {
View toMeasure = c.acquireMeasurableView();
toMeasure.measure(...)
...
c.releaseMeasurableView(toMeasure);
}
This way we might cache the views by context and thread and make this thread safe and consistent with theming. The acquire being a Component level api could simply call ComponentLifecycle.createMountContent
under the hood (and create appropriate LayoutParams
).
Point of contact: @IanChilds
Add elevation to a Component without the need of wrapping it on a CardSpec which supports elevation.
Able to add elevation to a Component.
https://github.com/pavlospt/litho-playground/blob/master/app/src/main/java/com/pavlospt/lithoplayground/ButtonContainerSpec.java
Contains an example of the wrapping to a Card component, situation!
When we set border color and border width on container components (such as Row/Column or any layout spec), it is drawn correctly respecting the boundaries of child items. However, when we set border on a leaf node (such as TextSpec or any mount spec) the border is overlapping with the actual content of that leaf node. Let's see these two cases:
Case 1: This works fine, i.e. the text content is not overlapped with border:
Column.create(c)
.child(Text.create(c)
.text("Lorem ipsum")
.textSizeDip(18))
.borderColor(Color.GREEN)
.borderWidthDip(YogaEdge.LEFT, 6)
.borderWidthDip(YogaEdge.TOP, 6)
Case 2: Here the border is overlapping with the content:
Text.create(c)
.text("Lorem ipsum")
.textSizeDip(18)
.withLayout()
.borderColor(Color.GREEN)
.borderWidthDip(YogaEdge.LEFT, 6)
.borderWidthDip(YogaEdge.TOP, 6)
Possible solution could be to offset the LayoutOutput
's bounds when it's calculated (https://github.com/facebook/litho/blob/master/litho-core/src/main/java/com/facebook/litho/LayoutState.java#L215) in the same way as we do with padding.
Point of contact: @muraziz
The 1830 header should pop back into the scrollable surface. Currently the header does not pop into the document, which results in a strange/glitchy header.
Standard litho sample/demo as of today. Video: https://www.youtube.com/watch?v=KEbN1-iriSk&feature=youtu.be
We expose AccessibilityDelegate
method callbacks in LayoutSpecs
as event handlers. However, we're missing getAccessibilityNodeProvider
. Proper implementations of node providers can be very stateful since they need to handle hover callbacks. In order to make this as stateless as possible and play nice with the framework, there are two possibilities:
AccessibilityNodeInfoProviderCompat
object directly, instead expose its API as event handlers.ComponentAccessibilityDelegate
extends ExploreByTouchHelper
and expose its virtual view related abstract methods as event handlers. This would also require that we make sure that the dispatchHoverEvent
callback is extended to arbitrary views and not just ComponentHost
Regardless of which idea we choose, there are a couple of things to consider:
getAccessibilityNodeProvider
. Returning a non-null value changes how/whether certain accessibility events are routed to the right callbacksMountSpecs
that implement virtual view hierarchies, require we return a special node provider. If no event handler for node provider is set on the LayoutSpec
, we should respect the MountSpec
's original behavior, otherwise, we should override it. See ComponentAccessibilityDelegate#onInitializeAccessibilityNodeInfo
for an example.Point of contact: @muraziz
Add more fluent and straight-forward APIs for testing changes to components and sub-components after state updates. The current way to test stateful APIs is unnecessarily clunky. StateUpdatesTestHelper
is the current way to trigger state updates and make assertions about the state after an update. The test helper Gets Things Done, but it's unpleasant to use. You need to use reflection to set it up and if something goes wrong, it's unclear why.
It would be nice to unify this under our ComponentAsserts
API and allow for a fluent style like assertThat(component).afterStateUpdate(...).hasSubComponent(...)
.
Point of contact: @passy
It's an RecyclerBinder API so it should be under litho-widget in the org.facebook.litho.widget
java package.
Point of contact: @pasqualeanatriello
Each Component
is scoped to a ComponentContext
. This helps us identify, given a ComponentContext
, which component we are trying to apply a state update to.
Every time a component gets scoped to a component context, a new component context instance is created and associated with that component.
We should use a ComponentContext
pool instead of allocating a new ComponentContext
each time we want to have a ComponentContext
-> Component
association
Point of contact: @mihaelao
To avoid forcing users to explicitly call build() on ComponentInfo.Builder
every time they update the RecyclerBinder.
Point of contact: @pasqualeanatriello
I'm following the instructions in the README to run the sample
$ buck fetch sample
Error: cannot locate a .buckversion file in the current directory or any parent directories.
Are you sure you are inside a valid repository?
caabernathy-mbp:litho caabernathy$ buck fetch sample
Using watchman.
[-] PROCESSING BUCK FILES...FINISHED 0.0s [100%] 🐳 New buck daemon
[+] DOWNLOADING... (0.00 B/S, TOTAL: 0.00 B, 0 Artifacts)
[+] BUILDING...2.2s
BUILD FAILED: Couldn't get dependency '//sample/src/main/java/com/facebook/samples/litho:litho' of target '//sample:sample':
Parse error for build file /Users/caabernathy/Facebook/OpenSource/Litho/Code/litho/sample/src/main/java/com/facebook/samples/litho/BUCK:
TypeError: android_library() got an unexpected keyword argument 'plugins'
Call stack:
File "/Users/caabernathy/Facebook/OpenSource/Litho/Code/litho/.buckd/tmp/buck_run.qTVfjj/buck_python_program8423449095434172792/python_bundle.zip/buck_parser/buck.py", line 1271, in process_with_diagnostics
diagnostics=diagnostics)
File "/Users/caabernathy/Facebook/OpenSource/Litho/Code/litho/.buckd/tmp/buck_run.qTVfjj/buck_python_program8423449095434172792/python_bundle.zip/buck_parser/buck.py", line 1161, in process
implicit_includes=self._implicit_includes)
File "/Users/caabernathy/Facebook/OpenSource/Litho/Code/litho/.buckd/tmp/buck_run.qTVfjj/buck_python_program8423449095434172792/python_bundle.zip/buck_parser/buck.py", line 1094, in _process_build_file
implicit_includes=implicit_includes)
File "/Users/caabernathy/Facebook/OpenSource/Litho/Code/litho/.buckd/tmp/buck_run.qTVfjj/buck_python_program8423449095434172792/python_bundle.zip/buck_parser/buck.py", line 1016, in _process
exec(code, module.__dict__)
File "/Users/caabernathy/Facebook/OpenSource/Litho/Code/litho/sample/src/main/java/com/facebook/samples/litho/BUCK", line 28
COMPONENTS_YOGAPREBUILT_TARGET,
File "/Users/caabernathy/Facebook/OpenSource/Litho/Code/litho/.buckd/tmp/buck_run.qTVfjj/buck_python_program8423449095434172792/python_bundle.zip/buck_parser/buck.py", line 149, in invoke
return self.func(*args, **updated_kwargs)
Note, I'm using the open source version of Buck:
$ buck --version
buck version v2016.11.11.01
We have a lot of booleans to configure the test components like callsShouldUpdateOnMount
or implementsAccessibility
. Instead of keeping the configuration flags as booleans we could have them as bit flags.
Point of contact: @mihaelao
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.