ribesg
04/03/2019, 8:18 AMhorizontalChain
in a constraintLayout
for the first time using the dsl, and it’s not easy nor easy to readkluck
05/06/2019, 7:27 AMFailed to instantiate one or more classes
The following classes could not be instantiated:
- splitties.views.dsl.idepreview.UiPreView (Open Class, Show Exception, Clear Cache)
Here's my preview file `src/debug/res/layout/main_preview.xml`:
<splitties.views.dsl.idepreview.UiPreView
xmlns:android="<http://schemas.android.com/apk/res/android>"
xmlns:app="<http://schemas.android.com/apk/res-auto>"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:splitties_class_package_name_relative=".MainUi"/>
The actual Ui file:
class MainUi(override val ctx: Context) : Ui {
override val root = coordinatorLayout {
fitsSystemWindows = true
add(appBarLayout(theme = R.style.AppTheme_AppBarOverlay) {
add(toolbar {
popupTheme = R.style.AppTheme_PopupOverlay
(ctx as? AppCompatActivity)?.setSupportActionBar(this)
}, defaultLParams())
}, appBarLParams())
add(frameLayout(id = R.id.container) {}, contentScrollingWithAppBarLParams())
}
}
In my dependencies, I have debugImplementation("com.louiscad.splitties:splitties-views-dsl-ide-preview:$splittiesVersion")
Is there something I might have missed?Pierfrancesco Gulinelli
05/17/2019, 5:22 PMPierfrancesco Gulinelli
05/20/2019, 9:50 AMlouiscad
06/17/2019, 10:58 AMribesg
06/25/2019, 2:46 PMribesg
06/28/2019, 10:49 AMSwipeRefreshLayout
in Splitties right?ribesg
07/18/2019, 12:55 PMstartActivityForResult
, is there no extension that cover this use case anywhere?nickk
07/29/2019, 12:32 PMverticalLayout, scrollView, textView, button
etcnickk
07/30/2019, 3:04 PMjava.lang.ClassNotFoundException: com.louiscad.splittiessample.main.MainUi
at org.jetbrains.android.uipreview.ModuleClassLoader.load(ModuleClassLoader.java:201)
at com.android.tools.idea.rendering.RenderClassLoader.findClass(RenderClassLoader.java:61)
at org.jetbrains.android.uipreview.ModuleClassLoader.findClass(ModuleClassLoader.java:135)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at org.jetbrains.android.uipreview.ModuleClassLoader.loadClass(ModuleClassLoader.java:235)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at splitties.views.dsl.idepreview.UiPreView.<init>(UiPreView.kt:60)
at splitties.views.dsl.idepreview.UiPreView.<init>(UiPreView.kt:43)
at splitties.views.dsl.idepreview.UiPreView.<init>(UiPreView.kt)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.jetbrains.android.uipreview.ViewLoader.createNewInstance(ViewLoader.java:403)
at org.jetbrains.android.uipreview.ViewLoader.loadClass(ViewLoader.java:186)
at org.jetbrains.android.uipreview.ViewLoader.loadView(ViewLoader.java:144)
at com.android.tools.idea.rendering.LayoutlibCallbackImpl.loadView(LayoutlibCallbackImpl.java:309)
at android.view.BridgeInflater.loadCustomView(BridgeInflater.java:418)
at android.view.BridgeInflater.loadCustomView(BridgeInflater.java:429)
at android.view.BridgeInflater.createViewFromTag(BridgeInflater.java:333)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
at android.view.LayoutInflater.inflate(LayoutInflater.java:394)
at com.android.layoutlib.bridge.impl.RenderSessionImpl.inflate(RenderSessionImpl.java:323)
at com.android.layoutlib.bridge.Bridge.createSession(Bridge.java:394)
at com.android.tools.idea.layoutlib.LayoutLibrary.createSession(LayoutLibrary.java:200)
at com.android.tools.idea.rendering.RenderTask.createRenderSession(RenderTask.java:572)
at com.android.tools.idea.rendering.RenderTask.lambda$inflate$5(RenderTask.java:698)
at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
If I clean the project, I get a slightly different error:
Missing classes: The following classes could not be found:
splitties.views.dsl.idepreview.UiPreView
nickk
07/31/2019, 3:22 PMalert {
customView { ... }
}
?ispbox
08/08/2019, 9:35 AMreturn scrollView {
verticalLayout {
}.lparams {
margin = dip(buttonMargin) // Margin for all sides, except bottom (it doesn't work in ScrollView).
}
bottomPadding = dip(2 * buttonMargin) // Special padding for bottom of ScrollView.
}
I tried something like:
private val scrollView = view(::ScrollView) {
add(content, lParams {
margin = dip(buttonMargin) // Margin for all sides, except bottom (it doesn't work in ScrollView).
width = matchParent
height = matchParent
bottomPadding = dip(buttonMargin) // Special padding for bottom of ScrollView.
})
}
override val root = verticalLayout {
background = resources.getDrawable(android.R.color.white, null)
add(scrollView, lParams {
margin = dip(buttonMargin) // Margin for all sides, except bottom (it doesn't work in ScrollView).
width = matchParent
height = matchParent
bottomPadding = dip(buttonMargin) // Special padding for bottom of ScrollView.
})
}
But no margins/padding is applied at all. What's wrong?ispbox
08/08/2019, 7:48 PMView
into ViewGroup
dynamically, after it's creation, is there any way to do that shorter / with Splitties DSL?
root.addView(childView, LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT))
All samples I've seen follow one (most common) workflow of static UI. But I need to add some views dynamically.nickk
08/09/2019, 12:04 PMview { cornerRadius = 3 }
or
view { shadowRadius = 2 }
ispbox
08/12/2019, 5:39 AMispbox
08/12/2019, 6:46 PMclass ItemsUi(override val ctx: Context,
private val displayHelper: DisplayHelper) // Any other stuff for abstraction from platform...
: Ui {
/**
* Holder for buttons.
*/
val content = verticalLayout {
}
/**
* Root of Ui. Should be below all other properties for correct initialization order.
*/
override val root = verticalLayout {
background = resources.getDrawable(android.R.color.white, null)
add(content, lParams {
width = matchParent
height = matchParent
})
}
/**
* Creates UI based on data.
*/
fun createUi(items: List<Item>?) {
content.apply {
for (item in items) {
add(createButton(item), lParams {
width = matchParent
height = matchParent
})
}
}
}
}
class ItemsPresenter(ownerScope: CoroutineScope,
private var view: View?,
private val loadItemsCommand: LoadItemsCommand) : CoroutineScope by ownerScope {
interface View {
fun showItems(items: List<Item>?)
}
fun loadItems() = launch(<http://Dispatchers.IO|Dispatchers.IO>) {
val items = loadItemsCommand(null)
withContext(Dispatchers.Main) {
view?.showItems(items)
}
}
fun stop() {
view = null
}
}
class ItemsController : Controller(),
CoroutineScope,
KoinComponent,
ItemsPresenter.View {
private val itemsPresenter: ItemsPresenter by inject { parametersOf(this, this) }
private lateinit var itemsUi: ItemsUi
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View {
itemsPresenter.loadItems()
val displayHelper: DisplayHelper by inject()
itemsUi = ItemsUi(container.context, displayHelper, ::onItemSelection)
// or, alternatively, you can do something like that:
// itemsUi.button.onClick {
// val pushHandler = FadeChangeHandler(false)
// val popHandler = FadeChangeHandler()
//
// router.pushController(RouterTransaction.with(ItemDetailsController())
// .pushChangeHandler(pushHandler)
// .popChangeHandler(popHandler))
// }
return itemsUi.root
}
override fun onDestroyView(view: View) {
super.onDestroyView(view)
itemsPresenter.stop()
}
override fun showItems(items: List<Item>?) {
itemsUi.createUi(items)
}
private fun onItemSelection(itemId: Int) {
val pushHandler = FadeChangeHandler(false)
val popHandler = FadeChangeHandler()
router.pushController(RouterTransaction.with(ItemDetailsController())
.pushChangeHandler(pushHandler)
.popChangeHandler(popHandler))
}
override val coroutineContext: CoroutineContext by lazy {
(activity as MainActivity).coroutineContext
}
}
nickk
08/13/2019, 11:36 AMView.wrapInRecyclerView()
provide a performance increase? Or is there some other reason for it?nickk
08/13/2019, 11:44 AMispbox
08/16/2019, 6:09 AMinterface AndroidInboxUi : InboxUiContract, Ui
interface IOSInboxUi : InboxUiContract {
val root: UIView
}
Is it actually used in some app with Kotlin Native?ispbox
08/17/2019, 11:04 AMval launchDemoBtn = button {
textResource = R.string.go_to_the_demo
}
It doesn't work for me - just empty space is shown, and no errors.
I didn't notice this initially because I started right from AppCompat samples (they work pretty well :))ispbox
08/18/2019, 4:43 PMtext
property should be initialized, and if it is after - everything works without this extra property).
Maybe the is some technique for initialization in one transaction, without intermediate UI invalidation?Tankraj Joshi
08/21/2019, 5:53 AMPierfrancesco Gulinelli
08/21/2019, 7:38 AMlouiscad
08/23/2019, 10:07 AMadd
extension for ViewGroup
?
inline fun <V : View> ViewGroup.add(
view: V,
lp: ViewGroup.LayoutParams,
beforeChild: View? = null,
afterChild: View? = null
): V
If not, would it annoy you to see it in autocomplete? (😤 reaction is fine for that)ispbox
08/25/2019, 8:03 AMprivate val appCompatStyles = AppCompatStyles(ctx)
private val buttons = appCompatStyles.button
val button = buttons.default {
}
while the following replacement works well:
val button = view<AppCompatButton>(::AppCompatButton){
}
ispbox
08/27/2019, 7:24 AMfun View.onClick(action: suspend (View) -> Unit) {
// launch one actor
val eventActor = GlobalScope.actor<View>(Dispatchers.Main) {
for (event in channel) action(event)
}
// install a listener to activate this actor
setOnClickListener {
eventActor.offer(it)
}
}
Another cool guy here suggests even better dsl solution:
https://www.hellsoft.se/even-smarter-async-with-coroutine-actors/
But my dream was to have some handy solution like View.awaitOneClick
(maybe, View.processOneClick
?) that incorporates waiting for coroutine to finish and then unblocks button.
My current solution is pretty simple - just disable button before long operation, and enable it after its completion. How do you handle the similar tasks, and what is the real necessity for View.awaitOneClick
?louiscad
08/28/2019, 7:34 AMlouiscad
08/28/2019, 1:05 PMConstraintLayout
, would you prefer to use below(view)
instead of topToBottomOf(view)
, above
instead of bottomToTopOf
, before
instead of endToStartOf
and after
instead of startToEndOf
?
I'm considering adding these into the ConstraintLayout module as aliases to the existing ones.wasyl
09/17/2019, 7:48 AMcoroutineScope
and lifecycleScope
and similarly defined to be active until the Lifecycle[Owner] is destroyed.
. I’m not using coroutines in production yet, so maybe that’s a silly question, but do those scopes suspend if the lifecycle is in stopped state (similarly to LiveData waiting before delivering values)? Is it even possible (and reasonable) with scopes?wasyl
09/17/2019, 12:49 PMLiveData<String>
to TextView::setText
?
Probably couple of extension methods would be enough for majority of use cases, but I imagine something like adapters/converters would make view dsl very interesting