
Image viewer library with intuitive gesture effects, large image support, customizable components, and transition animations. Offers image list browsing, pop-up previews, and operates independently of third-party libraries.
🖼 An image viewer for jetpack compose multiplatform.
一款基于Jetpack Compose Multiplatform开发的图片浏览库,支持过渡变换和超大图片的显示
| 兼容性 | Android | IOS | Desktop | JS/WasmJS |
|---|---|---|---|---|
| scale-zoomable-view | ✅ | ✅ | ✅ | ⛔️ |
| scale-image-viewer | ✅ | ✅ | ✅ | ⛔️ |
| scale-sampling-decoder | ✅ | ✅ | ✅ | ⛔️ |
| scale-image-viewer-classic | ⛔️ |
💽 接口文档 👉 API REFERENCE
👋 示例代码请参考:
Android 👉 SAMPLE-ANDROID
IOS 👉 SAMPLE-IOS
Scale is available on mavenCentral()
// 使用MavenCentral仓库
repositories {
mavenCentral()
}
val version = "1.1.1-beta.3"
// 图片浏览库
implementation("com.jvziyaoyao.scale:image-viewer:$version")
// 大型图片支持(可选)
implementation("com.jvziyaoyao.scale:sampling-decoder:$version")val painter = painterResource(id = R.drawable.light_02)
val state = rememberZoomableState(contentSize = painter.intrinsicSize)
ZoomableView(state = state) {
Image(
modifier = Modifier.fillMaxSize(), // 这里请务必要充满整个图层
painter = painter,
contentDescription = null,
)
}val scope = rememberCoroutineScope()
val state = rememberZoomableState()
ImageViewer(
state = state,
model = painterResource(id = R.drawable.light_02),
modifier = Modifier.fillMaxSize(),
detectGesture = ZoomableGestureScope(onDoubleTap = {
// 双击放大缩小
scope.launch {
state.toggleScale(it)
}
})
)添加SamplingDecoder依赖支持:
implementation("com.jvziyaoyao.scale:sampling-decoder:$version")‼ 仅在model类型为SamplingDecoder才会被当做大图进行加载
val bytes = remember { mutableStateOf<ByteArray?>(null) }
LaunchedEffect(Unit) { bytes.value = Res.readBytes("files/a350.jpg") }
val (samplingDecoder) = rememberSamplingDecoder(bytes.value)
if (samplingDecoder != null) {
val state = rememberZoomableState(
contentSize = samplingDecoder.intrinsicSize
)
ImageViewer(
model = samplingDecoder,
state = state,
processor = ModelProcessor(samplingProcessorPair),
)
}val images = remember {
mutableStateListOf(
R.drawable.light_01,
R.drawable.light_02,
)
}
ImagePager(
modifier = Modifier.fillMaxSize(),
pagerState = rememberZoomablePagerState { images.size },
imageLoader = { index ->
val painter = painterResource(images[index])
return@ImagePager Pair(painter, painter.intrinsicSize)
},
)val images = remember {
listOf(
R.drawable.img_01,
R.drawable.img_02,
)
}
val previewerState = rememberPreviewerState(pageCount = { images.size })
val scope = rememberCoroutineScope()
ImagePreviewer(
state = previewerState,
detectGesture = PagerGestureScope(onTap = {
scope.launch {
// 关闭预览组件
previewerState.close()
}
}),
imageLoader = { index ->
val painter = painterResource(id = images[index])
Pair(painter, painter.intrinsicSize)
}
)
// 显示预览组件
previewerState.open()val images = remember {
listOf(
// 依次声明图片的key、缩略图、原图(实际情况按实际情况来,这里只是示例)
Triple("001", R.drawable.thumb_01, R.drawable.img_01),
Triple("002", R.drawable.thumb_02, R.drawable.img_02),
)
}
// 为组件提供获取数据长度和获取key的方法
val previewerState = rememberPreviewerState(
pageCount = { images.size },
getKey = { images[it].first }
)
// 显示缩略图小图的示例代码
val index = 1
val scope = rememberCoroutineScope()
TransformImageView(
modifier = Modifier
.size(120.dp)
.clickable {
scope.launch {
// 点击事件触发动效
previewerState.enterTransform(index)
}
},
imageLoader = {
val key = images[index].first
val imageDrawableId = images[index].second
val painter = painterResource(id = imageDrawableId) // 这里使用的是缩略图
// 必须依次返回key、图片数据、图片的尺寸
Triple(key, painter, painter.intrinsicSize)
},
transformState = previewerState,
)
// 这里声明图片预览组件
ImagePreviewer(
state = previewerState,
detectGesture = PagerGestureScope(onTap = {
scope.launch {
// 点击界面后关闭组件
previewerState.exitTransform()
}
}),
imageLoader = {
val painter = painterResource(id = images[it].third) // 这里使用的是原图
// 这里必须依次返回图片数据、图片的尺寸
return@ImagePreviewer Pair(painter, painter.intrinsicSize)
}
)Copyright 2022 jvziyaoyao
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
🖼 An image viewer for jetpack compose multiplatform.
一款基于Jetpack Compose Multiplatform开发的图片浏览库,支持过渡变换和超大图片的显示
| 兼容性 | Android | IOS | Desktop | JS/WasmJS |
|---|---|---|---|---|
| scale-zoomable-view | ✅ | ✅ | ✅ | ⛔️ |
| scale-image-viewer | ✅ | ✅ | ✅ | ⛔️ |
| scale-sampling-decoder | ✅ | ✅ | ✅ | ⛔️ |
| scale-image-viewer-classic | ⛔️ |
💽 接口文档 👉 API REFERENCE
👋 示例代码请参考:
Android 👉 SAMPLE-ANDROID
IOS 👉 SAMPLE-IOS
Scale is available on mavenCentral()
// 使用MavenCentral仓库
repositories {
mavenCentral()
}
val version = "1.1.1-beta.3"
// 图片浏览库
implementation("com.jvziyaoyao.scale:image-viewer:$version")
// 大型图片支持(可选)
implementation("com.jvziyaoyao.scale:sampling-decoder:$version")val painter = painterResource(id = R.drawable.light_02)
val state = rememberZoomableState(contentSize = painter.intrinsicSize)
ZoomableView(state = state) {
Image(
modifier = Modifier.fillMaxSize(), // 这里请务必要充满整个图层
painter = painter,
contentDescription = null,
)
}val scope = rememberCoroutineScope()
val state = rememberZoomableState()
ImageViewer(
state = state,
model = painterResource(id = R.drawable.light_02),
modifier = Modifier.fillMaxSize(),
detectGesture = ZoomableGestureScope(onDoubleTap = {
// 双击放大缩小
scope.launch {
state.toggleScale(it)
}
})
)添加SamplingDecoder依赖支持:
implementation("com.jvziyaoyao.scale:sampling-decoder:$version")‼ 仅在model类型为SamplingDecoder才会被当做大图进行加载
val bytes = remember { mutableStateOf<ByteArray?>(null) }
LaunchedEffect(Unit) { bytes.value = Res.readBytes("files/a350.jpg") }
val (samplingDecoder) = rememberSamplingDecoder(bytes.value)
if (samplingDecoder != null) {
val state = rememberZoomableState(
contentSize = samplingDecoder.intrinsicSize
)
ImageViewer(
model = samplingDecoder,
state = state,
processor = ModelProcessor(samplingProcessorPair),
)
}val images = remember {
mutableStateListOf(
R.drawable.light_01,
R.drawable.light_02,
)
}
ImagePager(
modifier = Modifier.fillMaxSize(),
pagerState = rememberZoomablePagerState { images.size },
imageLoader = { index ->
val painter = painterResource(images[index])
return@ImagePager Pair(painter, painter.intrinsicSize)
},
)val images = remember {
listOf(
R.drawable.img_01,
R.drawable.img_02,
)
}
val previewerState = rememberPreviewerState(pageCount = { images.size })
val scope = rememberCoroutineScope()
ImagePreviewer(
state = previewerState,
detectGesture = PagerGestureScope(onTap = {
scope.launch {
// 关闭预览组件
previewerState.close()
}
}),
imageLoader = { index ->
val painter = painterResource(id = images[index])
Pair(painter, painter.intrinsicSize)
}
)
// 显示预览组件
previewerState.open()val images = remember {
listOf(
// 依次声明图片的key、缩略图、原图(实际情况按实际情况来,这里只是示例)
Triple("001", R.drawable.thumb_01, R.drawable.img_01),
Triple("002", R.drawable.thumb_02, R.drawable.img_02),
)
}
// 为组件提供获取数据长度和获取key的方法
val previewerState = rememberPreviewerState(
pageCount = { images.size },
getKey = { images[it].first }
)
// 显示缩略图小图的示例代码
val index = 1
val scope = rememberCoroutineScope()
TransformImageView(
modifier = Modifier
.size(120.dp)
.clickable {
scope.launch {
// 点击事件触发动效
previewerState.enterTransform(index)
}
},
imageLoader = {
val key = images[index].first
val imageDrawableId = images[index].second
val painter = painterResource(id = imageDrawableId) // 这里使用的是缩略图
// 必须依次返回key、图片数据、图片的尺寸
Triple(key, painter, painter.intrinsicSize)
},
transformState = previewerState,
)
// 这里声明图片预览组件
ImagePreviewer(
state = previewerState,
detectGesture = PagerGestureScope(onTap = {
scope.launch {
// 点击界面后关闭组件
previewerState.exitTransform()
}
}),
imageLoader = {
val painter = painterResource(id = images[it].third) // 这里使用的是原图
// 这里必须依次返回图片数据、图片的尺寸
return@ImagePreviewer Pair(painter, painter.intrinsicSize)
}
)Copyright 2022 jvziyaoyao
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.