英文:
How to make initials icons using Coil in Jetpack Compose
问题
So I am using the Coil library for our image processing and I noticed in the placeholder it only takes an int. I want, however, to display initials if a user does not have an avatar or in case of any error show initials, like this image below. Problem is, I am new in Jetpack Compose and not sure how I can achieve this. See my code below.
I have this card that has an icon and some details, my Profile Card
ProfileCard(
personName = String.format("%s %s", e.firstName, e.lastName),
personC = entity.program ?: "",
painter = rememberAsyncImagePainter(model = getProfileAvatar(entity.id)),
onCardClick = {})
My getProfileAvatar()
private fun getProfileAvatar(id: String) : ImageRequest {
val url = ServiceAPI.photoUrl(id)
return ImageRequest.Builder(requireContext())
.data(url)
.addHeader() )
.build() }
Will appreciate feedback, I did see a couple of posts, but don't address the Jetpack part.
英文:
So I am using the Coil library for our image processing and I noticed in the place holder it only takes an int. I want however to display initials if a user does not have an avatar or incase of any error show initials, like this image see below. Problem is, I am new in jetpack compose and not sure how I can achieve this. See my code below.
I have this card that has icon, and some details my Profile Card
ProfileCard(
personName = String.format("%s %s", e.firstName, e.lastName),
personC = entity.program ?: "",
painter = rememberAsyncImagePainter(model = getProfileAvatar(entity.id)),
onCardClick = {})
My getProfileAvatar()
private fun getProfileAvatar(id: String) : ImageRequest {
val url = ServiceAPI.photoUrl(id)
return ImageRequest.Builder(requireContext())
.data(url)
.addHeader() )
.build() }
Will appreciate feedback, I did see a couple of post, but don't address the Jetpack part.
答案1
得分: 2
Coil没有内置支持可组合的占位符。但是您有不同的选择。
您可以使用SubcomposeAsyncImage
,使用painter.state
来定义不同的可组合项:
SubcomposeAsyncImage(
model = url,
contentDescription = "contentDescription",
contentScale = ContentScale.Crop,
modifier = Modifier.clip(CircleShape)
) {
val state = painter.state
if (state is AsyncImagePainter.State.Loading || state is AsyncImagePainter.State.Error) {
//text with a background circle
Text(
modifier = Modifier
.padding(16.dp)
.drawBehind {
drawCircle(
color = Teal200,
radius = this.size.maxDimension
)
},
text = "NG",
style = TextStyle(color = Color.White, fontSize = 20.sp)
)
} else {
SubcomposeAsyncImageContent()
}
}
此外,AsyncImage
中的placeholder
参数接受一个Painter
。您可以定义自定义的TextPainter
:
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(url)
.build(),
placeholder = TextPainter(
circleColor = Teal200,
textMeasurer = rememberTextMeasurer(),
text = "NG",
circleSize = Size(200f, 200f)
),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.padding(16.dp)
)
其中:
class TextPainter(val circleColor: Color,
val circleSize: Size,
val textMeasurer: TextMeasurer,
val text: String,
) : Painter() {
val textLayoutResult: TextLayoutResult =
textMeasurer.measure(
text = AnnotatedString(text),
style = TextStyle(color = Color.White, fontSize = 20.sp)
)
override val intrinsicSize: Size get() = circleSize
override fun DrawScope.onDraw() {
//the circle background
drawCircle(
color = circleColor,
radius = size.maxDimension / 2
)
val textSize = textLayoutResult.size
//The text
drawText(
textLayoutResult = textLayoutResult,
topLeft = Offset(
(this.size.width - textSize.width) / 2f,
(this.size.height - textSize.height) / 2f
)
)
}
}
英文:
Coil has no built-in support for composable placeholders.
However you have different options.
You can use the SubcomposeAsyncImage
using the painter.state
to define different Composables:
SubcomposeAsyncImage(
model = url,
contentDescription = "contentDescription",
contentScale = ContentScale.Crop,
modifier = Modifier.clip(CircleShape)
) {
val state = painter.state
if (state is AsyncImagePainter.State.Loading || state is AsyncImagePainter.State.Error) {
//text with a background circle
Text(
modifier = Modifier
.padding(16.dp)
.drawBehind {
drawCircle(
color = Teal200,
radius = this.size.maxDimension
)
},
text = "NG",
style = TextStyle(color = Color.White, fontSize = 20.sp)
)
} else {
SubcomposeAsyncImageContent()
}
Also the placeholder
parameter in the AsyncImage
accepts a Painter
. You can define your custom TextPainter
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(url)
.build(),
placeholder = TextPainter(
circleColor= Teal200,
textMeasurer = rememberTextMeasurer(),
text="NG",
circleSize = Size(200f, 200f)
),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.padding(16.dp)
)
where:
class TextPainter(val circleColor: Color,
val circleSize : Size,
val textMeasurer: TextMeasurer,
val text : String,
) : Painter() {
val textLayoutResult: TextLayoutResult =
textMeasurer.measure(
text = AnnotatedString(text),
style = TextStyle(color = Color.White, fontSize = 20.sp)
)
override val intrinsicSize: Size get() = circleSize
override fun DrawScope.onDraw() {
//the circle background
drawCircle(
color = circleColor,
radius = size.maxDimension/2
)
val textSize = textLayoutResult.size
//The text
drawText(
textLayoutResult = textLayoutResult,
topLeft = Offset(
(this.size.width - textSize.width) / 2f,
(this.size.height - textSize.height) / 2f
)
)
}
}
答案2
得分: 0
你可以使用 Coil 的 SubcomposeAsyncImage
来实现这个功能。它允许你将任何可组合函数用作占位符或错误状态:
SubcomposeAsyncImage(
model = getProfileAvatar()
) {
val state = painter.state
if (state is AsyncImagePainter.State.Loading || state is AsyncImagePainter.State.Error) {
Text(text = "NG")
} else {
SubcomposeAsyncImageContent()
}
}
英文:
You can use coil's SubcomposeAsyncImage
for that. It allows you to use any composable function as a placeholder/error state:
SubcomposeAsyncImage(
model = getProfileAvatar()
) {
val state = painter.state
if (state is AsyncImagePainter.State.Loading || state is AsyncImagePainter.State.Error) {
Text(text = "NG")
} else {
SubcomposeAsyncImageContent()
}
}
答案3
得分: 0
val personName by remember{ mutableStateOf(String.format("%s %s", entity.firstName, entity.lastName)) }
val painter = rememberAsyncImagePainter(
model = ImageRequest.Builder(LocalContext.current)
.allowHardware(false)
.data("https://xxxx.xxxx.user_avatar.jpg")
.size(Size.ORIGINAL)
.build()
)
val isErrorState = painter.state is AsyncImagePainter.State.Error
val textMeasure = rememberTextMeasurer()
val textLayoutResult = textMeasure.measure(text = buildAnnotatedString { append(personName) }, style = TextStyle(color = Color.White, fontSize = 16.sp))
ProfileCard(
modifier = Modifier.drawBehind {
if(isErrorState) {
drawText(textLayoutResult = textLayoutResult)
}
},
personName = personName,
personC = entity.program ?: "",
painter = rememberAsyncImagePainter(model = getProfileAvatar(entity.id)),
onCardClick = {}
)
英文:
Example:
val personName by remember{ mutableStateOf(String.format("%s %s", entity.firstName, entity.lastName)) }
val painter = rememberAsyncImagePainter(
model = ImageRequest.Builder(LocalContext.current)
.allowHardware(false)
.data("https://xxxx.xxxx.user_avatar.jpg")
.size(Size.ORIGINAL)
.build()
)
val isErrorState = painter.state is AsyncImagePainter.State.Error
val textMeasure = rememberTextMeasurer()
val textLayoutResult = textMeasure.measure(text = buildAnnotatedString { append(personName) }, style = TextStyle(color = Color.White, fontSize = 16.sp))
ProfileCard(
modifier = Modifier.drawBehind {
if(isErrorState) {
drawText(textLayoutResult = textLayoutResult)
}
},
personName = personName,
personC = entity.program ?: "",
painter = rememberAsyncImagePainter(model = getProfileAvatar(entity.id)),
onCardClick = {}
)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论