Compose 调用 - 网络图片 Coil

一、概念

相比 Glide、Picasso 而言,Coil 更专注于 Compose 且它的代码使用 Kotlin。

二、添加依赖

最新版本

val coilVersion = "3.3.0"
implementation("io.coil-kt.coil3:coil-compose:$coilVersion")
//可选,如果没有集成过 Retrofit 或 OKHttp 的话
implementation("io.coil-kt.coil3:coil-network-okhttp:$coilVersion")
//可选,支持GIF
implementation("io.coil-kt.coil3:coil-gif:$coilVersion")
//可选,支持SVG
implementation("io.coil-kt.coil3:coil-svg:$coilVersion")

三、简单使用

根据加载的状态,AsyncImage() 只能设置不同的图,SubcomposeAsyncImage() 可以设置不同界面。

单界面

@Composable
@NonRestartableComposable
fun AsyncImage(
    model: Any?,        //传入 ImageRequest 或其 deda 属性
    contentDescription: String?,        //无障碍描述
    modifier: Modifier = Modifier,
    placeholder: Painter? = null,        //加载中占位图
    error: Painter? = null,        //失败占位图
    fallback: Painter? = error,        //空数据占位图(参数model是null的时候)
    onLoading: ((State.Loading) -> Unit)? = null,        //加载中的回调
    onSuccess: ((State.Success) -> Unit)? = null,        //请求成功的回调
    onError: ((State.Error) -> Unit)? = null,                //请求失败的回调
    alignment: Alignment = Alignment.Center,        //对齐
    contentScale: ContentScale = ContentScale.Fit,        //缩放
    alpha: Float = DefaultAlpha,        //透明度
    colorFilter: ColorFilter? = null,        //滤镜颜色
    filterQuality: FilterQuality = DefaultFilterQuality,        //滤镜质量(采样算法)
    clipToBounds: Boolean = true,        //裁剪边界(true内容奖被裁剪至边界范围内)
)

@Composable
@NonRestartableComposable
fun AsyncImage(
    model: Any?,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    transform: (State) -> State = DefaultTransform,
    onState: ((State) -> Unit)? = null,                                //状态被合并需要手动判断
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    alpha: Float = DefaultAlpha,
    colorFilter: ColorFilter? = null,
    filterQuality: FilterQuality = DefaultFilterQuality,
    clipToBounds: Boolean = true,
)
多界面

@Composable
@NonRestartableComposable
fun SubcomposeAsyncImage(
    model: Any?,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    transform: (State) -> State = DefaultTransform,

    //加载界面
    loading: @Composable (SubcomposeAsyncImageScope.(State.Loading) -> Unit)? = null,

    //成功界面
    success: @Composable (SubcomposeAsyncImageScope.(State.Success) -> Unit)? = null,

    //失败界面
    error: @Composable (SubcomposeAsyncImageScope.(State.Error) -> Unit)? = null,
    onLoading: ((State.Loading) -> Unit)? = null,
    onSuccess: ((State.Success) -> Unit)? = null,
    onError: ((State.Error) -> Unit)? = null,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    alpha: Float = DefaultAlpha,
    colorFilter: ColorFilter? = null,
    filterQuality: FilterQuality = DefaultFilterQuality,
    clipToBounds: Boolean = true,
)

AsyncImage(
    model = "https://example.com/image.jpg",    //网络资源
//    model = R.drawable.bkg_naruto,    //本地资源(没必要,用系统自带的Image)
    //需要手动判断状态的重载
    onState = { state ->
        when(state) {
            AsyncImagePainter.State.Empty -> TODO()
            is AsyncImagePainter.State.Error -> TODO()
            is AsyncImagePainter.State.Loading -> TODO()
            is AsyncImagePainter.State.Success -> TODO()
        }
    }
)

四、全局配置 ImageLoader

非必须,不自定义会使用默认的。

4.1 初始化方式(选一个)

4.1.1 通过 Application 实现(推荐)

class MyApplication : Application(), SingletonImageLoader.Factory {
    override fun newImageLoader(context: PlatformContext): ImageLoader {
        return ImageLoader.Builder(context)
            .build()
    }
}

4.1.2 通过 Application#onCreate() 调用

确保不会覆盖已创建的现有图像加载器。如果是单 Activity 也可以在 Activity#onCreate() 中调用。

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        SingletonImageLoader.setSafe { context ->
            ImageLoader.Builder(context)
                .build()
        }
    }
}

