Jetpack Compose Desktop: getting your display's height and width - kotlin

I am looking for a way to get your display's height and width in Jetpack Compose for Desktop, but despite the fact that I've found some questions on SO (Screen width and height in Jetpack Compose), it's not very helpful, because there are no values (and other stuff) such as LocalConfiguration, only - LocalViewConfiguration, which is a different thing.
So, some words about my initial goal: I want to be able to automatically change the size of font used in my application: textStyle = TextStyle(fontFamily = FontFamily.Monospace, fontSize = calculateRelativeFontSize()), where: #Composable fun calculateRelativeFontSize(): TextUnit { val height = ...; val width = ...; ...}
Finally, I'm sorry if I'm missing something, because I'm not really a Kotlin or (honestly) Jetpack Compose programmer, just was asked to do some stuff...
P.S. I'm working under Linux, so... maybe somehow (really don't believe in that)... (you got the point)

You have to remember that JetBrains Compose is built upon Skia and Java's AWT libraries. You can use their native functions relating to screen info. For instance using AWT:
// CloudsAnimation.kt
import org.jetbrains.skia.RuntimeEffect
import java.awt.Toolkit
#Composable
fun CloudsAnimation(
modifier: Modifier = Modifier
) {
val screenSize = Toolkit.getDefaultToolkit().screenSize
val screenHeight = screenSize.height
val screenWidth = screenSize.width
println("Width: $screenWidth ; Height: $screenHeight")
// ... composables below etc
}
Running this on my 13 inch MacBook Pro :
Width: 1440 ; Height: 900

Related

Why scrollable modifier doesn't scroll view content?

I am trying to get scrolling to work on a Column where the number of entries may exceed the height of the window.
I'm currently using Compose 1.1.0-rc03 and at the moment I'm only trying to get it working on desktop.
I reduced the problem to this:
#Composable
fun App() {
val optionsScrollState = rememberScrollState()
Row(modifier = Modifier.fillMaxSize()) {
// Left column
Column(
modifier = Modifier
.scrollable(optionsScrollState, Orientation.Vertical)
.width(240.dp)
.fillMaxHeight()
) {
(1..100).forEach { i -> Text("Row $i") }
}
}
}
But this doesn't scroll, or at least, not with the mousewheel. Maybe there's another way to scroll that isn't immediately apparent to me.
How do I make this work?
The docs on scrollable say that I might have to manage the state myself. So is using rememberScrollState() not enough?
I found some existing questions about disabling scrolling on columns, but they were always talking about LazyColumn which I'm not using here.
You're using a wrong modifier. From documentation:
The scrollable modifier differs from the scroll modifiers in that scrollable detects the scroll gestures, but does not offset its contents.
If you're interested how Modifier.scrollable should be used, you can find an example in the same documentation chapter.
You can use Modifier.verticalScroll instead, which will give you the expected behavior.
Also consider switching to LazyColumn, which already has built-in scrolling as well as lazy cell loading.

Jetpack Compose Desktop: Scrollable Column/LazyColumn

I'm creating a program in Jetpack Compose Desktop version 1.0.0-beta5 and I can't figure out how to make Column/LazyColumn scrollable. At the same time, it seems to me that a lot of the classes listed in the documentation for Android are missing and can not work from their examples.
val lazyListState = rememberLazyListState()
val scrollState = rememberScrollState()
LazyColumn(
state = lazyListState,
modifier = Modifier.verticalScroll(scrollState)
) {
items(ArrayList<String>()){ item ->
Column(modifier = Modifier.padding(8.dp)) {
Text(item)
}
}
}
This code is currently producing an error.
To be precise, the empty list used can be seen in the example, but this is just an adjustment, in fact I draw a lot of items.
I know this question is very old, but you can take a look at Desktop Compoments
Jetpack compose is for the android framework,
Compose desktop is a flavor of Jetpack compose, it uses Skia and Swing under the hood

Jetpack Compose Desktop – MaterialTheme.colors.background Not Working

Setting MaterialTheme.colors
I'm trying to make a very basic window in Jetpack Compose for Desktop (not mobile), but I'm having some difficulties with changing the colors of the window. I've looked at some tutorials and examples, but maybe I don't quite understand how color themes are correctly implemented.
The code that I wrote should create a window with a dark background, but the window when the program runs is white.
Please provide any insights you can as to what I am doing wrong.
Code (Kotlin)
import androidx.compose.desktop.*
import androidx.compose.material.*
import androidx.compose.ui.unit.*
fun main() = Window(
title = "Window",
resizable = false,
size = IntSize(1200, 800),
) {
MaterialTheme(colors = darkColors()) {
}
}
Window
Other Info
macOS Big Sur
IntelliJ 2021.2
Jetpack Compose 0.4.0
The MaterialTheme only provides colors for all views inside the container, it does not create or render the view.
Most Material components will use these colors as default values, but you can also use these colors in your views using, for example, MaterialTheme.colors.background.
You need to put some view inside, size it and apply some background color, for example:
MaterialTheme(colors = darkColors()) {
Box(Modifier.fillMaxSize().background(MaterialTheme.colors.background))
}
You can use Scaffold to see changes.
In your example:
...
MaterialTheme(colors = darkColors()) {
Scaffold {
// your content
}
}
...
You can read about it:
https://developer.android.com/jetpack/compose/layouts/material
or here:
https://metanit.com/kotlin/jetpack/4.11.php

