OffscreenPageLimit behaviour for ViewPager from Accompanist - android

I am using HorizontalViewPager from Accompanist to show an image in each page of the viewpager. I am loading images with Coil. Here's the code:
val pagerState = rememberPagerState()
HorizontalPager(count = photos.size, state = pagerState) {
idx ->
photos[idx].let { cur ->
Image(
painter = rememberImagePainter(url),
contentDescription = null,
modifier - Modifier.fillMaxSize(),
contentScale = ContentScale.FillHeight,
alignment = Alignment.Center
)
}
}
It is working fine. But, Images are being loaded only after the page is opened. I was wondering if there is a way to preload the content of the adjacent pages of viewpager before they are opened.
ViewPager from AndroidX offers similar behavior with setOffscreenPageLimit method.

Related

HorizontalPager swipe stops working when fragment shows empty state

I am trying to implement a HorizontalPager that allows me to swipe between fragments. The thing is, when the fragment's data is empty, it shows an empty state but if this is shown, the HorizontalPager stops working, I can no longer swipe to other fragments, even the HorizontalPagerIndicator disappears.
I don't understand why this is happening, I made the empty state looked smaller in case it was covering the HorizontalPagerIndicator or something but that is not the case.
Any ideas?
This is the implementation:
val pagerState = rememberPagerState()
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
HorizontalPager(
modifier = Modifier
.fillMaxWidth()
.weight(1f),
count = MyFragmentEnum.values().size,
state = pagerState
) { page ->
when(MyFragmentEnum.values()[page]) {
FRAGMENT_1 -> Frag1()
FRAGMENT_2 -> Frag2()
FRAGMENT_3 -> Frag3()
FRAGMENT_4 -> Frag4()
}
}
HorizontalPagerIndicator(
pagerState = pagerState,
indicatorHeight = 20.dp,
indicatorWidth = 20.dp
)
}
On top of that, it always goes straight into fragment 2 for some reason even though it should be going to fragment 1.
Thanks.

How to make toolbar/appbar scrollable

