[英]How can I achieve the below layout in jetpack compose?
This layout is made by me, the layout you are looking is a SVG image so I have just made the image to fill max size and added the above text and camera capture button below.此布局由我制作,您正在查看的布局是 SVG 图像,所以我刚刚制作了图像以填充最大尺寸,并在下面添加了上面的文本和相机捕捉按钮。 But now I want to remove the image background and want to make the same layout programmatically.
但现在我想删除图像背景并想以编程方式制作相同的布局。
Box(contentAlignment = Alignment.BottomCenter, modifier = Modifier.fillMaxSize()) {
AndroidView({ previewView }, modifier = Modifier.fillMaxSize())
Column(modifier = Modifier.fillMaxSize()) {
Icon(
painter = painterResource(id = R.drawable.ic_card_overlay),
contentDescription = null
)
Image(
modifier = Modifier.fillMaxSize(),
painter = painterResource(id = R.drawable.ic_black_transparent),
contentDescription = null,
contentScale = ContentScale.FillWidth
)
}
Column(
modifier = Modifier
.fillMaxSize()
.padding(26.dp)
) {
Row(
modifier = Modifier
.padding(bottom = 20.dp), verticalAlignment = Alignment.CenterVertically
) {
Icon(
modifier = Modifier.clickable {
onCloseCameraClick()
},
painter = painterResource(id = R.drawable.ic_baseline_arrow_back_ios_24),
contentDescription = null,
tint = Color.White
)
Text(
text = "Passport",
color = Color.White,
fontSize = 20.sp
)
}
Text(
text = "Place your passport inside the frame and take a\npicture.\nMake sure it is not cut or has any glare.",
color = Color.White,
fontSize = 12.sp
)
}
IconButton(
modifier = Modifier.padding(bottom = 20.dp),
onClick = {
Log.d("takePhoto", "ON CLICK")
takePhoto(
imageCapture = imageCapture,
outputDirectory = outputDirectory,
executor = executor,
onImageCaptured = onImageCaptured,
onError = onError
)
},
content = {
Icon(
painter = painterResource(id = R.drawable.ic_baseline_camera_24),
contentDescription = stringResource(R.string.take_picture),
tint = Color.White,
modifier = Modifier
.fillMaxSize(0.2f)
)
}
)
}
You can see I have used ic_card_overlay image which act like a background.你可以看到我使用了像背景一样的 ic_card_overlay 图像。 I want to achieve the same black transparent background with the box in the middle which will not include the black transparent color.
我想用中间的框实现相同的黑色透明背景,其中不包括黑色透明色。 Thank you.
谢谢你。
You can achieve this with using BlendMode.Clear您可以使用 BlendMode.Clear 来实现这一点
@Composable
fun TransparentClipLayout(
modifier: Modifier,
width: Dp,
height: Dp,
offsetY: Dp
) {
val offsetInPx: Float
val widthInPx: Float
val heightInPx: Float
with(LocalDensity.current) {
offsetInPx = offsetY.toPx()
widthInPx = width.toPx()
heightInPx = height.toPx()
}
Canvas(modifier = modifier) {
val canvasWidth = size.width
with(drawContext.canvas.nativeCanvas) {
val checkPoint = saveLayer(null, null)
// Destination
drawRect(Color(0x77000000))
// Source
drawRoundRect(
topLeft = Offset(
x = (canvasWidth - widthInPx) / 2,
y = offsetInPx
),
size = Size(widthInPx, heightInPx),
cornerRadius = CornerRadius(30f,30f),
color = Color.Transparent,
blendMode = BlendMode.Clear
)
restoreToCount(checkPoint)
}
}
}
You can customize corner radius size too.您也可以自定义角半径大小。 This is only for demonstration
这仅用于演示
Usage用法
Column {
Box(modifier = Modifier.fillMaxSize()) {
Image(
modifier =Modifier.fillMaxSize(),
painter = painterResource(id = R.drawable.landscape1),
contentDescription = null,
contentScale = ContentScale.Crop
)
TransparentClipLayout(
modifier = Modifier.fillMaxSize(),
width = 300.dp,
height = 200.dp,
offsetY = 150.dp
)
}
}
Result结果
You can archieve this background layout using a custom Shape
in combination with a Surface
.您可以将自定义
Shape
与Surface
结合使用来归档此背景布局。 With a custom implementation you can define what parts of the Surface
are displayed and which parts are "cut out".通过自定义实现,您可以定义
Surface
的哪些部分被显示以及哪些部分被“剪切”。
The cutoutPath
defines the part which are highlighted. cutoutPath
定义了突出显示的部分。 Here it is defined as a RoundRect
with a dynamically calculated position and size.在这里,它被定义为具有动态计算的 position 和大小的
RoundRect
。 Adjust the topLeft
and ``formulas as you need.根据需要调整
topLeft
和 ``公式。
Using Path.combine(...)
the outlinePath
is combined with the cutoutPath
.使用
Path.combine(...)
将outlinePath
与cutoutPath
相结合。 This is where the magic happens.这就是魔法发生的地方。
/**
* This is a shape with cuts out a rectangle in the center
*/
class CutOutShape : Shape {
override fun createOutline(
size: Size,
layoutDirection: LayoutDirection,
density: Density
): Outline {
val outlinePath = Path()
outlinePath.addRect(Rect(Offset(0f, 0f), size))
val cutoutHeight = size.height * 0.3f
val cutoutWidth = size.width * 0.75f
val center = Offset(size.width / 2f, size.height / 2f)
val cutoutPath = Path()
cutoutPath.addRoundRect(
RoundRect(
Rect(
topLeft = center - Offset(
cutoutWidth / 2f,
cutoutHeight / 2f
),
bottomRight = center + Offset(
cutoutWidth / 2f,
cutoutHeight / 2f
)
),
cornerRadius = CornerRadius(16f, 16f)
)
)
val finalPath = Path.combine(
PathOperation.Difference,
outlinePath,
cutoutPath
)
return Outline.Generic(finalPath)
}
}
The shape can be used like this:形状可以这样使用:
Surface(
shape = CutOutShape(),
color = Color.Black.copy(alpha = 0.45f)
) { }
This results in the following screen:这将导致以下屏幕:
Box {
AndroidView({ previewView }, modifier = Modifier.fillMaxSize())
Surface(
shape = CutOutShape(),
color = Color.Black.copy(alpha = 0.45f),
modifier = Modifier.fillMaxSize()
) { }
Column(
modifier = Modifier
.padding(top = 54.dp, start = 32.dp, end = 32.dp, bottom = 54.dp)
) {
Row(
Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
IconButton(onClick = { /*TODO*/ }) {
Icon(
imageVector = Icons.TwoTone.ArrowBack,
contentDescription = null,
tint = Color.White
)
}
Text(
"Passport",
color = Color.White,
fontSize = 20.sp
)
}
Text(
"Place your passport inside the frame and take a picture.\nMake sure it is not cut or has any glare.",
color = Color.White,
fontSize = 12.sp
)
Spacer(modifier = Modifier.weight(1f))
Icon(
imageVector = Icons.TwoTone.Camera,
contentDescription = null,
tint = Color.White,
modifier = Modifier
.size(48.dp)
.align(Alignment.CenterHorizontally)
)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.