Content Modeling in Android
Learn how to handle different content-type and nestable blocks, render rich text, and use story references to manage content globally.
In the existing space, create the following blocks:
- An
articlecontent type block with the following fields:title: Textcontent: Rich text
- A
featured-articlesnestable block with the following field:articles: References
Next, create an Articles folder, open it, and create a few stories that use the article content type.
Finally, add the featured-articles block to the body field of the Home story, and select the created articles to feature.
Create and register blocks
Section titled “Create and register blocks”Update the BlockLibrary.kt file to add Component subclasses for the new blocks.
package com.example.myapplication
import kotlinx.serialization.SerialNameimport kotlinx.serialization.Serializableimport com.storyblok.cdn.schema.Componentimport com.storyblok.cdn.schema.RichTextimport com.storyblok.cdn.schema.Story…@Serializable@SerialName("teaser")data class Teaser(val headline: String): Component()
@Serializable@SerialName("article")data class Article(val title: String, val content: RichText) : Component()
@Serializable@SerialName("featured-articles")data class FeaturedArticles(val articles: List<Story<Article>>) : Component()The fields of the article and featured-articles blocks are defined as follows:
Article.contentis defined asRichTextwhich can represent any rich text node (a document in this case).FeaturedArticles.articlesis defined asList<Story<Article>>which will cause the referenced stories to be resolved and returned. To receive only the UUIDs of the linked stories change the type of the field toList<Uuid>.
Next, add composables for these blocks inside the blockProvider in MainActivity.kt.
…import androidx.navigation3.ui.NavDisplayimport androidx.navigation3.runtime.entryProviderimport androidx.compose.foundation.layout.Columnimport androidx.compose.foundation.layout.Spacerimport androidx.compose.foundation.layout.heightimport androidx.compose.material3.TextButton
… blockProvider = blockProvider( fallback = { it, _ -> Text("Unknown block type '${it.component}'") } storyLinkListener = { uuid, _ -> backStack.add(StoryKey(uuid = uuid)) } ) { block<Page> { page, modifier -> LazyColumn(modifier) { items(page.body, key = { it.uid }) { Block(it, Modifier.fillMaxWidth()) } } } block<Feature> { feature, modifier -> Text(feature.name, modifier.padding(16.dp)) } block<Teaser> { teaser, modifier -> Text(teaser.headline, modifier.padding(16.dp), style = typography.headlineMedium) } block<Grid> { grid, modifier -> FlowRow(modifier) { grid.columns.forEach { Block(it) } } } block<FeaturedArticles> { featured, modifier -> Column(modifier.padding(16.dp)) { Text("Featured Articles", style = MaterialTheme.typography.titleLarge) Spacer(Modifier.height(8.dp)) featured.articles.forEach { article -> TextButton(onClick = { backStack.add(StoryKey(story = article)) }) { Text(article.content.title) } } } } block<Article> { article, modifier -> Column(modifier.padding(16.dp)) { Text(article.title, style = MaterialTheme.typography.headlineLarge) Spacer(Modifier.height(16.dp)) RichText(article.content, Modifier.fillMaxWidth()) } } } …Composables for FeaturedArticles and Article are registered alongside the existing blocks:
- The
block<FeaturedArticles>composable renders links to the featured articles, which on click construct aStoryKeywith the articleStoryinstance for immediate display of the selected article. - The
block<Article>composable invokesRichText()to render the article’s rich text content.
Also storyLinkListener is set in the blockProvider to handle any story links present in the rich text content.
Run the app and see the home story with the links to the featured articles being rendered. Tapping any link navigates to the article.
Related resources
Section titled “Related resources”Was this page helpful?
This site uses reCAPTCHA and Google's Privacy Policy (opens in a new window).Terms of Service (opens in a new window) apply.
Get in touch with the Storyblok community