ضربه بزنید و فشار دهید

بسیاری از composable ها دارای پشتیبانی داخلی برای ضربه زدن یا کلیک هستند و شامل onClick lambda هستند. به عنوان مثال، می توانید یک Surface قابل کلیک ایجاد کنید که شامل تمام رفتارهای طراحی متریال مناسب برای تعامل با سطوح باشد:

Surface(onClick = { /* handle click */ }) {
    Text("Click me!", Modifier.padding(24.dp))
}

اما کلیک ها تنها راهی نیستند که کاربر می تواند با composable ها تعامل داشته باشد. این صفحه روی حرکاتی متمرکز است که شامل یک اشاره گر هستند، جایی که موقعیت آن اشاره گر برای مدیریت آن رویداد مهم نیست. جدول زیر این نوع حرکات را فهرست می کند:

ژست

شرح

ضربه بزنید (یا کلیک کنید)

اشاره گر پایین و سپس بالا می رود

دو تا ضربه ی آهسته بزن

اشاره گر پایین، بالا، پایین، بالا می رود

فشار طولانی

اشاره گر پایین می آید و برای مدت طولانی تری نگه داشته می شود

مطبوعات

اشاره گر پایین می رود

به ضربه زدن یا کلیک کردن پاسخ دهید

clickable یک اصلاح کننده متداول است که باعث می شود یک ترکیب کننده به ضربه ها یا کلیک ها واکنش نشان دهد. این اصلاح‌کننده همچنین ویژگی‌های دیگری مانند پشتیبانی از فوکوس، شناور شدن ماوس و قلم، و یک نشانه بصری قابل تنظیم هنگام فشار دادن را اضافه می‌کند. اصلاح‌کننده به «کلیک‌ها» در وسیع‌ترین معنای کلمه پاسخ می‌دهد - نه تنها با ماوس یا انگشت، بلکه رویدادهای کلیک را از طریق ورودی صفحه‌کلید یا هنگام استفاده از سرویس‌های دسترس‌پذیری نیز انجام می‌دهد.

شبکه‌ای از تصاویر را تصور کنید، جایی که وقتی کاربر روی آن کلیک می‌کند، تصویری تمام صفحه نشان داده می‌شود:

برای اجرای این رفتار می توانید اصلاح کننده clickable را به هر مورد در شبکه اضافه کنید:

@Composable
private fun ImageGrid(photos: List<Photo>) {
    var activePhotoId by rememberSaveable { mutableStateOf<Int?>(null) }
    LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 128.dp)) {
        items(photos, { it.id }) { photo ->
            ImageItem(
                photo,
                Modifier.clickable { activePhotoId = photo.id }
            )
        }
    }
    if (activePhotoId != null) {
        FullScreenImage(
            photo = photos.first { it.id == activePhotoId },
            onDismiss = { activePhotoId = null }
        )
    }
}

اصلاح کننده clickable نیز رفتار اضافی را اضافه می کند:

  • interactionSource و indication ، که به طور پیش‌فرض هنگامی که کاربر روی composable ضربه می‌زند، یک موج می‌کشد. نحوه سفارشی کردن این موارد را در صفحه مدیریت تعاملات کاربر بیاموزید.
  • به سرویس‌های دسترس‌پذیری اجازه می‌دهد با تنظیم اطلاعات معنایی با عنصر تعامل داشته باشند.
  • از تعامل صفحه کلید یا جوی استیک با اجازه دادن به فوکوس و فشار دادن Enter یا مرکز d-pad برای تعامل پشتیبانی می کند.
  • عنصر را قابل شناور سازید، بنابراین به شناور شدن ماوس یا قلم روی آن پاسخ دهد.

برای نمایش منوی زمینه متنی، فشار طولانی دهید

combinedClickable به شما امکان می دهد تا رفتار دوبار ضربه یا فشار طولانی را علاوه بر رفتار کلیک معمولی اضافه کنید. وقتی کاربر تصویر شبکه ای را لمس می کند و نگه می دارد، می توانید از combinedClickable برای نشان دادن منوی زمینه استفاده کنید:

var contextMenuPhotoId by rememberSaveable { mutableStateOf<Int?>(null) }
val haptics = LocalHapticFeedback.current
LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 128.dp)) {
    items(photos, { it.id }) { photo ->
        ImageItem(
            photo,
            Modifier
                .combinedClickable(
                    onClick = { activePhotoId = photo.id },
                    onLongClick = {
                        haptics.performHapticFeedback(HapticFeedbackType.LongPress)
                        contextMenuPhotoId = photo.id
                    },
                    onLongClickLabel = stringResource(R.string.open_context_menu)
                )
        )
    }
}
if (contextMenuPhotoId != null) {
    PhotoActionsSheet(
        photo = photos.first { it.id == contextMenuPhotoId },
        onDismissSheet = { contextMenuPhotoId = null }
    )
}

