You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
305 lines
11 KiB
305 lines
11 KiB
3 years ago
|
# Desktop components
|
||
4 years ago
|
|
||
|
## What is covered
|
||
|
|
||
3 years ago
|
In this tutorial, we will show you how to use desktop-specific components of Compose for Desktop such as scrollbars and tooltips.
|
||
4 years ago
|
|
||
3 years ago
|
## Scrollbars
|
||
4 years ago
|
|
||
3 years ago
|
You can apply scrollbars to scrollable components. The scrollbar and scrollable components share a common state to synchronize with each other. For example, `VerticalScrollbar` can be attached to `Modifier.verticalScroll`, and `LazyColumnFor` and `HorizontalScrollbar` can be attached to `Modifier.horizontalScroll` and `LazyRowFor`.
|
||
4 years ago
|
|
||
|
```kotlin
|
||
|
import androidx.compose.desktop.Window
|
||
|
import androidx.compose.foundation.HorizontalScrollbar
|
||
4 years ago
|
import androidx.compose.foundation.VerticalScrollbar
|
||
|
import androidx.compose.foundation.background
|
||
|
import androidx.compose.foundation.horizontalScroll
|
||
4 years ago
|
import androidx.compose.foundation.layout.Box
|
||
|
import androidx.compose.foundation.layout.Column
|
||
4 years ago
|
import androidx.compose.foundation.layout.Spacer
|
||
4 years ago
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||
4 years ago
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||
4 years ago
|
import androidx.compose.foundation.layout.height
|
||
|
import androidx.compose.foundation.layout.padding
|
||
|
import androidx.compose.foundation.layout.width
|
||
|
import androidx.compose.foundation.rememberScrollState
|
||
4 years ago
|
import androidx.compose.foundation.rememberScrollbarAdapter
|
||
|
import androidx.compose.foundation.verticalScroll
|
||
4 years ago
|
import androidx.compose.material.Text
|
||
4 years ago
|
import androidx.compose.runtime.Composable
|
||
|
import androidx.compose.ui.Alignment
|
||
|
import androidx.compose.ui.Modifier
|
||
4 years ago
|
import androidx.compose.ui.graphics.Color
|
||
4 years ago
|
import androidx.compose.ui.unit.IntSize
|
||
4 years ago
|
import androidx.compose.ui.unit.dp
|
||
4 years ago
|
|
||
|
fun main() {
|
||
|
Window(title = "Scrollbars", size = IntSize(250, 400)) {
|
||
|
Box(
|
||
|
modifier = Modifier.fillMaxSize()
|
||
|
.background(color = Color(180, 180, 180))
|
||
|
.padding(10.dp)
|
||
|
) {
|
||
4 years ago
|
val stateVertical = rememberScrollState(0)
|
||
|
val stateHorizontal = rememberScrollState(0)
|
||
4 years ago
|
|
||
4 years ago
|
Box(
|
||
|
modifier = Modifier
|
||
|
.fillMaxSize()
|
||
|
.verticalScroll(stateVertical)
|
||
|
.padding(end = 12.dp, bottom = 12.dp)
|
||
|
.horizontalScroll(stateHorizontal)
|
||
4 years ago
|
) {
|
||
4 years ago
|
Column {
|
||
|
for (item in 0..30) {
|
||
4 years ago
|
TextBox("Item #$item")
|
||
4 years ago
|
if (item < 30) {
|
||
|
Spacer(modifier = Modifier.height(5.dp))
|
||
4 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
VerticalScrollbar(
|
||
|
modifier = Modifier.align(Alignment.CenterEnd)
|
||
|
.fillMaxHeight(),
|
||
|
adapter = rememberScrollbarAdapter(stateVertical)
|
||
|
)
|
||
|
HorizontalScrollbar(
|
||
|
modifier = Modifier.align(Alignment.BottomStart)
|
||
|
.fillMaxWidth()
|
||
|
.padding(end = 12.dp),
|
||
|
adapter = rememberScrollbarAdapter(stateHorizontal)
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Composable
|
||
|
fun TextBox(text: String = "Item") {
|
||
|
Box(
|
||
|
modifier = Modifier.height(32.dp)
|
||
|
.width(400.dp)
|
||
4 years ago
|
.background(color = Color(200, 0, 0, 20))
|
||
4 years ago
|
.padding(start = 10.dp),
|
||
4 years ago
|
contentAlignment = Alignment.CenterStart
|
||
4 years ago
|
) {
|
||
|
Text(text = text)
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
![Scrollbars](scrollbars.gif)
|
||
|
|
||
|
## Lazy scrollable components with Scrollbar
|
||
|
|
||
3 years ago
|
You can use scrollbars with lazy scrollable components, for example, `LazyColumn`.
|
||
4 years ago
|
|
||
|
```kotlin
|
||
|
import androidx.compose.desktop.Window
|
||
4 years ago
|
import androidx.compose.foundation.VerticalScrollbar
|
||
|
import androidx.compose.foundation.background
|
||
|
import androidx.compose.foundation.layout.Box
|
||
|
import androidx.compose.foundation.layout.Spacer
|
||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||
|
import androidx.compose.foundation.layout.height
|
||
|
import androidx.compose.foundation.layout.padding
|
||
4 years ago
|
import androidx.compose.foundation.lazy.LazyColumn
|
||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||
|
import androidx.compose.foundation.rememberScrollbarAdapter
|
||
4 years ago
|
import androidx.compose.material.Text
|
||
4 years ago
|
import androidx.compose.runtime.Composable
|
||
|
import androidx.compose.ui.Alignment
|
||
|
import androidx.compose.ui.Modifier
|
||
4 years ago
|
import androidx.compose.ui.graphics.Color
|
||
4 years ago
|
import androidx.compose.ui.unit.IntSize
|
||
4 years ago
|
import androidx.compose.ui.unit.dp
|
||
4 years ago
|
|
||
|
fun main() {
|
||
|
Window(title = "Scrollbars", size = IntSize(250, 400)) {
|
||
|
LazyScrollable()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Composable
|
||
|
fun LazyScrollable() {
|
||
|
Box(
|
||
|
modifier = Modifier.fillMaxSize()
|
||
|
.background(color = Color(180, 180, 180))
|
||
|
.padding(10.dp)
|
||
4 years ago
|
) {
|
||
4 years ago
|
|
||
|
val state = rememberLazyListState()
|
||
|
|
||
|
LazyColumn(Modifier.fillMaxSize().padding(end = 12.dp), state) {
|
||
3 years ago
|
items(1000) { x ->
|
||
4 years ago
|
TextBox("Item #$x")
|
||
4 years ago
|
Spacer(modifier = Modifier.height(5.dp))
|
||
|
}
|
||
|
}
|
||
|
VerticalScrollbar(
|
||
|
modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight(),
|
||
|
adapter = rememberScrollbarAdapter(
|
||
3 years ago
|
scrollState = state
|
||
4 years ago
|
)
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Composable
|
||
|
fun TextBox(text: String = "Item") {
|
||
|
Box(
|
||
|
modifier = Modifier.height(32.dp)
|
||
|
.fillMaxWidth()
|
||
|
.background(color = Color(0, 0, 0, 20))
|
||
|
.padding(start = 10.dp),
|
||
4 years ago
|
contentAlignment = Alignment.CenterStart
|
||
4 years ago
|
) {
|
||
|
Text(text = text)
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
![Lazy component](lazy_scrollbar.gif)
|
||
|
|
||
|
## Theme applying
|
||
|
|
||
3 years ago
|
Scrollbars support themes to change their appearance. The example below shows how to use the `DesktopTheme` appearance for the scrollbar.
|
||
4 years ago
|
|
||
4 years ago
|
```kotlin
|
||
4 years ago
|
import androidx.compose.desktop.DesktopTheme
|
||
|
import androidx.compose.desktop.Window
|
||
|
import androidx.compose.foundation.background
|
||
|
import androidx.compose.foundation.layout.Box
|
||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||
|
import androidx.compose.foundation.layout.height
|
||
|
import androidx.compose.foundation.layout.padding
|
||
|
import androidx.compose.foundation.layout.Spacer
|
||
|
import androidx.compose.foundation.rememberScrollbarAdapter
|
||
|
import androidx.compose.foundation.rememberScrollState
|
||
4 years ago
|
import androidx.compose.material.Text
|
||
4 years ago
|
import androidx.compose.foundation.VerticalScrollbar
|
||
4 years ago
|
import androidx.compose.foundation.layout.Column
|
||
|
import androidx.compose.foundation.verticalScroll
|
||
4 years ago
|
import androidx.compose.material.MaterialTheme
|
||
|
import androidx.compose.runtime.Composable
|
||
|
import androidx.compose.ui.Alignment
|
||
|
import androidx.compose.ui.graphics.Color
|
||
|
import androidx.compose.ui.Modifier
|
||
|
import androidx.compose.ui.unit.dp
|
||
|
import androidx.compose.ui.unit.IntSize
|
||
|
|
||
|
fun main() {
|
||
|
Window(title = "Scrollbars", size = IntSize(280, 400)) {
|
||
|
MaterialTheme {
|
||
|
DesktopTheme {
|
||
|
Box(
|
||
|
modifier = Modifier.fillMaxSize()
|
||
|
.background(color = Color(180, 180, 180))
|
||
|
.padding(10.dp)
|
||
|
) {
|
||
4 years ago
|
val state = rememberScrollState(0)
|
||
4 years ago
|
|
||
4 years ago
|
Column(
|
||
|
modifier = Modifier
|
||
|
.verticalScroll(state)
|
||
|
.fillMaxSize()
|
||
|
.padding(end = 12.dp)
|
||
4 years ago
|
) {
|
||
|
for (item in 0..30) {
|
||
4 years ago
|
TextBox("Item #$item")
|
||
4 years ago
|
if (item < 30) {
|
||
|
Spacer(modifier = Modifier.height(5.dp))
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
VerticalScrollbar(
|
||
|
modifier = Modifier.align(Alignment.CenterEnd)
|
||
|
.fillMaxHeight(),
|
||
|
adapter = rememberScrollbarAdapter(state)
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Composable
|
||
|
fun TextBox(text: String = "Item") {
|
||
|
Box(
|
||
|
modifier = Modifier.height(32.dp)
|
||
|
.fillMaxWidth()
|
||
|
.background(color = Color(0, 0, 0, 20))
|
||
|
.padding(start = 10.dp),
|
||
4 years ago
|
contentAlignment = Alignment.CenterStart
|
||
4 years ago
|
) {
|
||
|
Text(text = text)
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
![Themed scrollbar](themed_scrollbar.gif)
|
||
3 years ago
|
|
||
|
|
||
|
## Tooltips
|
||
|
|
||
|
You can add tooltip to any components using `BoxWithTooltip`. Basically `BoxWithTooltip` is a `Box` with the ability to show a tooltip, and has the same arguments and behavior as `Box`.
|
||
|
The main arguments of the `BoxWithTooltip` function:
|
||
|
- tooltip - composable content representing tooltip
|
||
|
- delay - time delay in milliseconds after which the tooltip will be shown (default is 500 ms)
|
||
|
- offset - tooltip offset, the default position of the tooltip is under the mouse cursor
|
||
|
|
||
|
```kotlin
|
||
|
import androidx.compose.desktop.Window
|
||
|
import androidx.compose.foundation.BoxWithTooltip
|
||
|
import androidx.compose.foundation.layout.Arrangement
|
||
|
import androidx.compose.foundation.layout.Column
|
||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||
|
import androidx.compose.foundation.layout.padding
|
||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||
|
import androidx.compose.material.Button
|
||
|
import androidx.compose.material.Surface
|
||
|
import androidx.compose.material.Text
|
||
|
import androidx.compose.ui.Alignment
|
||
|
import androidx.compose.ui.draw.shadow
|
||
|
import androidx.compose.ui.graphics.Color
|
||
|
import androidx.compose.ui.Modifier
|
||
|
import androidx.compose.ui.unit.dp
|
||
|
import androidx.compose.ui.unit.DpOffset
|
||
|
import androidx.compose.ui.unit.IntSize
|
||
|
|
||
|
fun main() = Window(title = "Tooltip Example", size = IntSize(300, 300)) {
|
||
|
val buttons = listOf("Button A", "Button B", "Button C", "Button D", "Button E", "Button F")
|
||
|
Column(Modifier.fillMaxSize(), Arrangement.spacedBy(5.dp)) {
|
||
|
buttons.forEachIndexed { index, name ->
|
||
|
// wrap button in BoxWithTooltip
|
||
|
BoxWithTooltip(
|
||
|
modifier = Modifier.padding(start = 40.dp),
|
||
|
tooltip = {
|
||
|
// composable tooltip content
|
||
|
Surface(
|
||
|
modifier = Modifier.shadow(4.dp),
|
||
|
color = Color(255, 255, 210),
|
||
|
shape = RoundedCornerShape(4.dp)
|
||
|
) {
|
||
|
Text(
|
||
|
text = "Tooltip for ${name}",
|
||
|
modifier = Modifier.padding(10.dp)
|
||
|
)
|
||
|
}
|
||
|
},
|
||
|
delay = 600, // in milliseconds
|
||
|
offset = if (index % 2 == 0) DpOffset(-16.dp, 0.dp) else DpOffset.Zero // tooltip offset
|
||
|
) {
|
||
|
Button(onClick = {}) { Text(text = name) }
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
![Tooltip](tooltips.gif)
|