Divider composable becomes invisible when placed inside composable with horizontalScroll modifier set. Is this a bug?

Background
I am making a desktop compose application.
I had a LazyColumn with Divider separating items. LazyColumn's width may not fit in window so I made the LazyColumn horizontally scrollable by enclosing it inside a Box with horizontalScroll() modifier set.
Now LazyColumn became horizontal scrollable as well. But strangely the Divider's separating the items disappeared.
After digging into it for a while, I figured out that Divider's became invisible only when placed inside a horizontally scrollable parent.
Minimal Reproduction
Here is a minimal reproduction of observed behavior where red Divider is clearly invisible when horizontalScroll(rememberScrollState()) modifier is set in enclosing Box.
fun main() = application {
Window(onCloseRequest = ::exitApplication) {
Box(
Modifier.fillMaxSize()
.background(Color.Green)
.horizontalScroll(rememberScrollState())
) {
Divider(thickness = 10.dp, color = Color.Red)
}
}
}
As it can be seen that the red Divider is invisible for above code.
Expected Output:
With verticalScroll() or no scroll modifier at all works fine as expected.
fun main() = application {
Window(onCloseRequest = ::exitApplication) {
Box(
Modifier.fillMaxSize()
.background(Color.Green)
.verticalScroll(rememberScrollState())
) {
Divider(thickness = 10.dp, color = Color.Red)
}
}
}
Correct output as expected, the red Divider is clearly visible for above code.
Version info
kotlin("jvm") version "1.5.21"
id("org.jetbrains.compose") version "1.0.0-alpha3"
I'd like to know if this is a bug? or is there a way to fix this.
No, this is not a bug.
Divider is used to take the full width, just like any other view with the fillMaxWidth() modifier.
But inside horizontalScroll this modifier is ignored because it is ambiguous: horizontalScroll wraps the size of the content, so the maxWidth constraint in this area is infinite.
From fillMaxWidth documentation:
If the incoming maximum width is Constraints.Infinity this modifier will have no effect.
I haven't found any documentation mentioning horizontalScroll effects Constraints, you can see maintainer's answer on the same issue, or you can test it by yourself like this:
Box {
BoxWithConstraints(Modifier.fillMaxSize()) {
// output 1080 2082
println("non scrollable max dimensions: ${constraints.maxWidth} ${constraints.maxHeight}")
}
BoxWithConstraints(Modifier.fillMaxSize().horizontalScroll(rememberScrollState())) {
// output 2147483647 2082
println("scrollable max dimensions: ${constraints.maxWidth} ${constraints.maxHeight}")
}
}
In this case you need to specify the width explicitly, e.g:
Box(
Modifier
.fillMaxSize()
.background(Color.Green)
.horizontalScroll(rememberScrollState())
) {
var width by remember { mutableStateOf(0) }
val density = LocalDensity.current
val widthDp = remember(width, density) { with(density) { width.toDp() } }
LazyColumn(
modifier = Modifier.onSizeChanged {
width = it.width
}
) {
items(100) {
Text("$it".repeat(it))
Divider(
thickness = 10.dp,
color = Color.Red,
modifier = Modifier.width(widthDp)
)
}
}
}
Note that when the top part of your LazyColumn is smaller than the bottom one, as in my example, the width will be smaller at first (to accommodate only the visible part), but after scrolling down and back up, the width will not be restored to its original width because the Divider width modifier will not let it shrink back down. If you need to prevent this, you need to calculate the `width' based only on the visible elements, which is more complicated.

ImageView is not respecting the size of the CardView

I am trying to make some sort of gallery app. I would like to display images inside of a ScrollView inside a GridLayout so I used CardView for this and it looks like this:
But when I put ImageView inside each CardView, the CardView spreads and fills the whole ScrollView. Here's a preview:
The CardView is created programatically. Here's the code
fun CreateCardView(ItemCount: Int){
for (i in 1 until ItemCount){
/////////////////////CARD VIEW//////////////////////////////
val card_view = CardView(this)
card_view.radius = 8F
card_view.setContentPadding(8,8,8,8)
card_view.setCardBackgroundColor(Color.LTGRAY)
card_view.cardElevation = 8F
val param = GridLayout.LayoutParams()
param.rowSpec = GridLayout.spec(GridLayout.UNDEFINED, 1f)
param.columnSpec = GridLayout.spec(GridLayout.UNDEFINED, 1f)
card_view.layoutParams = param
val param2 = card_view.layoutParams as GridLayout.LayoutParams
param2.setMargins(10,10,10,10)
card_view.layoutParams = param2
subLayoutGrid?.addView(card_view)
////////////////////////END//////////////////////////////////////
///////////////////////IMAGEVIEW////////////////////////////////
val img = ImageView(this)
val imageparams = WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT
)
img.layoutParams = imageparams
img.scaleType = ImageView.ScaleType.CENTER_CROP
img.setImageResource(R.drawable.animaleight)
card_view.addView(img)
////////////////////////END///////////////////////////
}
}
How can I put ImageView inside the CardView without filling the whole ScrollView?
I've already fixed my problem. I've tried to use a 40px x 40px Picture then it worked the way I want to. See the image:
It seems like when you use high resolution Picture, the app cant handle the populating of ImageView in GridLayout.