به عنوان بهترین روش، زمانی که کاربر عناصر را به مدت طولانی فشار می دهد، باید بازخورد لمسی را وارد کنید، به همین دلیل است که قطعه شامل فراخوان performHapticFeedback است.

با ضربه زدن روی یک اسکریم، یک قابل ترکیب را رد کنید

در مثال‌های بالا، clickable و combinedClickable قابلیت‌های مفیدی را به فایل‌های ترکیبی شما اضافه می‌کنند. آنها یک نشانه بصری در تعامل نشان می دهند، به شناور شدن پاسخ می دهند و شامل فوکوس، صفحه کلید و پشتیبانی دسترسی هستند. اما این رفتار اضافی همیشه مطلوب نیست.

بیایید به صفحه جزئیات تصویر نگاه کنیم. پس‌زمینه باید نیمه شفاف باشد و کاربر باید بتواند روی آن پس‌زمینه ضربه بزند تا صفحه جزئیات را نادیده بگیرد:

در این مورد، آن پس‌زمینه نباید هیچ نشانه بصری در مورد تعامل داشته باشد، نباید به شناور بودن پاسخ دهد، نباید قابل فوکوس باشد و پاسخ آن به رویدادهای صفحه‌کلید و دسترسی متفاوت از یک ترکیب معمولی است. به جای تلاش برای تطبیق رفتار clickable ، می توانید به سطح انتزاعی پایین تری رها کنید و مستقیماً از اصلاح کننده pointerInput در ترکیب با متد detectTapGestures استفاده کنید:

@OptIn(ExperimentalComposeUiApi::class)
@Composable
private fun Scrim(onClose: () -> Unit, modifier: Modifier = Modifier) {
    val strClose = stringResource(R.string.close)
    Box(
        modifier
            // handle pointer input
            .pointerInput(onClose) { detectTapGestures { onClose() } }
            // handle accessibility services
            .semantics(mergeDescendants = true) {
                contentDescription = strClose
                onClick {
                    onClose()
                    true
                }
            }
            // handle physical keyboard input
            .onKeyEvent {
                if (it.key == Key.Escape) {
                    onClose()
                    true
                } else {
                    false
                }
            }
            // draw scrim
            .background(Color.DarkGray.copy(alpha = 0.75f))
    )
}

به عنوان کلید تغییر دهنده pointerInput لامبدا onClose را ارسال می کنید. این به طور خودکار لامبدا را مجدداً اجرا می‌کند، و مطمئن می‌شود که وقتی کاربر روی scrim ضربه می‌زند، تماس صحیح فراخوانی می‌شود.

برای بزرگنمایی دو ضربه سریع بزنید

گاهی اوقات clickable و combinedClickable دارای اطلاعات کافی برای پاسخگویی صحیح به تعامل نیستند. به عنوان مثال، کامپوزیشن‌ها ممکن است نیاز به دسترسی به موقعیتی در محدوده‌های ترکیب‌پذیر داشته باشند که در آن تعامل صورت گرفته است.

بیایید دوباره به صفحه جزئیات تصویر نگاه کنیم. بهترین روش این است که با دو ضربه زدن روی تصویر بزرگنمایی کنید:

همانطور که در ویدیو می بینید، بزرگنمایی در اطراف موقعیت رویداد ضربه زدن انجام می شود. نتیجه زمانی متفاوت است که روی قسمت چپ تصویر در مقابل قسمت سمت راست بزرگنمایی کنیم. می‌توانیم از اصلاح‌کننده pointerInput در ترکیب با detectTapGestures استفاده کنیم تا موقعیت ضربه را در محاسبات خود بگنجانیم:

var zoomed by remember { mutableStateOf(false) }
var zoomOffset by remember { mutableStateOf(Offset.Zero) }
Image(
    painter = rememberAsyncImagePainter(model = photo.highResUrl),
    contentDescription = null,
    modifier = modifier
        .pointerInput(Unit) {
            detectTapGestures(
                onDoubleTap = { tapOffset ->
                    zoomOffset = if (zoomed) Offset.Zero else
                        calculateOffset(tapOffset, size)
                    zoomed = !zoomed
                }
            )
        }
        .graphicsLayer {
            scaleX = if (zoomed) 2f else 1f
            scaleY = if (zoomed) 2f else 1f
            translationX = zoomOffset.x
            translationY = zoomOffset.y
        }
)

{% کلمه به کلمه %} {% آخر کلمه %} {% کلمه به کلمه %} {% آخر کلمه %}