Pantrix UI

Supporting Pane Scaffold

Bir ekranın ana içeriği ve onu destekleyen bir panel: bir belge ve yorumları, bir grafik ve filtreleri, bir harita ve sonuçları. Yerde ikisine de yer varsa yan yana; yoksa ana içeriğin üstünde ya da yerinde.

import com.pantrixui.components.container.supportingpane.PantrixSupportingPaneScaffold

Örnekler

Belge ve yorumlar

Bir rapor ve yorumları. Geniş bir yerde yorumlar raporun yanında durur; üstündeki "Yorumları gizle" onları kaldırır, rapor bütün yeri alır.

Karttaki pencere seçicisinden "Dar"ı seç ve "Yorumlar"a bas: yorumlar alttan açılan bir sheet'te gelir. Tutamacından aşağı sürükle, scrim'e bas ya da kapatma düğmesine bas: kapanır. "Orta"da sheet sondan gelir.

Yorum alanına bir şey yaz ve pencereyi değiştir: yazdığın kalır. Destek paneli her yerde aynı kompozisyondur. Yanda dururken başlığını ve gizle düğmesini panel kendisi çizer (supportingPlace == Beside); sheet'te başlık ve kapatma düğmesi iskelenindir.

val comments = rememberSupportingPaneState()
PantrixSupportingPaneScaffold(
    state = comments,
    main = {
        DocumentPane(
            commentsShown = isSupportingShown,
            onComments = { if (isSupportingShown) comments.hide() else comments.show() }
        )
    },
    supporting = {
        CommentsPane(
            // Yanda panel kendi başlığını çizer; sheet'te başlık ve kapatma düğmesi iskelenindir.
            onHide = if (supportingPlace == SupportingPanePlace.Beside) ({ comments.hide() }) else null
        )
    },
    modifier = Modifier.fillMaxWidth().height(SUPPORTING_EXAMPLE_HEIGHT),
    mainTitle = "Çeyrek raporu",
    supportingTitle = "Yorumlar",
    tagKey = "document"
)

@Composable
private fun DocumentPane(
    commentsShown: Boolean,
    onComments: () -> Unit
) {
    PaneSurface {
        Column(modifier = Modifier.fillMaxSize()) {
            PantrixTopBar(
                title = "Çeyrek raporu",
                actions = {
                    PantrixButton(
                        text = if (commentsShown) "Yorumları gizle" else "Yorumlar",
                        onClick = onComments,
                        variant = ButtonVariant.Text,
                        tagKey = "document_comments"
                    )
                },
                tagKey = "document"
            )
            Column(
                modifier = Modifier.verticalScroll(rememberScrollState()).padding(PantrixTheme.spacing.md),
                verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md)
            ) {
                PARAGRAPHS.forEach { PantrixText(text = it, style = PantrixTheme.typography.body) }
            }
        }
    }
}

@Composable
private fun CommentsPane(onHide: (() -> Unit)?) {
    val draft = rememberTextFieldState()
    PaneSurface {
        Column(modifier = Modifier.fillMaxSize()) {
            if (onHide != null) HideBar(title = "Yorumlar", onHide = onHide, tagKey = "comments")
            Column(
                modifier = Modifier.weight(1f).verticalScroll(rememberScrollState()).padding(PantrixTheme.spacing.md),
                verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md)
            ) {
                COMMENTS.forEach { comment ->
                    Row(horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
                        PantrixAvatar(contentDescription = null, initials = comment.initials)
                        Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.xs)) {
                            PantrixText(text = comment.author, style = PantrixTheme.typography.callout)
                            PantrixText(text = comment.text, style = PantrixTheme.typography.footnote)
                        }
                    }
                }
            }
            PantrixHorizontalDivider()
            PantrixTextField(
                state = draft,
                modifier = Modifier.fillMaxWidth().padding(PantrixTheme.spacing.md),
                label = "Yorum yaz",
                tagKey = "comments_draft"
            )
        }
    }
}

private val SUPPORTING_EXAMPLE_HEIGHT = 460.dp

@Composable
private fun HideBar(
    title: String,
    onHide: () -> Unit,
    tagKey: String
) {
    PantrixTopBar(
        title = title,
        actions = {
            PantrixIconButton(
                imageVector = PantrixIcons.Close,
                contentDescription = "$title gizle",
                onClick = onHide,
                tagKey = "${tagKey}_hide"
            )
        },
        tagKey = tagKey
    )
}

