I'm looking to make an infinite vertical carousel in Jetpack Compose but I can't find how to do it.
I want something like this.
I did not find an example on the internet in Compose, everything is in XML.
I try https://google.github.io/accompanist/pager/ but it's not exactly what I want.
Thanks for helping me.
Solution 1:
It depends, you can use Pager Accompanist library:
https://github.com/google/accompanist/tree/main/pager
And you can check the docs here:
https://google.github.io/accompanist/pager/
Solution 2:
You can also try:
#Composable
fun CircularList(
items: List<String>,
modifier: Modifier = Modifier
) {
val listState = rememberLazyListState(Int.MAX_VALUE / 2)
LazyColumn(state = listState, modifier = modifier) {
items(
count = Int.MAX_VALUE,
itemContent = {
// your content
}
)
}
}
Good luck!
Related
I was trying to create a sample Tab View in Jetpack compose, so the structure will be like
Inside a Parent TabRow we are iterating the tab title and create Tab composable.
More precise code will be like this.
#OptIn(ExperimentalPagerApi::class)
#Composable
private fun MainApp() {
Scaffold(
topBar = {
TopAppBar(
title = { Text(stringResource(R.string.app_name)) },
backgroundColor = MaterialTheme.colors.surface
)
},
modifier = Modifier.fillMaxSize()
) { padding ->
Column(Modifier.fillMaxSize().padding(padding)) {
val pagerState = rememberPagerState()
val coroutineScope = rememberCoroutineScope()
val tabContents = listOf(
"Home" to Icons.Filled.Home,
"Search" to Icons.Filled.Search,
"Settings" to Icons.Filled.Settings
)
HorizontalPager(
count = tabContents.size,
state = pagerState,
contentPadding = PaddingValues(horizontal = 32.dp),
modifier = Modifier
.weight(1f)
.fillMaxWidth()
) { page ->
PagerSampleItem(
page = page
)
}
TabRow(
selectedTabIndex = pagerState.currentPage,
backgroundColor = MaterialTheme.colors.surface,
contentColor = MaterialTheme.colors.onSurface,
indicator = { tabPositions ->
TabRowDefaults.Indicator(
Modifier
.pagerTabIndicatorOffset(pagerState, tabPositions)
.height(4.dp)
.background(
color = Color.Green,
shape = RectangleShape
)
)
}
) {
tabContents.forEachIndexed { index, pair: Pair<String, ImageVector> ->
Tab(
selected = pagerState.currentPage == index,
selectedContentColor = Color.Green,
unselectedContentColor = Color.Gray,
onClick = {
coroutineScope.launch {
pagerState.animateScrollToPage(index)
}
},
text = { Text(text = pair.first) },
icon = { Icon(imageVector = pair.second, contentDescription = null) }
)
}
}
}
}
}
#Composable
internal fun PagerSampleItem(
page: Int
) {
// Displays the page index
Text(
text = page.toString(),
modifier = Modifier
.padding(16.dp)
.background(MaterialTheme.colors.surface, RoundedCornerShape(4.dp))
.sizeIn(minWidth = 40.dp, minHeight = 40.dp)
.padding(8.dp)
.wrapContentSize(Alignment.Center)
)
}
And coming to my question is whenever we click on the tab item, the inner content get recompose so weirdly. Im not able to understand why it is happens.
Am attaching an image of the recomposition counts below, please take a look that too, it would be good if you guys can help me more for understand this, also for future developers.
There are two question we have to resolve in this stage
Whether it will create any performance issue, when the view getting more complex
How to resolve this recompostion issue
Thanks alot.
… whenever we click on the tab item, the
inner content get recompose so weirdly. Im not able to understand why
it is happens...
It's hard to determine what this "weirdness" is, there could be something inside the composable your'e mentioning here.
You also didn't specify what the API is, so I copied and pasted your code and integrated accompanist view pager, then I was able to run it though not on an Android Studio with a re-composition count feature.
And since your'e only concerned about the Text and the Icon parameter of the API, I think that's something out of your control. I suspect the reason why your'e getting those number of re-composition count is because your'e animating the page switching.
coroutineScope.launch {
pagerState.animateScrollToPage(index)
}
Though 'm not able to try this on another Android Studio version with the re-composition feature, I think (though I'm not sure) scrolling to another page without animation will yield less re-composition count.
coroutineScope.launch {
pagerState.scrollToPage(index)
}
If it still bothers you, the best course of action is to ask them directly, though personally I wouldn't concerned much about this as they are part of an accepted API and its just Text and Icon being re-composed many times by an animation which is also fine IMO.
Now if you have some concerns about your PagerSampleItem stability(which you have a full control), based on the provided code and screenshot, I think your'e fine.
There's actually a feature suggested from this article to check the stability of a composable, I run it and I got this report.
restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun PagerSampleItem(
stable page: Int
)
Everything about this report is within the article I linked.
Also, your Text and Icon are using String and ImageVector which is stable and immutable (marked by #Immutable) respectively.
So TLDR, IMO your code is fine, your PagerSampleItem is not re-composing in the screenshot.
My current goal is to achieve view that can represent a table, but this table can contain pretty much elements in its columns and rows. My current idea is to populate LazyColumn with LazyRows.
#Composable
internal fun Table() {
LazyColumn {
items(count = 100) {
LazyRow {
items(10) {
Box(
modifier = Modifier
.size(100.dp)
.border(width = 1.dp, color = Color.Black)
)
}
}
}
}
}
But there is a huge problem: i don't want the rows to be able to scroll by themselves, i want any scrolling to be shared. Unfortunately, i can't figure out gow to achieve that. As far as i know lazy grid can't help me either.
I also tried to use same instance of LazyListState, but it doesn't work.
In a new version appered new layout called "LazyLayout" - it's somewhat of your custom lazy layout builder. This should solve my problem, although i haven't tried it yet
I wanted to make a list of all the elements I would draw in my composable fragment. And make it as easy to maintain as possible.
So I thought, I should not put the list of elements inside my fragment, but outside, in a class that will stock and order those elements.
Here is the solution I came with :
interface SimpleDraw {
#Composable
fun Draw()
}
Create differentes implementation of my interface
class WelcomeBottomSheetElementsImpl : WelcomeBottomSheetElements {
override fun listOfItemInBottomSheet(): List<SimpleDraw> {
return listOf(
insiert here my list of instances of my interface)
fun LazyListScope.BottomsheetBody(
welcomeElements: List<SimpleDraw>,
clickViewModel: ClickViewModel
) {
items(items = welcomeElements) {
Box(
modifier = Modifier
.fillMaxWidth()
.background(color = MaterialTheme.colors.background)
.padding(start = 10.dp, end = 10.dp, top = 5.dp)
) {
it.Draw()
}
}
}
So far it works great ! Produces the result I was looking at, but it feels off. It feels like this is not the way to do it in Compose.
Is this way correct or am I wrong ?
I was playing around with Jetpack Compose TextField and I found one strange behaviour with Keyboard.
If my TextField is around bottom of the screen and I open keyboard, the TextField is remain hidden behind the keyboard.
I tried some solutions as well.
Modifying android:windowSoftInputMode="adjustPan" and android:windowSoftInputMode="adjustResize"
If I use adjustPan, sometimes TextField is lifted up with the Keyboard but sometimes it does not.
Here is the code and images of what is happening.
Ok I did something that worked for me, I clarify that I have only been learning compose for a few weeks so don't expect much from me, I simply did something that may not be the right way but it is functional for me and may be useful to anyone.
What I did was create a main class that inherits the ComponentActivity() with all the toys.
class Login : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
HealthAtHansClientTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
LoginLayout()
}
}
}
}
}
After that I imported my #Composable function which contained my layout with the LoginLayout, but the important part is this:
val scrollState = rememberScrollState()
Column(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.padding(bottom = 100.dp, end = 40.dp, start = 40.dp)
.verticalScroll(scrollState),
verticalArrangement = Arrangement.SpaceAround,
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(top = 30.dp)
) {
Text(text = "Hola !", style = TextStyle(fontSize = 40.sp))
}
Row(horizontalArrangement = Arrangement.Center) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
TextField(
maxLines = 1,
modifier = Modifier.fillMaxWidth(),
value = documentNumber,
onValueChange = { documentNumber = it })
Spacer(modifier = Modifier.height(100.dp))
TextField(
maxLines = 1,
modifier = Modifier.fillMaxWidth(),
value = privateCode,
onValueChange = { privateCode = it })
}
}
}
Note that the space between the Textfields is 100 this was just to test that it is functional.
and finally declare the Login class in my main activity in the following way, since the Mainactivity came by default but it was only for this test, the idea is only that they realize the line that I added
And voilà that was all now my TextField is not hidden, I think it would be very feasible if you have extensive forms you create your "activity" in the manifest and add the line android:windowSoftInputMode="adjustResize"
that way the problem is over.
I hope someone with more skill and knowledge can do something more efficient, for now it works for me.
If there is already a more efficient solution for that, the comment is appreciated, if my solution is stupid, I would appreciate feedback to learn.
One other thing that happens is that if you run the emulator with 'DefaultPreview', none of the ways I try to do it work.
If you run the emulation of your application in App, it works without problem.
But I wanted to go further, so I compiled this example in a release apk version where it is supposed to look like it should and it works perfectly as you can see in the image.
Update at October 2022: The following code does the trick:
class SampleActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState)
setContent {
LazyColumn(
contentPadding = WindowInsets.navigationBars.asPaddingValues()
) {
// items
}
}
}
}
Setting Activity to fit system windows and also using contentPadding is key here.
How can I use combination of Lottie json animation and Jetpack Compose UI in Android?
I already tried AndroidView(resId = R.layout.animation) where is com.airbnb.lottie.LottieAnimationView with field lottie_rawRes but is it the best way?
Lottie compose has been released:
Dependency:
implementation "com.airbnb.android:lottie-compose:$lottie_version"
Basic usage:
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.my_animation))
LottieAnimation(composition)
As of compose version alpha05, Lottie seems to be working fine:
#Composable
fun CustomView(modifier: Modifier = Modifier
.fillMaxWidth()) {
val visibility = remember { mutableStateOf(0) }
val context = ContextAmbient.current
val customView = remember { LottieAnimationView(context) }
// Adds view to Compose
AndroidView({ customView }) { view ->
// View's been inflated - add logic here if necessary
with(view) {
setAnimation(R.raw.choose)
playAnimation()
repeatMode = LottieDrawable.INFINITE
foregroundGravity = Gravity.CENTER
}
}
}
First class support for Lottie has not been implemented yet but it will be eventually.
I'm not really sure if it is the best way to do it, but that's the current recommmended way to include an Android View in a #Composable function.
#Composable
fun <T : View> AndroidView(
viewBlock: (Context) -> T,
modifier: Modifier = Modifier,
update: (T) -> Unit = NoOpUpdate
)
It seems that they are working on it: https://github.com/airbnb/lottie-android/commits/gpeal/compose-1