{"id":16953933,"url":"https://github.com/romainguy/experiment-apex","last_synced_at":"2025-06-11T17:02:34.408Z","repository":{"id":41905269,"uuid":"431950593","full_name":"romainguy/experiment-apex","owner":"romainguy","description":"A basic, incomplete, buggy, far from efficient UI toolkit for Kotlin/Android. An experiment for fun and to learn.","archived":false,"fork":false,"pushed_at":"2022-04-23T08:26:26.000Z","size":3887,"stargazers_count":88,"open_issues_count":0,"forks_count":7,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-04-02T05:24:20.532Z","etag":null,"topics":["android","kotlin","ui","ui-toolkit"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/romainguy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-11-25T19:03:14.000Z","updated_at":"2024-12-11T13:31:23.000Z","dependencies_parsed_at":"2022-08-11T20:50:21.034Z","dependency_job_id":null,"html_url":"https://github.com/romainguy/experiment-apex","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/romainguy/experiment-apex","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/romainguy%2Fexperiment-apex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/romainguy%2Fexperiment-apex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/romainguy%2Fexperiment-apex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/romainguy%2Fexperiment-apex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/romainguy","download_url":"https://codeload.github.com/romainguy/experiment-apex/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/romainguy%2Fexperiment-apex/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259301675,"owners_count":22836974,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","kotlin","ui","ui-toolkit"],"created_at":"2024-10-13T22:08:20.984Z","updated_at":"2025-06-11T17:02:34.390Z","avatar_url":"https://github.com/romainguy.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Apex\n\nApex is just a simple proof of concept to demonstrate how easily you can build your own UI Toolkit\nfrom scratch. This code base is most likely full of bugs and design mistakes but it should help\nyou understand the basics of a UI Toolkit. It is meant as a learning and demonstration tool only.\n\nTested only in an emulator and only on API level 31.\n\n## Concepts\n\nWidgets are called elements and are all instances of the `Element` class. Apex elements are not\nintended to be subclassed, instead you build widgets by adding components to an element. Each\ncomponent has a single responsibility: layout, rendering, input event, or whatever else you want.\nComponents can be anything, and in the current codebase some are classes, some are interfaces, some\nare enums.\n\nFor instance a `Button` is an `Element` with the following components:\n\n- A `ButtonModel` (text, click listener, etc.), the public API of a button\n- A `RenderComponent`, to render the button\n- A `LayoutComponent`, to compute its own size and position the text\n- A `MotionInputComponent`, to react the touch events and handle clicks\n- An `InternalState`, to track the pressed state of the button\n\nApex also offers `Provider` instances, which are roughly equivalent to Jetpack Compose's composition\nlocals. They give access to global data throughout the tree: `Resources`, display density, the\ncurrent theme, etc. Any `Element` can inject new providers or override existing providers by using\nthe `ProviderComponent` component. `MainActivity` shows an example of using a `ThemeProvider` to\nmodify the current theme.\n\n## Exercises for the reader\n\nIf you'd like to play with this codebase a bit, here are a few things you could try:\n\n- Optimize components lookup. Right now, every lookup iterates over a flat list. It's not a big deal\n  since most elements will have a short list but this could be improved. Since it's intended that an\n  element can own multiple components of the same type, you'd probably have a data structure that\n  maps component types to a list (a linked hashmap for instance)\n- Optimize providers handling. Every layout/render/motion input phase currently re-applies the\n  providers. It's not very efficient. And the layout phase doesn't correctly apply the providers at\n  every level of the tree\n- Take the `MotionInputComponent` from `Button` and make it a generic, reusable API so you can\n  perform clicks on the `Image` widget in `MainActivity` as well\n- Track changes in data models to re-layout/re-draw only when needed\n- Don't relayout/redraw on *every* v-sync. It's wasteful\n- Reduce memory allocations (esp. generated by the many `RectF` and `SizeF` instances, among\n  other things)\n- Cleanup the inline/noinline/crossinline and reified generic mess in the various helper functions\n- Make this a multi-platform UI Toolkit! Remove Android-specific APIs (`Canvas`, `Bitmap`, etc.)\n  and use your own abstractions. For rendering, use [skiko](https://github.com/JetBrains/skiko)\n\n## Screenshot\n\nNot super exciting, but here it is:\n\n![Apex demo: a photo centered on screen with two buttons below, Previous and Next](./assets/apex_demo.png)\n\n## License\n\nSee [LICENSE](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fromainguy%2Fexperiment-apex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fromainguy%2Fexperiment-apex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fromainguy%2Fexperiment-apex/lists"}