@Composable
private fun PaneSurface(
    modifier: Modifier = Modifier,
    content: @Composable BoxScope.() -> Unit
) {
    PantrixSurface(modifier = modifier.fillMaxSize(), border = PantrixTheme.colors.border) { content() }
}

private val PARAGRAPHS = listOf(
    "Üçüncü çeyrekte satışlar bir önceki çeyreğe göre yüzde on iki arttı. Artışın çoğu internetten geldi.",
    "Mağazalardaki satış yerinde saydı; iki yeni mağazanın açılışı ekime kaldı.",
    "Bayi kanalında yeni sözleşmeler yürürlüğe girdi. Etkisi dördüncü çeyrekte görülecek.",
    "Gelecek çeyrek için hedef, internet satışlarını korurken mağazalarda yüzde beş büyümek."
)

private val COMMENTS = listOf(
    DemoComment("Ayşe Yılmaz", "AY", "İnternet satışlarının kaynağını ayrıca gösterebilir miyiz?"),
    DemoComment("Mert Kaya", "MK", "Mağaza açılışlarının tarihi kesinleşti mi?"),
    DemoComment("Elif Demir", "ED", "Bayi sözleşmelerinin özeti ekte.")
)

private class DemoComment(
    val author: String,
    val initials: String,
    val text: String
)

Grafik ve filtreler: genişliği sürüklenir

Bir grafik ve filtreleri. Filtrelerin değeri örnekte tutulur (channels, stacked): iki panel de onu okur, grafik filtre değişince kendini çizer.

resizable = true: geniş bir yerde panellerin arasındaki tutamacı sürükle ya da odaklayıp ok tuşlarıyla ayarla; sol ok filtreleri genişletir. Genişlik supportingWidth'te kalır, "Dar"a geçip dönünce de yerindedir. style = SupportingPaneScaffoldStyle(minSupportingWidth = 240.dp): tutamaç filtreleri 240dp'den dar yapmaz.

val filters = rememberSupportingPaneState()
val channels = remember { mutableStateListOf(*CHANNELS.map { it.key }.toTypedArray()) }
var stacked by remember { mutableStateOf(false) }
PantrixSupportingPaneScaffold(
    state = filters,
    main = {
        ChartPane(
            channels = channels,
            stacked = stacked,
            filtersShown = isSupportingShown,
            onFilters = { if (isSupportingShown) filters.hide() else filters.show() }
        )
    },
    supporting = {
        FiltersPane(
            channels = channels,
            onChannel = { key, on -> if (on) channels.add(key) else channels.remove(key) },
            stacked = stacked,
            onStacked = { stacked = it },
            onHide = if (supportingPlace == SupportingPanePlace.Beside) ({ filters.hide() }) else null
        )
    },
    modifier = Modifier.fillMaxWidth().height(SUPPORTING_EXAMPLE_HEIGHT),
    mainTitle = "Satışlar",
    supportingTitle = "Filtreler",
    resizable = true,
    style = SupportingPaneScaffoldStyle(minSupportingWidth = 240.dp),
    tagKey = "sales"
)

@Composable
private fun ChartPane(
    channels: List<String>,
    stacked: Boolean,
    filtersShown: Boolean,
    onFilters: () -> Unit
) {
    PaneSurface {
        Column(modifier = Modifier.fillMaxSize()) {
            PantrixTopBar(
                title = "Satışlar",
                actions = {
                    PantrixButton(
                        text = if (filtersShown) "Filtreleri gizle" else "Filtreler",
                        onClick = onFilters,
                        variant = ButtonVariant.Text,
                        tagKey = "sales_filters"
                    )
                },
                tagKey = "sales"
            )
            PantrixBarChart(
                data = MONTHS,
                x = { it.month },
                values = CHANNELS.filter { it.key in channels }.map { channel ->
                    ChartValue<MonthSales>(channel.key, channel.name) { channel.of(it) }
                },
                modifier = Modifier.weight(1f).padding(PantrixTheme.spacing.md),
                stacked = stacked,
                description = "Seçilen kanalların aylara göre satışı",
                tagKey = "sales_chart"
            )
        }
    }
}

