Nhiều thành phần kết hợp có hỗ trợ tích hợp cho thao tác nhấn hoặc nhấp và bao gồm
Hàm lambda onClick
. Ví dụ: bạn có thể tạo một Surface
nhấp vào được
bao gồm mọi hành vi của Material Design phù hợp để tương tác với các nền tảng:
Surface(onClick = { /* handle click */ }) { Text("Click me!", Modifier.padding(24.dp)) }
Tuy nhiên, lượt nhấp không phải là cách duy nhất mà người dùng có thể tương tác với các thành phần kết hợp. Trang này tập trung vào các cử chỉ liên quan đến một con trỏ, trong đó vị trí của con trỏ đó không quan trọng đối với việc xử lý sự kiện đó. Nội dung sau đây bảng liệt kê các loại cử chỉ sau:
Cử chỉ |
Mô tả |
Nhấn (hoặc nhấp) |
Con trỏ đi xuống rồi lên |
Nhấn đúp |
Con trỏ đi xuống, lên, xuống, lên trên |
Nhấn và giữ |
Con trỏ rơi xuống và được giữ lâu hơn |
Hình ảnh trên báo chí |
Con trỏ đi xuống |
Phản hồi khi người dùng nhấn hoặc nhấp
clickable
là một đối tượng sửa đổi thường dùng giúp thành phần kết hợp phản ứng với
nhấn hoặc nhấp. Công cụ sửa đổi này cũng thêm các tính năng bổ sung, chẳng hạn như hỗ trợ cho
tiêu điểm, thao tác di chuột bằng chuột và bút cảm ứng cũng như chỉ báo hình ảnh có thể tuỳ chỉnh khi
nhấn. Đối tượng sửa đổi phản hồi "lượt nhấp" theo nghĩa rộng nhất của từ này-- không phải
chỉ bằng chuột hoặc ngón tay, nhưng cũng có thể nhấp các sự kiện thông qua phương thức nhập bằng bàn phím hoặc khi
thông qua các dịch vụ hỗ trợ tiếp cận.
Hãy tưởng tượng một lưới hình ảnh, trong đó hình ảnh hiển thị toàn màn hình khi người dùng nhấp vào đó:
Bạn có thể thêm đối tượng sửa đổi clickable
vào từng mục trong lưới để triển khai việc này
hành vi:
@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 } ) } }
Đối tượng sửa đổi clickable
cũng bổ sung hành vi bổ sung:
interactionSource
vàindication
, vẽ một hiệu ứng gợn sóng theo mặc định khi người dùng nhấn vào thành phần kết hợp. Tìm hiểu cách tuỳ chỉnh các thông tin này trong bài viết Xử lý người dùng lượt tương tác.- Cho phép các dịch vụ hỗ trợ tiếp cận tương tác với phần tử này bằng cách đặt giá trị thông tin ngữ nghĩa.
- Hỗ trợ tương tác với bàn phím hoặc cần điều khiển bằng cách cho phép lấy nét và nhấn
Enter
hoặc phần giữa của d-pad để tương tác. - Đặt thành phần có thể di chuột để phản hồi với thao tác di chuột hoặc bút cảm ứng ghi đè lên nội dung đó.
Nhấn và giữ để hiện trình đơn theo bối cảnh
combinedClickable
cho phép bạn thêm hành vi nhấn đúp hoặc nhấn và giữ trong
ngoài hành vi nhấp chuột thông thường. Bạn có thể sử dụng combinedClickable
để hiển thị
trình đơn theo bối cảnh khi người dùng chạm và giữ một hình ảnh ở dạng lưới:
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 } ) }
Tốt nhất là bạn nên thêm phản hồi xúc giác khi người dùng
nhấn và giữ các phần tử, đó là lý do tại sao đoạn mã bao gồm
Lệnh gọi performHapticFeedback
.
Đóng thành phần kết hợp bằng cách nhấn vào một màn hình
Trong các ví dụ trên, clickable
và combinedClickable
thêm phần hữu ích
cho các thành phần kết hợp. Chúng cho thấy chỉ báo trực quan
về sự tương tác,
phản hồi thao tác di chuột và bao gồm tiêu điểm, bàn phím và hỗ trợ tiếp cận. Nhưng
hành vi bổ sung này không phải lúc nào cũng được mong muốn.
Hãy xem màn hình chi tiết hình ảnh. Nền phải là bán trong suốt và người dùng có thể nhấn vào nền đó để đóng màn hình chi tiết:
Trong trường hợp này, nền đó không được có bất kỳ chỉ báo trực quan nào
tương tác, không được phản hồi với thao tác di chuột, không nên đặt làm tâm điểm và
Phản hồi với bàn phím và các sự kiện hỗ trợ tiếp cận khác với phản hồi của
thành phần kết hợp. Thay vì cố gắng điều chỉnh hành vi của clickable
, bạn có thể thả
xuống mức độ trừu tượng thấp hơn và trực tiếp sử dụng đối tượng sửa đổi pointerInput
kết hợp với phương thức detectTapGestures
:
@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)) ) }
Là khoá của đối tượng sửa đổi pointerInput
, bạn truyền hàm lambda onClose
. Chiến dịch này
tự động thực thi lại hàm lambda, đảm bảo gọi lệnh gọi lại phù hợp
khi người dùng nhấn vào màn hình.
Nhấn đúp để thu phóng
Đôi khi clickable
và combinedClickable
không bao gồm đủ thông tin
để phản hồi tương tác theo đúng cách. Ví dụ: thành phần kết hợp có thể
cần quyền truy cập vào vị trí trong giới hạn của thành phần kết hợp nơi lượt tương tác
đã diễn ra.
Hãy xem lại màn hình chi tiết hình ảnh. Phương pháp hay nhất là làm cho có thể phóng to hình ảnh bằng cách nhấn đúp:
Như bạn có thể thấy trong video, thao tác phóng to diễn ra xung quanh vị trí nhấn
sự kiện. Kết quả sẽ khác khi chúng ta phóng to phần bên trái của hình ảnh
so với phần bên phải. Chúng ta có thể sử dụng kết hợp đối tượng sửa đổi pointerInput
bằng detectTapGestures
để kết hợp vị trí nhấn vào
phép tính:
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 } )
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- Tìm hiểu về cử chỉ
- Material Design 2 trong Compose
- Kotlin cho Jetpack Compose