4.1.3 通过 Compose 根入口调用

适合 Compose Multiplatform。

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            setSingletonImageLoaderFactory { context ->
                ImageLoader.Builder(context)
                    .build()
            }
            Screen()
        }
    }
}

4.1.4 通过 StartUp 配置

class CoilInitializer : Initializer<SingletonImageLoader> {
    override fun create(context: Context): SingletonImageLoader {
        SingletonImageLoader.setSafe { context ->
            ImageLoader.Builder(context)
                .build()
        }
        return SingletonImageLoader
    }

    override fun dependencies(): List<Class<out Initializer<*>?>?> {
        return mutableListOf()
    }
}
<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false"
    tools:node="merge"
    >
    <meta-data
        android:name="com.momentum.ui.core.startup.CoilInitializer"
        android:value="androidx.startup"
        />
</provider>

4.2 功能配置

ImageLoader.Builder(context)
    //淡入淡出
    .crossfade(true)    //传入Int多少毫秒,或true为200
    //添加日志(会降低性能,且不要用于生产环境!)
    .logger(DebugLogger())
    //内存缓存
    .memoryCache {
        MemoryCache.Builder()
            .maxSizePercent(context, 0.25)  //此APP可用内存的百分比
            .build()
    }
    //磁盘缓存
    .diskCache {
        DiskCache.Builder()
            .directory(context.cacheDir.resolve("coil_cache"))
            .maxSizePercent(0.2)    //设备可用磁盘空间的百分比
            .build()
    }
    //更多特性支持
    .components {
        //支持SVG
        add(SvgDecoder.Factory())
        //支持GIF
        if (SDK_INT >= 28) {
            add(AnimatedImageDecoder.Factory())
        } else {
            add(GifDecoder.Factory())
        }
    }
    .build()
//清除缓存
SingletonImageLoader.get(context).memoryCache?.clear()
SingletonImageLoader.get(context).diskCache?.clear()

五、请求配置 ImageRequest

单独对可组合项设置,会覆盖全局设置。

AsyncImage(
    model = ImageRequest.Builder(LocalContext.current)
        .data("https://example.com/image.jpg")
        .crossfade(true)
        .size(30)    //限制图片的像素大小
        .build()
)

六、返回 Painter 而不使用可组合项

当不方便使用 AsyncImage() 或 SubcomposeAsyncImage() 可组合项时,返回一个 Painter 可用于自带组件 Image()。

@Composable
@NonRestartableComposable
fun rememberAsyncImagePainter(
    model: Any?,
    imageLoader: ImageLoader,
    placeholder: Painter? = null,
    error: Painter? = null,
    fallback: Painter? = error,
    onLoading: ((State.Loading) -> Unit)? = null,
    onSuccess: ((State.Success) -> Unit)? = null,
    onError: ((State.Error) -> Unit)? = null,
    contentScale: ContentScale = ContentScale.Fit,
    filterQuality: FilterQuality = DefaultFilterQuality,
)
@Composable
@NonRestartableComposable
fun rememberAsyncImagePainter(
    model: Any?,
    transform: (State) -> State = DefaultTransform,
    onState: ((State) -> Unit)? = null,                        //状态合并版本
    contentScale: ContentScale = ContentScale.Fit,
    filterQuality: FilterQuality = DefaultFilterQuality,
)
val painter = rememberAsyncImagePainter(
    model = ""
)
//设置给自带控件
Image(
    painter = painter,
    contentDescription = ""
)
//收集状态加载不同界面
val state by painter.state.collectAsState()
when(state) {
    AsyncImagePainter.State.Empty -> TODO()
    is AsyncImagePainter.State.Error -> TODO()
    is AsyncImagePainter.State.Loading -> TODO()
    is AsyncImagePainter.State.Success -> TODO()
}

七、网图预览处理

由于预览环境禁用了网络访问,因此网络 URL 的请求将始终失败。在 Android Studio 预览中的行为由 LocalAsyncImagePreviewHandler 控制。

val previewHandler = AsyncImagePreviewHandler {
    ColorImage(Color.Red.toArgb())
}

CompositionLocalProvider(LocalAsyncImagePreviewHandler provides previewHandler) {
    AsyncImage(
        model = "https://example.com/image.jpg",
        contentDescription = null,
    )
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值