Reputation: 593
I searched on Google multiple ways to support multiple screen sizes on Android with Jetpack compose and I finally found the Google documentation: https://developer.android.com/guide/topics/large-screens/support-different-screen-sizes#compose
enum class WindowSizeClass { COMPACT, MEDIUM, EXPANDED }
@Composable
fun Activity.rememberWindowSizeClass() {
val configuration = LocalConfiguration.current
val windowMetrics = remember(configuration) {
WindowMetricsCalculator.getOrCreate()
.computeCurrentWindowMetrics(this)
}
val windowDpSize = with(LocalDensity.current) {
windowMetrics.bounds.toComposeRect().size.toDpSize()
}
val widthWindowSizeClass = when {
windowDpSize.width < 600.dp -> WindowSizeClass.COMPACT
windowDpSize.width < 840.dp -> WindowSizeClass.MEDIUM
else -> WindowSizeClass.EXPANDED
}
val heightWindowSizeClass = when {
windowDpSize.height < 480.dp -> WindowSizeClass.COMPACT
windowDpSize.height < 900.dp -> WindowSizeClass.MEDIUM
else -> WindowSizeClass.EXPANDED
}
// Use widthWindowSizeClass and heightWindowSizeClass
}
But it might be a problem for ldpi screens and where to store those variables? Do I need to do same as the old way and store dimens value in a dimen folder for all densities? Because for example images in a screen on 400dp might look very big on ldpi screen (~120dp) I'm quite confusing and I'm new to jetpack compose. Thanks in advance for your help.
Upvotes: 6
Views: 7918
Reputation: 2589
You can use library https://github.com/GetStream/butterfly or create
rememberWindowSizeClass.kt
data class WindowSizeClass(
val widthWindowSizeClass: WindowType,
val heightWindowSizeClass: WindowType,
val widthWindowDpSize: Dp,
val heightWindowDpSize: Dp
) {
sealed class WindowType {
object COMPACT : WindowType()
object MEDIUM : WindowType()
object EXPANDED : WindowType()
}
}
@Composable
fun Activity.rememberWindowSizeClass(): WindowSizeClass {
val configuration = LocalConfiguration.current
val windowMetrics = remember(configuration) {
WindowMetricsCalculator.getOrCreate()
.computeCurrentWindowMetrics(activity = this)
}
val windowDpSize = with(LocalDensity.current) {
windowMetrics.bounds.toComposeRect().size.toDpSize()
}
return WindowSizeClass(
widthWindowSizeClass = when {
windowDpSize.width < 0.dp -> throw IllegalArgumentException("Dp value cannot be negative")
windowDpSize.width < 600.dp -> WindowSizeClass.WindowType.COMPACT
windowDpSize.width < 840.dp -> WindowSizeClass.WindowType.MEDIUM
else -> WindowSizeClass.WindowType.EXPANDED
},
heightWindowSizeClass = when {
windowDpSize.height < 0.dp -> throw IllegalArgumentException("Dp value cannot be negative")
windowDpSize.height < 480.dp -> WindowSizeClass.WindowType.COMPACT
windowDpSize.height < 900.dp -> WindowSizeClass.WindowType.MEDIUM
else -> WindowSizeClass.WindowType.EXPANDED
},
widthWindowDpSize = windowDpSize.width,
heightWindowDpSize = windowDpSize.height
)
}
In
MainActivity.kt
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val windowSize = rememberWindowSizeClass()
when (windowSize.widthWindowSizeClass) {
is WindowSizeClass.WindowType.COMPACT -> {
AppScreenCompact()
}
is WindowSizeClass.WindowType.MEDIUM -> {
AppScreenMedium()
}
else -> {
AppScreenExpanded()
}
}
}
}
}
For further info refer to Documentation and Sample
Upvotes: 3
Reputation: 29877
Use Jetmagic. It was designed to treat your composables like resources in the same way the older view system treated your xml layouts. It supports all the configuration qualifiers that are supported by resource folders including the screen size and screen density qualifiers.
Using Jetmagic, your composable will be selected based upon device configurations and reselect a different composable should the configuration change at runtime such as device orientation changes.
The framework includes a demo app and there's a detailed article on Medium about it:
https://github.com/JohannBlake/Jetmagic
Jetmagic is a far superior solution than using the WindowSizeClass
.
Upvotes: 0
Reputation: 1314
The code above is just an example. You can create your own code based on this idea
to match your needs.
You can use the resources system to save the dimensions but I don't really see a reason to do so. If your image is 200dp, it is meant to be 200dp. DP is dynamic. Yes, 200dp will be larger on a small screen but it should because the user is meant to actually see the content of the image.
Your app layout not breaking on different screen sizes and settings is another issue that isn't really that related to compose in theory. You just need to design your layouts in a way that they are not too sensitive to font/dpi size changes meaning a mild font/dpi size change should not be able to break the layout.
Other than this, you can just write different composables for screen configurations that are too different to work with your standard composable.
Upvotes: 0