使用compose绘制可以保存成Bitmap的写字板
前言
公司的项目使用了MVI
架构,V层使用compose进行UI绘制,本着探索与学习,闲暇时间写了个记事本的app,现需要一个写字板功能,遂记录,本文不涉及compose 重组机制介绍,和绘制原理,只记录功能。
功能拆分
-
写字板
根据手势检测移动路径,使用Canvas组件绘制路径
-
保存Compose中的UI成图片
暂时没有找到Compose 控件直接转换成的方法,转换思路1、使用Modifier.onGloballyPositioned()监听组件在全局的位置
2、使用Bitmap Canvas PixelCopy 等类,将指定区域的View 保存成Bitmap,如果是传统的View 可以通过drawToBitmap() 扩展函数操作
3、使用contentResolver插入到相册
手势检测
Compose 中的Modifier
提供pointerInput
扩展方法用来监测手势输入 由于pointerInput
传入的方法是挂起函数 并是PointerInputScope
的扩展函数,所以pointerInput
处理手势时,并不会阻塞当前线程 在PointerInputScope.awaitEachGesture()
方法中 ,我们可以通过传入一个函数实时等待手指输入,获取当前位置和手指事件
绘制Path
和传统xml布局相似,可以通过Canvas 绘制一些点、线、路径等
差别是,XML是Canvas类,而Compose提供了一个方法(声明式UI特性)
Canvas(modifier = Modifier.fillMaxSize()) {
val path = Path()
path.moveTo(0f, 0f)
path.lineTo(size.width / 2f, size.height / 2f)
path.lineTo(size.width, 0f)
path.close()
drawPath(path, Color.Magenta, style = Stroke(width = 10f))
}
Compose组件转换成bitmap
DisposableEffect(Unit) {
screenshotState.callback = {
runCatching {
composeView?.let {
if (it.width == 0f || it.height == 0f){
return@let
}
view.screenshot(it){
screenshotState.imageState.value = it
if (it is ImageResult.Success){
println("screenshot imageState Success")
screenshotState.bitmapState.value = it.data
}
}
}
}.onFailure {
screenshotState.imageState.value = ImageResult.Error(Exception(it.message))
}
}
onDispose {
println("screenshot onDispose ")
val bmp = screenshotState.bitmapState.value
bmp?.apply {
if (!isRecycled) {
recycle()
}
}
screenshotState.bitmapState.value = null
screenshotState.callback = null
}
}
//根据区域保存bitmap
fun View.screenshot(
bounds: Rect,
bitmapCallback: (ImageResult) -> Unit
) {
try {
val bitmap = Bitmap.createBitmap(
bounds.width.toInt(),
bounds.height.toInt(),
Bitmap.Config.ARGB_8888,
)
PixelCopy.request(
(this.context as Activity).window,
bounds.toAndroidRect(),
bitmap,
{
when (it) {
PixelCopy.SUCCESS -> {
bitmapCallback.invoke(ImageResult.Success(bitmap))
}
PixelCopy.ERROR_DESTINATION_INVALID -> {
}
PixelCopy.ERROR_SOURCE_INVALID -> {
bitmapCallback.invoke(
)
}
PixelCopy.ERROR_TIMEOUT -> {
bitmapCallback.invoke(
ImageResult.Error(
Exception(
"A timeout occurred while trying to acquire a buffer "
"from the source to copy from."
)
)
)
}
PixelCopy.ERROR_SOURCE_NO_DATA -> {
}
else -> {
bitmapCallback.invoke(
)
}
}
},
Handler(Looper.getMainLooper())
)
} catch (e: Exception) {
bitmapCallback.invoke(ImageResult.Error(e))
}
}
具体实现
@Composable
fun DrawTablet() {
// 记录每一次move的路线
var linepath by remember { mutableStateOf(Offset.Zero) }
// 记录path对象
val path by remember { mutableStateOf(Path()) }
val screenshotState = rememberScreenshotState()
val context = LocalContext.current
val scope = rememberCoroutineScope()
ScreenshotBox(screenshotState = screenshotState,
modifier = Modifier
.statusBarsPadding().
navigationBarsPadding()
.fillMaxSize()
.pointerInput(Unit) {
awaitEachGesture{
while (true) {
val event = awaitPointerEvent()
when (event.type) {
//按住时,更新起始点
Press -> {
path.moveTo(event.changes.first().position.x, event.changes.first().position.y)
}
//移动时,更新起始点 移动时,记录路径path
Move->{
linepath = event.changes.first().position
}
}
}
}
}){
Canvas(modifier = Modifier.fillMaxSize()) {
//重组新路线
path.lineTo(linepath.x, linepath.y)
drawPath( color = Color.Red,
path = path,
style = Stroke(width = 10F))
}
Row(modifier = Modifier.align(Alignment.BottomCenter)) {
Button(modifier = Modifier.weight(1f).padding(8.dp), onClick = {
linepath = Offset.Zero
path.reset()
}){
Text(text = "Clear")
}
Button(modifier = Modifier.weight(1f).padding(8.dp), onClick = {
scope.launch {
screenshotState.capture()
screenshotState.bitmap?.insertImageToImage(context)
}
}){
Text(text = "Screenshot")
}
}
}
}
参考资料
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhcffhjf
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01