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.
Related
I have this image I want to load, I am using coil in jetpack compose to try and load it yet it didn't load and just gave me an empty composable. Whenever I try to load a different image from any other website it works, yet when I use the same website I am loading this image from. It doesn't Work.
Here is My Code:
#Composable
fun BookItem(
title: String,
cover: String?,
unreadChapters: Int,
) {
Box(
modifier = Modifier
.wrapContentSize(),
contentAlignment = Alignment.Center
) {
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(cover)
.crossfade(true)
.build(),
contentDescription = title,
contentScale = ContentScale.Inside,
modifier = Modifier
.clip(RoundedCornerShape(size = 12.dp))
.size(200.dp)
)
}
}
Here is the link:
https://static.lightnovelworld.com/bookcover/300x400/01365-shadow-slave.jpg
I tried using glide instead of coil and I got the same problem.
Thanks and Regards
You can debug it using:
val imageLoader = LocalContext.current.imageLoader.newBuilder()
.logger(DebugLogger())
.build()
AsyncImage(
//...
imageLoader = imageLoader,
)
Result:
🚨 Failed - https://static.lightnovelworld.com/bookcover/300x400/01365-shadow-slave.jpg - coil.network.HttpException: HTTP 403:
You can try to add some headers in you requests using something like:
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(url)
.setHeader("User-Agent", "Mozilla/5.0")
.build(),
//
)
I use Coil to load .svg resources from the web, for example:
#Composable
fun Widget(modifier: Modifier = Modifier) {
AsyncImage(
modifier = Modifier.fillMaxSize(),
model = ImageRequest.Builder(LocalContext.current)
.decoderFactory(SvgDecoder.Factory())
.data("https://www.svgrepo.com/show/326168/circle-large.svg")
.build(),
contentDescription = null,
contentScale = ContentScale.FillWidth
)
}
It loads successfully when running on devices, but when running in Compose Preview, no resources is displayed. How to have Compose Preview load and display resources fetched from the Web?
I have a pager (Accompanist) with image that are get from web with Coil in Compose.
The rememberPainter() seem to only call the request when the Image composable is shown for the first time.
So when I slide page in the pager, the Image show only at that moment and so we have to wait a moment.
Any way to force the rememberPainter (Coil) to preload ?
Edit 1 :
Here is a simple version of my implementation (with lots of stuff around removed but that had no impact on the result) :
#Composable
private fun Foo(imageList: List<ImageHolder>) {
if (imageList.isEmpty())
return
val painterList = imageList.map {
rememberImagePainter(
data = it.getDataForPainter(),
builder = {
crossfade(true)
})
}
ImageLayout(imageList, painterList)
}
#Composable
fun ImageLayout(imageList: List<ImageHolder>, painterList: List<Painter>) {
HorizontalPager(
count = imageList.size,
modifier = Modifier.fillMaxWidth(),
) { page ->
Image(
painter = painterList[page],
"",
modifier = Modifier
.fillMaxWidth()
.height(200.dp)
.background(
imageList[page].colorAverage
),
contentScale = ContentScale.Crop
)
}
}
I tried with having directly the rememberImagePainter at the Image too just in case.
But the problem is clearly that Image() of page 2, 3, 4 isn't rendered so Image don't do the call to the painter. I tried to look how it work inside but couldn't find.
Edit 2 : I found a workaround but it's not clean
for (painter in painterList)
Image(painter = painter, contentDescription = "", modifier = Modifier.size(0.001.dp))
It force coil to load image and with a size really small like 0.001.dp (with 0 it don't load).
Also the problem is that in the builder you need to force a size or it will just load one pixel, so I force the full size of image as I don't know what size would have been available for the image.
In the Coil documentation there is a section about preloading. Depending on your architecture, you can do this in different places, the easiest is to use LaunchedEffect:
val context = LocalContext.current
LaunchedEffect(Unit) {
val request = ImageRequest.Builder(context)
.data("https://www.example.com/image.jpg")
// Optional, but setting a ViewSizeResolver will conserve memory by limiting the size the image should be preloaded into memory at.
// For example you can set static size, or size resolved with Modifier.onSizeChanged
// .size(coil.size.PixelSize(width = 100, height = 100))
// or resolve display size if your images are full screen
// .size(DisplaySizeResolver(context))
.build()
context.imageLoader.enqueue(request)
}
Before version 2.0.0 use LocalImageLoader.current instead of context.imageLoader to get the image loader.
Here is full code for accompanist pager with coil preloading and indicator with video example
I'm migrating from XML layouts to Jetpack Compose and noticed that the Image composable does not scale an image as good as ImageView when the image gets cropped.
The image on the top is added via Jetpack Compose, the one at the bottom is an ImageView.
For comparison, I added them next to each other like this:
Column {
Image(
painter = painterResource(id = R.drawable.my_image),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.size(280.dp)
)
Spacer(
modifier = Modifier.height(4.dp)
)
AndroidView(
factory = { context ->
ImageView(context).apply {
scaleType = ImageView.ScaleType.CENTER_CROP
setImageResource(R.drawable.my_image)
}
},
modifier = Modifier.size(280.dp)
)
}
The effect is depending on the image which is used and I noticed it's mostly promiment on low-end devices, however I would expect Jetpack Compose to have the same or higher image quality, as it is the new framework for building UI on Android.
Is there something I'm missing which can give me the same quality as ImageView?
I'm migrating my app and for the grid view I used LazyVerticalGrid that loads images using coilPainter but the scrolling stutters a lot and it feels laggy. Does anyone have a solution or a better implementation for this?
val photos: List<Photo>? by photosViewModel.photosLiveData.observeAsState(null)
Surface(modifier = Modifier.fillMaxSize()) {
Box(
modifier = Modifier.fillMaxSize()
) {
LazyVerticalGrid(
cells = GridCells.Fixed(3)
) {
photos?.let { photosList ->
items(photosList) { photo ->
Image(
modifier = Modifier.padding(2.dp).clickable {
photosViewModel.onPhotoClicked(photo)
},
painter = rememberCoilPainter(photo.url),
contentDescription = stringResource(R.string.cd_details_photo),
contentScale = ContentScale.Fit,
alignment = Alignment.Center,
)
}
}
}
}
}
Update
Trying to move rememberCoilPainter above Image like val painter = rememberCoilPainter(photo.url) and use the painter inside the Image did not work
items takes an additional parameter key, assign this parameter to a unique value like the index of each photo of your list, If you don't know how does that relate to scrolling jank? Or what the heck am I talking about? check out the following documentation for a detailed explanation:
https://developer.android.com/jetpack/compose/lifecycle#add-info-smart-recomposition
After updating my compose image loading library to coil-compose I was forced to set a size to either the request builder or the image itself. The problem of the stuttering was caused by allowing the photo to load the original size and thus recomposing was done multiple times and loading the image had to wait for the picture to load. By setting e fixed height to the Image fixed the issue because the Images() were created and the recomposition was made only for the picture inside not for the Image itself with different height.