@Composable
private fun FiltersPane(
    channels: List<String>,
    onChannel: (key: String, on: Boolean) -> Unit,
    stacked: Boolean,
    onStacked: (Boolean) -> Unit,
    onHide: (() -> Unit)?
) {
    PaneSurface {
        Column(modifier = Modifier.fillMaxSize()) {
            if (onHide != null) HideBar(title = "Filtreler", onHide = onHide, tagKey = "filters")
            Column(
                modifier = Modifier.verticalScroll(rememberScrollState()).padding(PantrixTheme.spacing.md),
                verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)
            ) {
                PantrixText(text = "Kanallar", style = PantrixTheme.typography.callout)
                CHANNELS.forEach { channel ->
                    PantrixCheckbox(
                        checked = channel.key in channels,
                        onCheckedChange = { onChannel(channel.key, it) },
                        label = channel.name,
                        tagKey = "filter_${channel.key}"
                    )
                }
                PantrixHorizontalDivider()
                PantrixSwitchButton(
                    checked = stacked,
                    onCheckedChange = onStacked,
                    label = "Üst üste göster",
                    tagKey = "filter_stacked"
                )
            }
        }
    }
}

private val CHANNELS = listOf(
    SalesChannel("online", "İnternet") { it.online },
    SalesChannel("stores", "Mağazalar") { it.stores },
    SalesChannel("partners", "Bayiler") { it.partners }
)

private val SUPPORTING_EXAMPLE_HEIGHT = 460.dp

@Composable
private fun HideBar(
    title: String,
    onHide: () -> Unit,
    tagKey: String
) {
    PantrixTopBar(
        title = title,
        actions = {
            PantrixIconButton(
                imageVector = PantrixIcons.Close,
                contentDescription = "$title gizle",
                onClick = onHide,
                tagKey = "${tagKey}_hide"
            )
        },
        tagKey = tagKey
    )
}

@Composable
private fun PaneSurface(
    modifier: Modifier = Modifier,
    content: @Composable BoxScope.() -> Unit
) {
    PantrixSurface(modifier = modifier.fillMaxSize(), border = PantrixTheme.colors.border) { content() }
}

private class SalesChannel(
    val key: String,
    val name: String,
    val of: (MonthSales) -> Double
)

private class MonthSales(
    val month: String,
    val online: Double,
    val stores: Double,
    val partners: Double
)

private val MONTHS = listOf(
    MonthSales("Tem", online = 42.0, stores = 30.0, partners = 12.0),
    MonthSales("Ağu", online = 48.0, stores = 29.0, partners = 14.0),
    MonthSales("Eyl", online = 55.0, stores = 31.0, partners = 18.0)
)

Harita ve sonuçlar: dar yerde haritanın yerinde

Bir harita ve sonuçları, presentation = SupportingPanePresentation.Pane ile: dar bir yerde sonuçlar sheet'te değil, haritanın yerinde açılır. Başındaki geri düğmesi, Android'in geri tuşu, Escape ve iOS'un kenardan kaydırması haritaya döndürür; geri düğmesi yalnızca o zaman durur (supportingPlace == InPlaceOfMain).

Bir sonuca bas: haritadaki işareti büyür. Seçim örnekte tutulur, iki panel de onu okur.

val results = rememberSupportingPaneState()
var chosen by remember { mutableStateOf<String?>(null) }
PantrixSupportingPaneScaffold(
    state = results,
    main = {
        MapPane(
            chosen = chosen,
            // Yanda sonuçlar zaten görünür: düğme yalnızca dar yerde durur.
            onResults = if (supportingPlace == SupportingPanePlace.Beside) null else ({ results.show() })
        )
    },
    supporting = {
        ResultsPane(
            chosen = chosen,
            onChoose = { chosen = it },
            onBack = if (supportingPlace == SupportingPanePlace.InPlaceOfMain) ({ results.hide() }) else null
        )
    },
    modifier = Modifier.fillMaxWidth().height(SUPPORTING_EXAMPLE_HEIGHT),
    mainTitle = "Harita",
    supportingTitle = "Sonuçlar",
    presentation = SupportingPanePresentation.Pane,
    tagKey = "places"
)

