Commit f571d1e
authored
Make Image/AsyncImage stop using subcompose by default (#423)
* Make Image/AsyncImage stop using subcompose by default
Coil's documentation strongly recommends against using `SubcomposeAsyncImage` for performance reasons. https://coil-kt.github.io/coil/compose/
Here, we've replaced it with the most flexible version of Coil's non-subcompose API, `rememberAsyncImagePainter`.
But there is an important quirk in this API. SwiftUI `AsyncImage` has three `AsyncImagePhase` cases: `.success(Image)`, and `.failure(Error)`, and `.empty`, but there are four states of `AsyncImagePainter.State`: `Success`, `Failure`, `Loading` and `Empty`.
`Empty` is quite different from `Loading`. In the `Empty` state, which occurs on the first frame of rendering, Coil doesn't know yet whether the image will render immediately from the memory cache. In the subsequent frame, the state will change to either `Success` or `Loading`; it's up to the user to decide what to do in the `Empty` state.
Coil users have a few options for handling `Empty`.
1. We can optimistically render the image, hoping to get a cache hit.
2. We can pessimistically render the placeholder, waiting to render the image until we can be certain it's ready.
3. We can render the placeholder underneath the image, in a ZStack/Box. If the image renders (and if the image doesn't have transparency), the image will completely obscure the placeholder.
For `AsyncImage(url:scale:)` and `AsyncImage(url:scale:content:placeholder:)`, we've chosen option 3 for Coil's `Empty` case.
Users can choose their own option with `AsyncImage(url:scale:content:)`, which accepts an `AsyncImagePhase`. To permit users to distinguish Coil's `Loading` from `Empty`, we've added an argument to SwiftUI's `AsyncImagePhase.empty` enum case; it's now `.empty(Image?)`. This allows users to access the image in the `.empty` case with `let image: Image? = phase.image`. If the image is `nil`, then the image is `Loading`; users can render their placeholder. (In the `.empty` case, `phase.image` will always be `nil` in SwiftUI.) If the image is not `nil`, users can choose what to do with it, probably selecting one of the three options above.
Existing users of `AsyncImage(url:scale:content:)` can continue to handle `case .empty` without changing their code. In practice, that will function like the pessimistic option 2.
We've also introduced a new modifier, `.subcomposeAsyncImage()`, which sets an environment value, causing SkipUI to use `SubcomposeAsyncImage`, the old way.
* Fix Complex Layout ImagePlayground1 parent 46d9e5a commit f571d1e
5 files changed
Lines changed: 356 additions & 71 deletions
File tree
- Sources/SkipUI/SkipUI
- Components
- Environment
- View
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2912 | 2912 | | |
2913 | 2913 | | |
2914 | 2914 | | |
| 2915 | + | |
| 2916 | + | |
| 2917 | + | |
| 2918 | + | |
| 2919 | + | |
| 2920 | + | |
| 2921 | + | |
| 2922 | + | |
| 2923 | + | |
| 2924 | + | |
| 2925 | + | |
| 2926 | + | |
| 2927 | + | |
| 2928 | + | |
| 2929 | + | |
| 2930 | + | |
| 2931 | + | |
| 2932 | + | |
| 2933 | + | |
| 2934 | + | |
| 2935 | + | |
| 2936 | + | |
| 2937 | + | |
| 2938 | + | |
| 2939 | + | |
| 2940 | + | |
| 2941 | + | |
| 2942 | + | |
| 2943 | + | |
| 2944 | + | |
| 2945 | + | |
| 2946 | + | |
| 2947 | + | |
| 2948 | + | |
| 2949 | + | |
| 2950 | + | |
| 2951 | + | |
| 2952 | + | |
| 2953 | + | |
| 2954 | + | |
| 2955 | + | |
| 2956 | + | |
| 2957 | + | |
| 2958 | + | |
| 2959 | + | |
| 2960 | + | |
| 2961 | + | |
| 2962 | + | |
| 2963 | + | |
| 2964 | + | |
| 2965 | + | |
| 2966 | + | |
| 2967 | + | |
| 2968 | + | |
| 2969 | + | |
| 2970 | + | |
| 2971 | + | |
| 2972 | + | |
| 2973 | + | |
| 2974 | + | |
| 2975 | + | |
| 2976 | + | |
| 2977 | + | |
| 2978 | + | |
| 2979 | + | |
| 2980 | + | |
| 2981 | + | |
| 2982 | + | |
| 2983 | + | |
| 2984 | + | |
| 2985 | + | |
| 2986 | + | |
| 2987 | + | |
| 2988 | + | |
| 2989 | + | |
| 2990 | + | |
| 2991 | + | |
| 2992 | + | |
| 2993 | + | |
| 2994 | + | |
| 2995 | + | |
| 2996 | + | |
| 2997 | + | |
| 2998 | + | |
| 2999 | + | |
| 3000 | + | |
| 3001 | + | |
| 3002 | + | |
| 3003 | + | |
| 3004 | + | |
| 3005 | + | |
| 3006 | + | |
| 3007 | + | |
| 3008 | + | |
| 3009 | + | |
| 3010 | + | |
| 3011 | + | |
| 3012 | + | |
| 3013 | + | |
| 3014 | + | |
| 3015 | + | |
| 3016 | + | |
| 3017 | + | |
| 3018 | + | |
| 3019 | + | |
| 3020 | + | |
| 3021 | + | |
| 3022 | + | |
| 3023 | + | |
| 3024 | + | |
| 3025 | + | |
| 3026 | + | |
| 3027 | + | |
| 3028 | + | |
| 3029 | + | |
| 3030 | + | |
| 3031 | + | |
| 3032 | + | |
| 3033 | + | |
| 3034 | + | |
| 3035 | + | |
| 3036 | + | |
| 3037 | + | |
| 3038 | + | |
| 3039 | + | |
| 3040 | + | |
2915 | 3041 | | |
2916 | 3042 | | |
2917 | 3043 | | |
| |||
0 commit comments