I saw this app, which I thought to be very clean and well designed, so I tried using it to practice, but I had some issues.
They used a collapsing toolbar, which they made seamless with the status bar, but the toolbar doesn't collapse when scrolled, it just scrolls like a regular view, or composeable in jetpack compose.
And the toolbar scrolls when you swipe on it.
Here's an Image of it;
The issue I'm facing now is;
The collapsing toolbar doesn't scroll when I swipe on it, I tried giving the collapsing toolbar a .verticalScrollState, but it crashes the app.
And Also, when I scroll the elements (views) at the bottom of my App (which is the only side that scrolls, because the toolbar above doesn't respond), I don't get the same motion I get from the original App, mine appears as though the elements at the bottom is overlapping the toolbar, but I want everything to scroll upwards seamlessly.
So please (1) How do I make the collapsing toolbar scrollable, (11) How do I make everything scroll upwards seamlessly.
Here's my Collapsing toolbar code;
first I added a the gradle dependency
implementation "me.onebone:toolbar-compose:2.3.2"
#Composable
fun ContactCollapsingToolbar(
onContactsCardClick: (Int) -> Unit
) {
val collapsingToolbarState = rememberCollapsingToolbarScaffoldState()
CollapsingToolbarScaffold(
modifier = Modifier,
state = collapsingToolbarState,
scrollStrategy = ScrollStrategy.EnterAlwaysCollapsed,
toolbar = {
Box(
modifier = Modifier
.fillMaxWidth()
.height(150.dp)
.pin()
.background(
brush = Brush.linearGradient(
colors = listOf(
MaterialTheme.colors.primary,
White
)
)
)
)
Image(
painter = painterResource(id = R.drawable.fc4_self_massage),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier
.fillMaxSize()
.clip(RoundedCornerShape(bottomEnd = 45.dp))
//alpha =
)
Text(
text = stringResource(id = R.string.contact_categories),
style = TextStyle(color = MaterialTheme.colors.onPrimary) + MaterialTheme.typography.h1,
modifier = Modifier.padding(16.dp),
textAlign = TextAlign.Start
)
}
) {
ContactsContentScreen(onContactsCardClick)
}
}
I'll sinerely appreciate any help, whether code, instructions, or directing me somewhere.
Thanks to you in advance.

AsyncImage in LazyColumn Kotlin Compose

I have a list of photos from the internet and I want to load them into a LazyColumn. The problem is that some of them are loading faster than others so the photos appear in random order.
Here is the code:
val state = viewModel.photos.collectAsState()
val lastIndex = state.value.lastIndex
LazyColumn {
itemsIndexed(state.value) { i, photo ->
AsyncImage(
model = photo.urls.regular,
contentDescription = null,
modifier = Modifier.fillMaxWidth(),
)
if (i >= lastIndex-1 && !viewModel.isLoading.value) {
viewModel.getPhotos(6)
}
}
}
Sometimes image with LastIndex-1 occurs first and it triggers viewModel to get new data.
How can I make a handler for loading a list of images? Or maybe any suggestions on how to make a preloading screen which will end after loading all images into LazyColumn
I also have a Coil version too:
val model = ImageRequest.Builder(LocalContext.current)
.data(photo.urls.regular)
.size(Size.ORIGINAL)
.crossfade(true)
.build()
val painter = rememberAsyncImagePainter(model)
Image(
painter = painter,
contentDescription = null,
modifier = Modifier.fillMaxWidth(),
)

How to set visible indicator' dot and show the others when scrolling in jetpack compose

I have a lazyRow and I want to show list of indicators:
what I want: I want to show 6 items and when user scrolls other indicators get visible.
#Composable
private fun ImagesDotsIndicator(
modifier: Modifier,
totalDots: Int,
selectedIndex: Int
) {
LazyRow(
modifier = modifier,
horizontalArrangement = Arrangement.Center,
reverseLayout = true,
verticalAlignment = Alignment.CenterVertically
) {
if (totalDots == 1) return#LazyRow
items(totalDots) { index ->
if (index == selectedIndex) {
Box(
modifier = Modifier
.size(8.dp)
.clip(CircleShape)
.background(color = Color.White)
)
} else {
Box(
modifier = Modifier
.size(6.dp)
.clip(CircleShape)
.background(color = Color.LightGray)
)
}
Spacer(modifier = Modifier.padding(horizontal = 2.dp))
}
}
}
how can I make this indicator?
I would suggest you use Google's Accompanist HorizontalPager and HorizontalPagerIndicator if you want to swipe pages and show the dots. This is a layout that lays out items in a horizontal row, and allows the user to horizontally swipe between pages and also show the page indicator.
You need to add these 2 lines to your app build gradle file to add the dependencies.
// Horizontal Pager and Indicators - Accompanist
implementation "com.google.accompanist:accompanist-pager:0.24.7-alpha"
implementation "com.google.accompanist:accompanist-pager-indicators:0.24.7-alpha"
On your composable file, you can add a simple Sealed class to hold the data that you want to display e.g. text.
sealed class CustomDisplayItem(val text1:String, val text2: String){
object FirstItem: CustomDisplayItem("Hi", "World")
object SecondItem: CustomDisplayItem("Hello", "I'm John")
}
Thereafter make a template of the composable element or page that you want to show if the user swipes left or right.
#Composable
fun DisplayItemTemplate(item: CustomDisplayItem) {
Column() {
Text(text = item.text2 )
Spacer(modifier = Modifier.height(4.dp))
Text(text = item.text2)
}
}
Lastly use HorizontalPager and HorizontalPageIndicator composables to display the corresponding page when a user swipes back and forth.
#OptIn(ExperimentalPagerApi::class)
#Composable
fun ImagesDotsIndicator(
modifier: Modifier,
) {
//list of pages to display
val displayItems = listOf(CustomDisplayItem.FirstItem, CustomDisplayItem.SecondItem)
val state = rememberPagerState()
Column(modifier = modifier.fillMaxSize()) {
//A horizontally scrolling layout that allows users to
// flip between items to the left and right.
HorizontalPager(
count = 6,
state = state,
) {
/*whenever we scroll sideways the page variable changes
displaying the corresponding page */
item ->
//call template item and add the data
DisplayItemTemplate(item = displayItems[item])
}
//HorizontalPagerIndicator dots
HorizontalPagerIndicator(
pagerState = state,
activeColor = MaterialTheme.colors.primary,
inactiveColor = Color.Gray,
indicatorWidth = 16.dp,
indicatorShape = CircleShape,
spacing = 8.dp,
modifier = Modifier
.weight(.1f)
.align(CenterHorizontally)
)
}
}
Please see the above links to read more on how you can customize your composables to work in your case.
Actually it is preaty straight forward without any additional library:
val list = (0..100).toList()
val state = rememberLazyListState()
val visibleIndex by remember {
derivedStateOf {
state.firstVisibleItemIndex
}
}
Text(text = visibleIndex.toString())
LazyColumn(state = state) {
items(list) { item ->
Text(text = item.toString())
}
}
Create scroll state and use it on your list, and on created scroll state observe first visible item.

slider banner on android kotlin with photos 100% of the screen

slider banner on android kotlin all i found was detectDragGestures does anyone have any better suggestions?
slider banner with photos 100% of mobile phone screen
You can use the Pager from the accompanist library.
You just need to add the dependency:
dependencies {
implementation "com.google.accompanist:accompanist-pager:0.8.1"
}
And then use it as the following:
#ExperimentalPagerApi
#Composable
fun ViewPagerScreen() {
val images = listOf(
R.drawable.image1,
// include the other images here...
)
HorizontalPager(
state = rememberPagerState(pageCount = images.size),
offscreenLimit = 2
) { page ->
Image(
painterResource(id = images[page]),
null,
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Crop
)
}
}
If you need to load images from web, you can use another accompanist library: Coil or Glide.

Categories

Resources