@Composable
private fun MapPane(
    chosen: String?,
    onResults: (() -> Unit)?
) {
    val colors = PantrixTheme.colors
    PaneSurface {
        Column(modifier = Modifier.fillMaxSize()) {
            PantrixTopBar(
                title = "Harita",
                actions = if (onResults != null) {
                    {
                        PantrixButton(
                            text = "Sonuçlar",
                            onClick = onResults,
                            variant = ButtonVariant.Text,
                            tagKey = "places_results"
                        )
                    }
                } else {
                    null
                },
                tagKey = "places_map"
            )
            Canvas(modifier = Modifier.fillMaxWidth().weight(1f).background(colors.neutral.container)) {
                val step = 48.dp.toPx()
                var x = 0f
                while (x < size.width) {
                    drawLine(colors.border, Offset(x, 0f), Offset(x, size.height))
                    x += step
                }
                var y = 0f
                while (y < size.height) {
                    drawLine(colors.border, Offset(0f, y), Offset(size.width, y))
                    y += step
                }
                PLACES.forEach { place ->
                    val big = place.name == chosen
                    drawCircle(
                        color = if (big) colors.primary.color else colors.textSecondary,
                        radius = (if (big) 12.dp else 7.dp).toPx(),
                        center = Offset(place.x * size.width, place.y * size.height)
                    )
                }
            }
        }
    }
}

@Composable
private fun ResultsPane(
    chosen: String?,
    onChoose: (String) -> Unit,
    onBack: (() -> Unit)?
) {
    val colors = PantrixTheme.colors
    val spacing = PantrixTheme.spacing
    PaneSurface {
        Column(modifier = Modifier.fillMaxSize()) {
            PantrixTopBar(
                title = "Sonuçlar",
                navigationIcon = onBack?.let { back -> { PantrixBackButton(onClick = back, tagKey = "places_back") } },
                tagKey = "places_list"
            )
            Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
                PLACES.forEachIndexed { index, place ->
                    if (index > 0) PantrixHorizontalDivider()
                    val selected = place.name == chosen
                    Column(
                        modifier = Modifier
                            .fillMaxWidth()
                            .selectable(selected = selected, onClick = { onChoose(place.name) })
                            .background(if (selected) colors.primary.container else Color.Transparent)
                            .padding(spacing.md),
                        verticalArrangement = Arrangement.spacedBy(spacing.xs)
                    ) {
                        PantrixText(
                            text = place.name,
                            style = PantrixTheme.typography.callout,
                            color = if (selected) colors.primary.onContainer else Color.Unspecified,
                            tagKey = "place_$index"
                        )
                        PantrixText(
                            text = place.kind,
                            style = PantrixTheme.typography.footnote,
                            color = if (selected) colors.primary.onContainer else colors.textSecondary
                        )
                    }
                }
            }
        }
    }
}

private val SUPPORTING_EXAMPLE_HEIGHT = 460.dp

@Composable
private fun PaneSurface(
    modifier: Modifier = Modifier,
    content: @Composable BoxScope.() -> Unit
) {
    PantrixSurface(modifier = modifier.fillMaxSize(), border = PantrixTheme.colors.border) { content() }
}

private val PLACES = listOf(
    DemoPlace("Moda Sahili", "Park", 0.22f, 0.64f),
    DemoPlace("Kadıköy Çarşısı", "Pazar", 0.48f, 0.38f),
    DemoPlace("Haydarpaşa", "Gar", 0.36f, 0.18f),
    DemoPlace("Yeldeğirmeni", "Mahalle", 0.70f, 0.52f),
    DemoPlace("Fenerbahçe Parkı", "Park", 0.82f, 0.82f)
)

private class DemoPlace(
    val name: String,
    val kind: String,
    val x: Float,
    val y: Float
)

Yanda gizlemek ve göstermek

Durumun iki yarısı: isShownBeside geniş bir yerde, isOpenOver dar bir yerde ne gösterildiğini tutar; isShown o anki yerinkini okur. İkisi ayrıdır: pencere daralınca sheet kendiliğinden açılmaz.

"Geniş"te "Gizle"ye bas, sonra "Dar"a geç ve "Göster"e bas: sheet açılır. "Geniş"e dön: destek paneli yanda durur, isShownBeside yeniden "evet" olur. rememberSupportingPaneState(initiallyShownBeside = false) geniş bir yerde de kapalı başlatır.

