CameraX перекомпоновывает композицию и вызывает сбои на экране при обновлении текстаAndroid

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Anonymous
 CameraX перекомпоновывает композицию и вызывает сбои на экране при обновлении текста

Сообщение Anonymous »

У меня есть экран камеры в Jetpack Compose. У него есть еще один ImageView(

Код: Выделить всё

SubcomposeAsyncImage
), который обновляется с учетом количества изображений, когда я делаю снимок.
Проблема:
  • Предварительный просмотр камеры не открывается полностью (прежде чем щелкнуть изображение, посмотрите на нижнюю черную часть. Когда я нажимаю на изображение, оно открывается в полноэкранном режиме.
  • Каждый раз, когда обновляется SubcomposeAsyncImage , предварительный просмотр камеры меняет композицию и
    дает сбой на экране.
Вот код:
CameraScreen:

Код: Выделить всё

@Composable
fun CamScreen(
navController: NavController, viewModel: CamViewModel = hiltViewModel()
) {

CameraContent(
onTakePhoto = viewModel::onTakePhoto,
stackUrl = viewModel.state.value.stackUrl,
stackCount = viewModel.state.value.stackCount ?: 0
)
}

@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun CameraContent(
onTakePhoto: (File) -> Unit,
stackUrl: String,
stackCount: Int
) {
// Camera permission state
val cameraPermissionState = rememberPermissionState(
android.Manifest.permission.CAMERA
)

if (cameraPermissionState.status.isGranted) {
CameraScreenPreview(
onPhotoSaved = onTakePhoto,
stackUrl = stackUrl,
stackCount = stackCount
)
} else {
CameraPermission(cameraPermissionState)
}
}

@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun CameraPermission(cameraPermissionState: PermissionState) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
.background(Color.White),
verticalArrangement = Arrangement.Center
) {
val textToShow = if (cameraPermissionState.status.shouldShowRationale) {
// If the user has denied the permission but the rationale can be shown,
// then gently explain why the app requires this permission
stringResource(id = R.string.camera_permission_rationale)
} else {
// If it's the first time the user lands on this feature, or the user
// doesn't want to be asked again for this permission, explain that the
// permission is required
stringResource(id = R.string.camera_permission_required)
}
Text(textToShow, color = Black)
Button(
onClick = { cameraPermissionState.launchPermissionRequest() },
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(top = 16.dp)
) {
Text("Request permission")
}
}
}

@Composable
fun CameraScreenPreview(
onPhotoSaved: (File) ->  Unit,
stackUrl: String,
stackCount: Int
) {
val haptic = LocalHapticFeedback.current
val context = LocalContext.current
val controller = remember {
LifecycleCameraController(context).apply {
setEnabledUseCases(
CameraController.IMAGE_CAPTURE
)
}
}

Scaffold { padding ->
Box(
modifier = Modifier
.fillMaxSize()
.padding(padding)
) {
CameraPreview(controller)

if (stackUrl.isNotEmpty()) {
Stack(
url = stackUrl,
stackCount = stackCount,
modifier = Modifier
.padding(start = 16.dp, bottom = 16.dp)
.align(Alignment.BottomStart)
)
}

Row(
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter),
horizontalArrangement = Arrangement.SpaceAround
) {
IconButton(onClick = {
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
takePhoto(controller, context, onPhotoSaved) {}
}, modifier = Modifier.size(80.dp)) {
Icon(
painter = painterResource(id = R.drawable.camera),
contentDescription = stringResource(R.string.take_photo),
tint = Color.Unspecified
)
}
}
}
}
}

@Composable
fun CameraPreview(
controller: LifecycleCameraController
) {
val lifecycleOwner = LocalLifecycleOwner.current
AndroidView(
factory = {
PreviewView(it).apply {
this.controller = controller
controller.bindToLifecycle(lifecycleOwner)
}
}, modifier = Modifier.fillMaxSize()
)
}

private fun takePhoto(
controller: LifecycleCameraController,
context: Context,
onPhotoSaved: (File) -> Unit,
onError: (ImageCaptureException) ->  Unit
) {
val outputDirectory = AppUtils.getOutputDirectory(activityContext = context as Activity)
val photoFile = File(
outputDirectory, "s_receipt_${System.currentTimeMillis()}.jpg"
)

val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()

controller.takePicture(outputOptions,
ContextCompat.getMainExecutor(context),
object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
onPhotoSaved(photoFile)
}

override fun onError(exception: ImageCaptureException) {
onError(exception)
Timber.tag("Camera").e("Photo capture failed: ${exception.message}", exception)
}
})
}

@Composable
fun Stack(url: String, modifier: Modifier = Modifier, stackCount: Int) {
Box(
modifier = modifier.size(50.dp)
) {
if (url.isNotEmpty()) {
StackItem(url)
}
Box(
modifier = Modifier
.background(
shape = RoundedCornerShape(12.dp), color = LightBlue
)
.padding(
start = 8.dp, end = 8.dp, top = 2.dp, bottom = 2.dp
)
.align(Alignment.BottomEnd)
) {
Text(
text = stackCount.toString(),
fontSize = 12.sp,
lineHeight = 16.sp,
fontWeight = FontWeight(600),
color = Color.White,
)
}
}
}

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun StackItem(url: String, degree: Float = 0f) {
val context = LocalContext.current
val uri = Uri.parse(url)
val contentResolver = context.contentResolver
Card(
modifier = Modifier
.rotate(degree)
.size(45.dp),
elevation = CardDefaults.cardElevation(
defaultElevation = 2.dp
),
) {
if (contentResolver.getType(uri)?.contains("pdf") == true || url.contains("pdf")) {
val pdfState = rememberVerticalPdfReaderState(
resource = ResourceType.Local(Uri.parse(url)), isZoomEnable = false
)
VerticalPDFReader(state = pdfState,
modifier = Modifier
.size(45.dp)
.background(color = Color.Gray)
.pointerInteropFilter {
when (it.action) {
MotionEvent.ACTION_UP -> {

}

else -> {}
}
true
}

)
} else {
SubcomposeAsyncImage(
model = url,
contentDescription = "receipt",
contentScale = ContentScale.FillWidth,
modifier = Modifier
.size(45.dp)
.clip(RoundedCornerShape(5.dp))
.clickable {

},
loading = {
CircularProgressIndicator(
color = Navy, modifier = Modifier.background(Transparent)
)
},
)
}
}
}
ViewModel:

Код: Выделить всё

@HiltViewModel
open class CamViewModel @Inject constructor(
) : ViewModel() {

private val _state = mutableStateOf(CamState())
val state: State = _state

private val _docs = MutableStateFlow(immutableListOf())
val docs = _docs.asStateFlow()

fun onTakePhoto(file: File) {
val newDocs = ArrayList(docs.value)
newDocs.add(file.path)
_docs.value = newDocs
_state.value = state.value.copy(stackUrl = file.path, stackCount = newDocs.size)
}
}
библиотека камеры:

Код: Выделить всё

cameraxVersion = "1.3.4"
implementation(libs.androidx.camera.core)
implementation(libs.androidx.camera.camera2)
implementation(libs.androidx.camera.view)
implementation(libs.androidx.camera.lifecycle)
Запись экрана проблемы: https://imgur.com/a/UBjtlhC

Подробнее здесь: https://stackoverflow.com/questions/788 ... is-updated
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Android»