英文:
How can I achieve a consistent design across multiple devices in Jetpack Compose
问题
我正在进行一个Jetpack Compose项目,并尝试根据Sketch应用程序设计实现完美的像素级设计。然而,当我在两台不同的设备上运行应用程序时,一个是Pixel 6 Pro,另一个是Infix Mobility设备,输出看起来完全不同。在Infix设备上,按钮溢出到另一个布局上。
以下是我的代码:
Column(
modifier = Modifier
.fillMaxSize()
.background(Blue)
) {
ConstraintLayout(
modifier = Modifier
.fillMaxSize()
.weight(1f)
.padding(30.dp)
) {
// ... (代码太长,省略部分)
}
Column(
modifier = Modifier
.fillMaxSize()
.weight(0.35f)
.padding(horizontal = 40.dp)
) {
CommonShadowButton(
text = stringResource(id = R.string.next), backgroundColor = Color.White
) {
}
}
}
有人能帮我理解为什么在不同设备上输出不同,以及如何在Jetpack Compose中实现跨多个设备的一致设计吗?
英文:
I am working on a Jetpack Compose project and trying to achieve a pixel-perfect design based on a Sketch app design. However, when I run the app on two different devices, a Pixel 6 Pro and an Infix Mobility device, the output looks completely different. On the Infix device, there are issues with buttons overflowing on another layout.
Here is my code
Column(
modifier = Modifier
.fillMaxSize()
.background(Blue)
) {
ConstraintLayout(
modifier = Modifier
.fillMaxSize()
.weight(1f)
.padding(30.dp)
) {
val (backImg, headerTextId, subHeaderTextId, profileImageId, txtAddProfilePicId, firstNameId, lastNameId, phoneNumberId, nextBtnId) = createRefs()
Image(painter = painterResource(id = R.drawable.img_back),
contentDescription = "Back",
modifier = Modifier
.clickable {}
.constrainAs(backImg) {
top.linkTo(parent.top)
start.linkTo(parent.start)
})
Column(modifier = Modifier.constrainAs(headerTextId) {
top.linkTo(backImg.bottom, margin = 10.dp)
start.linkTo(parent.start)
}) {
CommonHeaderText(
text = stringResource(id = R.string.complete_profile), textSize = 26.sp
)
}
Column(modifier = Modifier.constrainAs(subHeaderTextId) {
top.linkTo(headerTextId.bottom)
start.linkTo(parent.start)
}) {
CommonSubHeaderText(stringResource(id = R.string.complete_profile_desc))
}
AsyncImage(model = ImageRequest.Builder(LocalContext.current).data(
R.drawable.camera_round
).crossfade(true).build(),
contentDescription = "Profile Image",
placeholder = painterResource(id = R.drawable.camera_round),
modifier = Modifier
.constrainAs(profileImageId) {
top.linkTo(subHeaderTextId.bottom, margin = 15.dp)
start.linkTo(parent.start)
}
.clip(CircleShape)
.size(100.dp)
.clickable {},
contentScale = ContentScale.Crop
)
Text(
stringResource(id = R.string.add_profile_pic),
modifier = Modifier
.padding(vertical = 5.dp)
.constrainAs(txtAddProfilePicId) {
top.linkTo(profileImageId.top)
bottom.linkTo(profileImageId.bottom)
start.linkTo(profileImageId.end, margin = 15.dp)
},
fontSize = 16.sp,
color = Color.White,
fontFamily = avenirFamily,
fontWeight = FontWeight.Bold
)
OutlinedTextField(keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Words, imeAction = ImeAction.Next
),
shape = RoundedCornerShape(7.dp),
isError = false,
value = "",
onValueChange = {},
placeholder = {
EditTextPlaceHolder(
stringResource(id = R.string.first_name), TextGreenColor
)
},
modifier = Modifier
.constrainAs(firstNameId) {
top.linkTo(profileImageId.bottom, margin = 30.dp)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
.fillMaxWidth()
.clip(shape = RoundedCornerShape(7.dp)),
colors = TextFieldDefaults.textFieldColors(
errorIndicatorColor = Red,
backgroundColor = Color.White,
cursorColor = ScreenBackgroundColor,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
focusedLabelColor = Color.Transparent
),
singleLine = true,
textStyle = TextStyle(
fontSize = 16.sp,
color = Color.Black.copy(alpha = 0.7f),
fontFamily = avenirFamily,
fontWeight = FontWeight.Medium
))
OutlinedTextField(keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Words, imeAction = ImeAction.Next
),
isError = false,
shape = RoundedCornerShape(7.dp),
value = "",
onValueChange = {},
placeholder = {
EditTextPlaceHolder(stringResource(id = R.string.last_name), TextGreenColor)
},
modifier = Modifier
.constrainAs(lastNameId) {
top.linkTo(firstNameId.bottom, margin = 20.dp)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
.fillMaxWidth()
.clip(shape = RoundedCornerShape(7.dp)),
colors = TextFieldDefaults.textFieldColors(
errorIndicatorColor = Red,
backgroundColor = Color.White,
cursorColor = ScreenBackgroundColor,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
focusedLabelColor = Color.Transparent
),
singleLine = true,
textStyle = TextStyle(
fontSize = 16.sp,
color = Color.Black.copy(alpha = 0.7f),
fontFamily = avenirFamily,
fontWeight = FontWeight.Medium
))
Column(modifier = Modifier
.constrainAs(phoneNumberId) {
top.linkTo(lastNameId.bottom, margin = 20.dp)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
.clip(shape = RoundedCornerShape(7.dp))
.background(Color.White)) {
MaterialCountryCodePicker(
pickedCountry = {
},
showErrorText = false,
showCountryCodeInDIalog = true,
showDropDownAfterFlag = false,
textFieldShapeCornerRadiusInPercentage = 10,
searchFieldShapeCornerRadiusInPercentage = 20,
countryItemBgShape = RoundedCornerShape(12.dp),
focusedBorderColor = Color.Transparent,
unfocusedBorderColor = Color.Transparent,
cursorColor = ScreenBackgroundColor,
showCountryFlag = false,
showCountryCode = true,
countrytextstyle = TextStyle(
fontSize = 16.sp,
color = Color.Black,
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
countrycodetextstyle = TextStyle(
fontSize = 16.sp,
color = Color.Black,
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
phonenumbertextstyle = TextStyle(
fontSize = 16.sp,
color = Color.Black,
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
phonehintnumbertextstyle = TextStyle(
fontSize = 16.sp,
color = TextGreenColor,
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
searchFieldTextStyle = TextStyle(
fontSize = 16.sp,
color = Color.Black,
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
dialogcountrycodetextstyle = TextStyle(
fontSize = 16.sp,
color = Color.Black,
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
searchFieldPlaceHolderTextStyle = TextStyle(
fontSize = 16.sp,
color = Color.Black.copy(alpha = 0.5f),
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
appbartitleStyle = TextStyle(
fontSize = 18.sp,
color = Color.Black,
fontFamily = poppinsFamily,
fontWeight = FontWeight.SemiBold
),
defaultCountry = CountryData("+91"),
onValueChange = {
},
text = ""
)
}
}
Column(
modifier = Modifier
.fillMaxSize()
.weight(0.35f)
.padding(horizontal = 40.dp)
) {
CommonShadowButton(
text = stringResource(id = R.string.next), backgroundColor = Color.White
) {
}
}
}
Can anyone help me understand why the output is different on different devices and how to achieve a consistent design across multiple devices in Jetpack Compose?"
EDIT 1 :
I am using weight because I have one button which will be placed on fix position on every screen. If i'm using it directly then button will be not placed on same place in every screen that's why i'm using weight.
Let me share you output i want for different screen
That's why I'm using column weight and placed this function on every screen.
Column(
modifier = Modifier
.fillMaxSize()
.weight(0.35f)
.padding(horizontal = 40.dp)
) {
CommonShadowButton(
text = stringResource(id = R.string.next), backgroundColor = Color.White
) {
}
}
答案1
得分: 2
以下是代码部分的翻译:
Box(
modifier = Modifier
.fillMaxSize()
.background(Blue)
) {
ConstraintLayout(
modifier = Modifier
.padding(30.dp)
.verticalScroll(rememberScrollState())
) {
val (backImg, headerTextId, subHeaderTextId, profileImageId, txtAddProfilePicId, firstNameId, lastNameId, phoneNumberId, nextBtnId) = createRefs()
Image(
painter = painterResource(id = R.drawable.img_back),
contentDescription = "Back",
modifier = Modifier
.clickable {}
.constrainAs(backImg) {
top.linkTo(parent.top)
start.linkTo(parent.start)
}
)
Column(modifier = Modifier.constrainAs(headerTextId) {
top.linkTo(backImg.bottom, margin = 10.dp)
start.linkTo(parent.start)
}) {
CommonHeaderText(
text = stringResource(id = R.string.complete_profile), textSize = 26.sp
)
}
Column(modifier = Modifier.constrainAs(subHeaderTextId) {
top.linkTo(headerTextId.bottom)
start.linkTo(parent.start)
}) {
CommonSubHeaderText(stringResource(id = R.string.complete_profile_desc))
}
AsyncImage(
model = ImageRequest.Builder(LocalContext.current).data(
R.drawable.camera_round
).crossfade(true).build(),
contentDescription = "Profile Image",
placeholder = painterResource(id = R.drawable.camera_round),
modifier = Modifier
.constrainAs(profileImageId) {
top.linkTo(subHeaderTextId.bottom, margin = 15.dp)
start.linkTo(parent.start)
}
.clip(CircleShape)
.size(100.dp)
.clickable {},
contentScale = ContentScale.Crop
)
Text(
stringResource(id = R.string.add_profile_pic),
modifier = Modifier
.padding(vertical = 5.dp)
.constrainAs(txtAddProfilePicId) {
top.linkTo(profileImageId.top)
bottom.linkTo(profileImageId.bottom)
start.linkTo(profileImageId.end, margin = 15.dp)
},
fontSize = 16.sp,
color = Color.White,
fontFamily = avenirFamily,
fontWeight = FontWeight.Bold
)
OutlinedTextField(keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Words, imeAction = ImeAction.Next
),
shape = RoundedCornerShape(7.dp),
isError = false,
value = "",
onValueChange = {},
placeholder = {
EditTextPlaceHolder(
stringResource(id = R.string.first_name), TextGreenColor
)
},
modifier = Modifier
.constrainAs(firstNameId) {
top.linkTo(profileImageId.bottom, margin = 30.dp)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
.fillMaxWidth()
.clip(shape = RoundedCornerShape(7.dp)),
colors = TextFieldDefaults.textFieldColors(
errorIndicatorColor = Red,
backgroundColor = Color.White,
cursorColor = ScreenBackgroundColor,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
focusedLabelColor = Color.Transparent
),
singleLine = true,
textStyle = TextStyle(
fontSize = 16.sp,
color = Color.Black.copy(alpha = 0.7f),
fontFamily = avenirFamily,
fontWeight = FontWeight.Medium
)
)
OutlinedTextField(keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Words, imeAction = ImeAction.Next
),
isError = false,
shape = RoundedCornerShape(7.dp),
value = "",
onValueChange = {},
placeholder = {
EditTextPlaceHolder(stringResource(id = R.string.last_name), TextGreenColor)
},
modifier = Modifier
.constrainAs(lastNameId) {
top.linkTo(firstNameId.bottom, margin = 20.dp)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
.fillMaxWidth()
.clip(shape = RoundedCornerShape(7.dp)),
colors = TextFieldDefaults.textFieldColors(
errorIndicatorColor = Red,
backgroundColor = Color White,
cursorColor = ScreenBackgroundColor,
focusedIndicatorColor = Color Transparent,
unfocusedIndicatorColor = Color Transparent,
focusedLabelColor = Color Transparent
),
singleLine = true,
textStyle = TextStyle(
fontSize = 16.sp,
color = Color.Black.copy(alpha = 0.7f),
fontFamily = avenirFamily,
fontWeight = FontWeight.Medium
)
)
Column(modifier = Modifier
.constrainAs(phoneNumberId) {
top.linkTo(lastNameId.bottom, margin = 20.dp)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
.clip(shape = RoundedCornerShape(7.dp))
.background(Color.White)) {
MaterialCountryCodePicker(
pickedCountry = {},
showErrorText = false,
showCountryCodeInDIalog = true,
showDropDownAfterFlag = false,
textFieldShapeCornerRadiusInPercentage = 10,
searchFieldShapeCornerRadiusInPercentage = 20,
countryItemBgShape = RoundedCornerShape(12.dp),
focusedBorderColor = Color Transparent,
unfocusedBorderColor = Color Transparent,
cursorColor = ScreenBackgroundColor,
showCountryFlag = false,
showCountryCode = true,
countrytextstyle = TextStyle(
fontSize = 16.sp,
color = Color Black,
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
countrycodetextstyle = TextStyle(
fontSize = 16.sp,
color = Color Black,
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
phonenumbertextstyle = TextStyle(
fontSize = 16.sp,
color = Color Black,
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
phonehintnumbertextstyle = TextStyle(
fontSize = 16.sp,
color = TextGreenColor,
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
searchFieldTextStyle = TextStyle(
fontSize = 16.sp,
color = Color Black,
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
dialogcountrycodetextstyle = TextStyle(
fontSize = 16.sp,
color = Color Black,
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
searchFieldPlaceHolderTextStyle = TextStyle(
fontSize = 16.sp,
color = Color Black.copy(alpha = 0.5f),
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
appbartitleStyle = TextStyle(
fontSize = 18.sp,
color = Color Black,
fontFamily = poppinsFamily,
fontWeight = FontWeight.SemiBold
),
defaultCountry = CountryData("+91"),
onValueChange = {},
text = ""
)
}
}
Column(
modifier = Modifier
.fillMaxWidth()
.padding(20)
.align(Alignment.BottomCenter)
<details>
<summary>英文:</summary>
Paste the below code and try it .. actually what i did here , removed the weight property and added space between in column property.
Box(
modifier = Modifier
.fillMaxSize()
.background(Blue)
) {
ConstraintLayout(
modifier = Modifier
.padding(30.dp)
.verticalScroll(rememberScrollState())
) {
val (backImg, headerTextId, subHeaderTextId, profileImageId, txtAddProfilePicId, firstNameId, lastNameId, phoneNumberId, nextBtnId) = createRefs()
Image(painter = painterResource(id = R.drawable.img_back),
contentDescription = "Back",
modifier = Modifier
.clickable {}
.constrainAs(backImg) {
top.linkTo(parent.top)
start.linkTo(parent.start)
})
Column(modifier = Modifier.constrainAs(headerTextId) {
top.linkTo(backImg.bottom, margin = 10.dp)
start.linkTo(parent.start)
}) {
CommonHeaderText(
text = stringResource(id = R.string.complete_profile), textSize = 26.sp
)
}
Column(modifier = Modifier.constrainAs(subHeaderTextId) {
top.linkTo(headerTextId.bottom)
start.linkTo(parent.start)
}) {
CommonSubHeaderText(stringResource(id = R.string.complete_profile_desc))
}
AsyncImage(model = ImageRequest.Builder(LocalContext.current).data(
R.drawable.camera_round
).crossfade(true).build(),
contentDescription = "Profile Image",
placeholder = painterResource(id = R.drawable.camera_round),
modifier = Modifier
.constrainAs(profileImageId) {
top.linkTo(subHeaderTextId.bottom, margin = 15.dp)
start.linkTo(parent.start)
}
.clip(CircleShape)
.size(100.dp)
.clickable {},
contentScale = ContentScale.Crop
)
Text(
stringResource(id = R.string.add_profile_pic),
modifier = Modifier
.padding(vertical = 5.dp)
.constrainAs(txtAddProfilePicId) {
top.linkTo(profileImageId.top)
bottom.linkTo(profileImageId.bottom)
start.linkTo(profileImageId.end, margin = 15.dp)
},
fontSize = 16.sp,
color = Color.White,
fontFamily = avenirFamily,
fontWeight = FontWeight.Bold
)
OutlinedTextField(keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Words, imeAction = ImeAction.Next
),
shape = RoundedCornerShape(7.dp),
isError = false,
value = "",
onValueChange = {},
placeholder = {
EditTextPlaceHolder(
stringResource(id = R.string.first_name), TextGreenColor
)
},
modifier = Modifier
.constrainAs(firstNameId) {
top.linkTo(profileImageId.bottom, margin = 30.dp)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
.fillMaxWidth()
.clip(shape = RoundedCornerShape(7.dp)),
colors = TextFieldDefaults.textFieldColors(
errorIndicatorColor = Red,
backgroundColor = Color.White,
cursorColor = ScreenBackgroundColor,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
focusedLabelColor = Color.Transparent
),
singleLine = true,
textStyle = TextStyle(
fontSize = 16.sp,
color = Color.Black.copy(alpha = 0.7f),
fontFamily = avenirFamily,
fontWeight = FontWeight.Medium
))
OutlinedTextField(keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Words, imeAction = ImeAction.Next
),
isError = false,
shape = RoundedCornerShape(7.dp),
value = "",
onValueChange = {},
placeholder = {
EditTextPlaceHolder(stringResource(id = R.string.last_name), TextGreenColor)
},
modifier = Modifier
.constrainAs(lastNameId) {
top.linkTo(firstNameId.bottom, margin = 20.dp)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
.fillMaxWidth()
.clip(shape = RoundedCornerShape(7.dp)),
colors = TextFieldDefaults.textFieldColors(
errorIndicatorColor = Red,
backgroundColor = Color.White,
cursorColor = ScreenBackgroundColor,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
focusedLabelColor = Color.Transparent
),
singleLine = true,
textStyle = TextStyle(
fontSize = 16.sp,
color = Color.Black.copy(alpha = 0.7f),
fontFamily = avenirFamily,
fontWeight = FontWeight.Medium
))
Column(modifier = Modifier
.constrainAs(phoneNumberId) {
top.linkTo(lastNameId.bottom, margin = 20.dp)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
.clip(shape = RoundedCornerShape(7.dp))
.background(Color.White)) {
MaterialCountryCodePicker(
pickedCountry = {
},
showErrorText = false,
showCountryCodeInDIalog = true,
showDropDownAfterFlag = false,
textFieldShapeCornerRadiusInPercentage = 10,
searchFieldShapeCornerRadiusInPercentage = 20,
countryItemBgShape = RoundedCornerShape(12.dp),
focusedBorderColor = Color.Transparent,
unfocusedBorderColor = Color.Transparent,
cursorColor = ScreenBackgroundColor,
showCountryFlag = false,
showCountryCode = true,
countrytextstyle = TextStyle(
fontSize = 16.sp,
color = Color.Black,
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
countrycodetextstyle = TextStyle(
fontSize = 16.sp,
color = Color.Black,
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
phonenumbertextstyle = TextStyle(
fontSize = 16.sp,
color = Color.Black,
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
phonehintnumbertextstyle = TextStyle(
fontSize = 16.sp,
color = TextGreenColor,
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
searchFieldTextStyle = TextStyle(
fontSize = 16.sp,
color = Color.Black,
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
dialogcountrycodetextstyle = TextStyle(
fontSize = 16.sp,
color = Color.Black,
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
searchFieldPlaceHolderTextStyle = TextStyle(
fontSize = 16.sp,
color = Color.Black.copy(alpha = 0.5f),
fontFamily = poppinsFamily,
fontWeight = FontWeight.Medium
),
appbartitleStyle = TextStyle(
fontSize = 18.sp,
color = Color.Black,
fontFamily = poppinsFamily,
fontWeight = FontWeight.SemiBold
),
defaultCountry = CountryData("+91"),
onValueChange = {
},
text = ""
)
}
}
Column(
modifier = Modifier
.fillMaxWidth()
.padding(20)
.align(Alignment.BottomCenter)
) {
CommonShadowButton(
text = stringResource(id = R.string.next), backgroundColor = Color.White
) {
}
}
}
**Note :-**. you have to work on your code quality. if the things are repeating make it common and also use column, row and box when your layout are not complex. Constraints layout is for complex layout.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论