val notes = rememberSupportingPaneState()
PantrixSupportingPaneScaffold(
    state = notes,
    main = {
        PaneSurface {
            Column(
                modifier = Modifier.padding(PantrixTheme.spacing.md),
                verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)
            ) {
                StateLines(this@PantrixSupportingPaneScaffold)
                Row(horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
                    PantrixButton(text = "Göster", onClick = { notes.show() }, tagKey = "notes_show")
                    PantrixButton(
                        text = "Gizle",
                        onClick = { notes.hide() },
                        variant = ButtonVariant.Outline,
                        tagKey = "notes_hide"
                    )
                }
            }
        }
    },
    supporting = {
        PaneSurface {
            PantrixText(
                text = "Notlar",
                modifier = Modifier.padding(PantrixTheme.spacing.md),
                style = PantrixTheme.typography.headline,
                tagKey = "notes_title"
            )
        }
    },
    modifier = Modifier.fillMaxWidth().height(SUPPORTING_EXAMPLE_HEIGHT),
    supportingTitle = "Notlar",
    tagKey = "notes"
)

@Composable
private fun StateLines(scope: SupportingPaneScope) {
    val state = scope.state
    listOf(
        "supportingPlace: ${scope.supportingPlace.name}",
        "isShown: ${yesNo(state.isShown)}",
        "isShownBeside: ${yesNo(state.isShownBeside)}",
        "isOpenOver: ${yesNo(state.isOpenOver)}"
    ).forEach { line ->
        PantrixText(text = line, style = PantrixTheme.typography.footnote, color = PantrixTheme.colors.textSecondary)
    }
}

@Composable
private fun PaneSurface(
    modifier: Modifier = Modifier,
    content: @Composable BoxScope.() -> Unit
) {
    PantrixSurface(modifier = modifier.fillMaxSize(), border = PantrixTheme.colors.border) { content() }
}

private val SUPPORTING_EXAMPLE_HEIGHT = 460.dp

private fun yesNo(value: Boolean): String = if (value) "evet" else "hayır"

Katlanan cihazda: kat yerinde ayrılır

Katlanan bir cihazda iki panel kat yerinde ayrılır. Her panel kendi ölçüsünü ve pencere sınıfını yazar.

"Kitap"ı seç: pencere 951dp, kat yeri dikey; ana içerik ve destek paneli kat yerinin iki yanında, aradaki boşluk kat yerinin iki yanındaki 20'şer dp'lik şerittir. "Masa"yı seç: kat yeri yataydır, ana içerik üstte, destek paneli altta. 669dp'lik pencere düz bir telefonda tek panel olurdu; masaya konmuş bir katlanabilirde iki panel olur.

İskele kat yerini kendi yerinde arar. "Masa"da kat yeri 951dp'lik pencerenin ortasındadır: örnek orada pencere kadar uzundur ki kat yeri onu kessin. Bir ekranda iskele zaten Modifier.fillMaxSize() ile bütün pencereyi alır.

val player = rememberSupportingPaneState()
val window = PantrixTheme.window
// Masaya konmuş bir katlanabilirde kat yeri pencerenin ortasındadır: örnek pencere kadar uzun olur.
val tall = if (window.posture.isTabletop) window.size.height else SUPPORTING_EXAMPLE_HEIGHT
PantrixSupportingPaneScaffold(
    state = player,
    main = { MeasuredPane(name = "Ana içerik", tagKey = "player_main_size") },
    supporting = { MeasuredPane(name = "Destek paneli", tagKey = "player_supporting_size") },
    modifier = Modifier.fillMaxWidth().height(tall),
    mainTitle = "Video",
    supportingTitle = "Denetimler",
    tagKey = "player"
)

@Composable
private fun MeasuredPane(
    name: String,
    tagKey: String
) {
    var size by remember { mutableStateOf(IntSize.Zero) }
    val density = LocalDensity.current
    val words = with(density) { "${size.width.toDp().value.roundToInt()} × ${size.height.toDp().value.roundToInt()}" }
    PaneSurface(modifier = Modifier.onSizeChanged { size = it }) {
        // Ölçüler soldan sağa yazılır: sağdan sola bir paragrafta genişlik ile yükseklik yer değiştirmiş okunurdu.
        CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
            PantrixText(
                // Panel kendi penceresidir: sınıfı panelin genişliğine göredir.
                text = "$name: $words dp · ${PantrixTheme.window.widthClass.name}",
                modifier = Modifier.align(Alignment.Center).padding(PantrixTheme.spacing.md),
                style = PantrixTheme.typography.footnote,
                color = PantrixTheme.colors.textSecondary,
                tagKey = tagKey
            )
        }
    }
}

private val SUPPORTING_EXAMPLE_HEIGHT = 460.dp

@Composable
private fun PaneSurface(
    modifier: Modifier = Modifier,
    content: @Composable BoxScope.() -> Unit
) {
    PantrixSurface(modifier = modifier.fillMaxSize(), border = PantrixTheme.colors.border) { content() }
}

API

state

Bir ekranın ana içeriği ve onu destekleyen bir panel: bir belge ve yorumları, bir grafik ve filtreleri, bir harita ve sonuçları. Yerde ikisine de yer varsa yan yana; yoksa ana içeriğin üstünde ya da yerinde.

ParametreTürVarsayılanNe olduğu
stateSupportingPaneStatedestek panelinin gösterilip gösterilmediği ve genişliği: rememberSupportingPaneState onu yapılandırma değişince de korur.
main@Composable SupportingPaneScope.() -> Unitekranın ana içeriği.
supporting@Composable SupportingPaneScope.() -> Unitonu destekleyen.
modifierModifierModifierpanellerin yeri.
mainTitleString?nullana içeriğin adı; görünür olurken ekran okuyucu için: "Rapor".
supportingTitleString?nulldestek panelinin adı: gösterildiği sheet'in başlığı ve görünür olurken ekran okuyucu için: "Yorumlar".
presentationSupportingPanePresentationSupportingPanePresentation.Sheetana içeriğin yanında yer olmadığında destek panelinin nasıl gösterildiği.
resizableBooleanfalseana içerik ile destek paneli arasındaki bir tutamacın destek panelini genişletip daraltmadığı.
styleSupportingPaneScaffoldStyle?nulliskelenin genişlikleri, temanınkilerin üstüne.
tagKeyString?nulliskelenin otomasyon etiketlerinin anahtarı.

SupportingPaneScaffoldStyle

PantrixSupportingPaneScaffold'un ölçüleri: destek panelinin ana içeriğin yanında ne kadar geniş olduğu, tutamacın sürüklenmesinin onu ve ana içeriği en çok ne kadar daraltabileceği ve tutamacın kendisi.

ParametreTürVarsayılanNe olduğu
supportingWidthDpDp.UnspecifiedDestek panelinin, tutamacı sürüklenene kadar ana içeriğin yanında ve yanında yer yokken gösterildiği yan sheet'te ne kadar geniş olduğu: bir telefonun genişliği, 360dp.
minSupportingWidthDpDp.UnspecifiedTutamacın sürüklenmesinin destek panelini en çok daraltabileceği genişlik.
minMainWidthDpDp.UnspecifiedAna içeriğin destek panelinin yanında en çok ne kadar daralabileceği: tutamacın sürüklenmesi ana içerik daha dar kalacağı yerde durur, ikisinin en dar hâline de yetmeyen bir yer destek panelini ana içeriğin üstünde gösterir.
gapDpDp.UnspecifiedPaneller arasında. Ön ayarlarda belirtilmemiştir: pencereyle büyüyen yerleşim oluğu, PantrixTheme.layout.gutter. Panelleri kenar kenara birleşen, aralarında kendi çizgisi olan bir marka 0dp verir.
handleWidthDpDp.UnspecifiedGenişliği değişebilen bir destek panelinin tutamacının boşlukta çizdiği işaret: kısa, dik bir çubuk.
handleHeightDpDp.UnspecifiedTutamacın dik çubuğunun ne kadar uzun olduğu: ne kadar kalın olduğu handleWidth'tir.
handleTargetDpDp.UnspecifiedBir parmağın ya da işaretçinin tutamacı yakaladığı şeridin genişliği; boşluğun ortasında durur, boşluk daha darsa panellerin kenarlarının üstüne taşar: parmak altında her platformun en küçük dokunma alanı, işaretçi altında dar bir şerit.