Các phần sau đây giải thích một số khái niệm chính đối với quy trình kéo và thả.
Quá trình kéo và thả
Có 4 bước hoặc trạng thái trong quá trình kéo và thả: bắt đầu, tiếp tục, đã bỏ và kết thúc.
- Started (Đã khởi động)
Để phản hồi cử chỉ kéo của người dùng, ứng dụng sẽ gọi
startDragAndDrop()
để yêu cầu hệ thống bắt đầu thao tác kéo và thả. Các đối số của phương thức cung cấp như sau:- Dữ liệu cần kéo.
- Lệnh gọi lại để vẽ bóng khi kéo
- Siêu dữ liệu mô tả dữ liệu đã kéo
- Hệ thống sẽ phản hồi bằng cách gọi lại ứng dụng của bạn để lấy bóng khi kéo. Sau đó, hệ thống sẽ hiển thị bóng khi kéo trên thiết bị.
- Tiếp theo, hệ thống sẽ gửi một sự kiện kéo có loại thao tác
ACTION_DRAG_STARTED
đến trình nghe sự kiện kéo của tất cả các đối tượngView
trong bố cục hiện tại. Để tiếp tục nhận các sự kiện kéo (bao gồm cả một sự kiện thả có thể xảy ra), trình nghe sự kiện kéo phải trả vềtrue
. Thao tác này sẽ đăng ký trình nghe với hệ thống. Chỉ những trình nghe đã đăng ký mới tiếp tục nhận được các sự kiện kéo. Tại thời điểm này, trình nghe cũng có thể thay đổi giao diện của đối tượngView
mục tiêu thả để cho thấy rằng khung hiển thị có thể chấp nhận một sự kiện thả. - Nếu trình nghe sự kiện kéo trả về
false
, trình nghe đó sẽ không nhận được các sự kiện kéo cho thao tác hiện tại cho đến khi hệ thống gửi một sự kiện kéo có loại thao tácACTION_DRAG_ENDED
. Khi trả vềfalse
, trình nghe sẽ cho hệ thống biết rằng nó không quan tâm đến thao tác kéo và thả cũng như không muốn chấp nhận dữ liệu đã kéo.
- Đang tiếp tục
- Người dùng tiếp tục kéo. Khi bóng khi kéo giao với hộp giới hạn của mục tiêu thả, hệ thống sẽ gửi một hoặc nhiều sự kiện kéo đến trình nghe sự kiện kéo của mục tiêu. Trình nghe có thể thay đổi giao diện của mục tiêu thả
View
để phản hồi sự kiện. Ví dụ: nếu sự kiện cho biết rằng bóng khi kéo vào hộp giới hạn của mục tiêu thả (loại hành độngACTION_DRAG_ENTERED
), thì trình nghe có thể phản ứng bằng cách làm nổi bậtView
. - Thả
- Người dùng thả bóng khi kéo trong hộp giới hạn của mục tiêu thả. Hệ thống sẽ gửi trình nghe của mục tiêu thả một sự kiện kéo có loại thao tác
ACTION_DROP
. Đối tượng sự kiện kéo chứa dữ liệu truyền đến hệ thống trong lệnh gọistartDragAndDrop()
để bắt đầu thao tác. Trình nghe dự kiến sẽ trả về booleantrue
cho hệ thống nếu trình nghe xử lý thành công dữ liệu được thả. : Bước này chỉ xảy ra nếu người dùng thả bóng khi kéo trong hộp giới hạn củaView
có trình nghe đã được đăng ký để nhận sự kiện kéo (mục tiêu thả). Nếu người dùng thả bóng khi kéo trong bất kỳ tình huống nào khác, thì sẽ không có sự kiện kéoACTION_DROP
nào được gửi. - Đã kết thúc
Sau khi người dùng thả bóng khi kéo và sau khi hệ thống gửi
một sự kiện kéo có loại thao tác
ACTION_DROP
, nếu cần, hệ thống sẽ gửi một sự kiện kéo có loại thao tácACTION_DRAG_ENDED
để cho biết thao tác kéo và thả đã kết thúc. Việc này được thực hiện bất kể người dùng thả bóng khi kéo ở đâu. Sự kiện này được gửi đến mọi trình nghe được đăng ký để nhận sự kiện kéo, ngay cả khi trình nghe cũng nhận được sự kiệnACTION_DROP
.
Từng bước này được mô tả chi tiết hơn trong phần có tên là Thao tác kéo và thả.
Sự kiện kéo
Hệ thống sẽ gửi một sự kiện kéo dưới dạng đối tượng DragEvent
, chứa loại thao tác mô tả những gì đang xảy ra trong quá trình kéo và thả. Tuỳ thuộc vào loại thao tác mà đối tượng cũng có thể chứa dữ liệu khác.
Trình nghe sự kiện kéo sẽ nhận đối tượng DragEvent
. Để biết loại thao tác, trình nghe gọi DragEvent.getAction()
.
Có 6 giá trị có thể được xác định bằng các hằng số trong lớp DragEvent
, như mô tả trong bảng 1:
Loại thao tác | Ý nghĩa |
---|---|
ACTION_DRAG_STARTED |
Ứng dụng gọi startDragAndDrop() và thu được bóng khi kéo. Nếu muốn tiếp tục nhận các sự kiện kéo cho thao tác này, trình nghe phải trả về giá trị boolean true cho hệ thống.
|
ACTION_DRAG_ENTERED |
Bóng khi kéo vào hộp giới hạn của View của trình nghe sự kiện kéo. Đây là loại thao tác sự kiện đầu tiên mà trình nghe nhận được khi bóng khi kéo vào hộp giới hạn.
|
ACTION_DRAG_LOCATION |
Sau sự kiện ACTION_DRAG_ENTERED , bóng đổ vẫn nằm trong hộp giới hạn của View của trình nghe sự kiện kéo.
|
ACTION_DRAG_EXITED |
Sau ACTION_DRAG_ENTERED và ít nhất một sự kiện ACTION_DRAG_LOCATION , bóng khi kéo sẽ di chuyển ra bên ngoài hộp giới hạn của View của trình nghe sự kiện kéo.
|
ACTION_DROP |
Bóng khi kéo được thả qua View của trình nghe sự kiện kéo. Loại thao tác này chỉ được gửi đến trình nghe của đối tượng View nếu trình nghe trả về boolean true để phản hồi sự kiện kéo ACTION_DRAG_STARTED . Loại thao tác này sẽ không được gửi nếu người dùng thả bóng khi kéo trên View có trình nghe chưa đăng ký, hoặc nếu người dùng thả bóng khi kéo trên bất kỳ phần tử nào không thuộc bố cục hiện tại.
Trình nghe sẽ trả về giá trị boolean |
ACTION_DRAG_ENDED |
Hệ thống đang kết thúc thao tác kéo và thả. Loại hành động này không nhất thiết phải đứng sau sự kiện ACTION_DROP . Nếu hệ thống gửi một ACTION_DROP , thì việc nhận được loại thao tác ACTION_DRAG_ENDED không có nghĩa là việc giảm đã thành công. Trình nghe phải gọi getResult() , như minh hoạ trong bảng 2 để nhận giá trị được trả về trong phản hồi ACTION_DROP . Nếu sự kiện ACTION_DROP không được gửi, thì getResult() sẽ trả về false .
|
Đối tượng DragEvent
cũng chứa dữ liệu và siêu dữ liệu mà ứng dụng của bạn cung cấp cho hệ thống trong lệnh gọi đến startDragAndDrop()
. Một số dữ liệu chỉ hợp lệ cho một số loại hành động nhất định được tóm tắt trong bảng 2. Để biết thêm thông tin về các sự kiện và dữ liệu liên quan, hãy xem phần Thao tác kéo và thả.
Giá trị getAction() |
Giá trị getClipDescription() |
Giá trị getLocalState() |
Giá trị getX() |
Giá trị getY() |
Giá trị getClipData() |
Giá trị getResult() |
---|---|---|---|---|---|---|
ACTION_DRAG_STARTED |
✓ | ✓ | ||||
ACTION_DRAG_ENTERED |
✓ | ✓ | ||||
ACTION_DRAG_LOCATION |
✓ | ✓ | ✓ | ✓ | ||
ACTION_DRAG_EXITED |
✓ | ✓ | ||||
ACTION_DROP |
✓ | ✓ | ✓ | ✓ | ✓ | |
ACTION_DRAG_ENDED |
✓ | ✓ |
Các phương thức DragEvent
getAction()
, describeContents()
, writeToParcel()
và toString()
luôn trả về dữ liệu hợp lệ.
Nếu một phương thức không chứa dữ liệu hợp lệ cho một loại thao tác cụ thể, thì phương thức đó sẽ trả về null
hoặc 0, tuỳ thuộc vào loại kết quả.
Bóng khi kéo
Trong khi thực hiện thao tác kéo và thả, hệ thống sẽ hiển thị một hình ảnh mà người dùng kéo. Đối với di chuyển dữ liệu, hình ảnh này đại diện cho dữ liệu đang được kéo. Đối với các thao tác khác, hình ảnh đại diện cho một số chương trình thành phần của thao tác kéo.
Hình ảnh này được gọi là đổ bóng khi kéo. Bạn tạo lớp này bằng các phương thức bạn khai báo cho đối tượng View.DragShadowBuilder
. Bạn truyền trình tạo đến hệ thống khi bắt đầu thao tác kéo và thả bằng startDragAndDrop()
. Để phản hồi startDragAndDrop()
, hệ thống gọi các phương thức gọi lại mà bạn xác định trong View.DragShadowBuilder
để lấy bóng khi kéo.
Lớp View.DragShadowBuilder
có hai hàm khởi tạo (constructor):
View.DragShadowBuilder(View)
Hàm khởi tạo này chấp nhận mọi đối tượng
View
của ứng dụng. Hàm khởi tạo lưu trữ đối tượngView
trong đối tượngView.DragShadowBuilder
, vì vậy, các lệnh gọi lại có thể truy cập vào đối tượng đó để tạo bóng khi kéo. Khung hiển thị không nhất thiết phải làView
mà người dùng chọn để bắt đầu thao tác kéo.Nếu sử dụng hàm khởi tạo này, bạn không cần phải mở rộng
View.DragShadowBuilder
hoặc ghi đè phương thức của hàm khởi tạo. Theo mặc định, bạn sẽ nhận được một bóng khi kéo có hình thức giống vớiView
mà bạn truyền dưới dạng đối số, nằm ở giữa vị trí người dùng chạm vào màn hình.View.DragShadowBuilder()
Nếu bạn sử dụng hàm khởi tạo này, sẽ không có đối tượng
View
nào trong đối tượngView.DragShadowBuilder
. Trường này đã được đặt thànhnull
. Bạn phải mở rộngView.DragShadowBuilder
và ghi đè các phương thức, nếu không, bạn sẽ nhận được bóng khi kéo vô hình. Hệ thống không báo lỗi.
Lớp View.DragShadowBuilder
có 2 phương thức cùng tạo bóng khi kéo:
onProvideShadowMetrics()
Hệ thống sẽ gọi phương thức này ngay sau khi bạn gọi
startDragAndDrop()
. Sử dụng phương thức để gửi kích thước và điểm chạm của bóng khi kéo đến hệ thống. Phương thức có hai tham số:outShadowSize
: đối tượngPoint
. Chiều rộng bóng khi kéo được truyền vàox
và chiều cao của bóng được truyền vàoy
.outShadowTouchPoint
: đối tượngPoint
. Điểm chạm là vị trí bên trong bóng khi kéo và phải nằm dưới ngón tay của người dùng trong khi kéo. Vị trí X của thiết bị nằm trongx
và vị trí Y của thiết bị nằm trongy
.onDrawShadow()
Ngay sau khi gọi
onProvideShadowMetrics()
, hệ thống sẽ gọionDrawShadow()
để tạo bóng khi kéo. Phương thức này có một đối số duy nhất, đối tượngCanvas
mà hệ thống tạo từ các tham số bạn cung cấp trongonProvideShadowMetrics()
. Phương thức này sẽ vẽ bóng khi kéo trênCanvas
được cung cấp.
Để cải thiện hiệu suất, hãy giữ cho kích thước của bóng khi kéo nhỏ. Đối với một mục riêng lẻ, bạn nên sử dụng biểu tượng. Để chọn nhiều mục, bạn nên sử dụng các biểu tượng trong một ngăn xếp thay vì hình ảnh đầy đủ trải rộng trên màn hình.
Trình nghe sự kiện kéo và phương thức gọi lại
View
nhận các sự kiện kéo bằng trình nghe sự kiện kéo giúp triển khai View.OnDragListener
hoặc bằng phương thức gọi lại onDragEvent()
của khung hiển thị. Khi gọi phương thức hoặc trình nghe, hệ thống sẽ cung cấp một đối số DragEvent
.
Trong hầu hết trường hợp, bạn nên sử dụng trình nghe thay vì phương thức gọi lại. Khi thiết kế giao diện người dùng, bạn thường không phân lớp các lớp View
, nhưng khi sử dụng phương thức gọi lại, bạn sẽ phải tạo các lớp con để ghi đè phương thức. Khi so sánh, bạn có thể triển khai một lớp trình nghe rồi sử dụng lớp đó với nhiều đối tượng View
riêng biệt. Bạn cũng có thể triển khai phương thức này dưới dạng một lớp cùng dòng hoặc biểu thức lambda ẩn danh. Để thiết lập trình nghe cho đối tượng View
, hãy gọi setOnDragListener()
.
Ngoài ra, bạn có thể thay đổi cách triển khai mặc định của onDragEvent()
mà không cần ghi đè phương thức. Đặt OnReceiveContentListener
trên một khung hiển thị; để biết thêm thông tin chi tiết, hãy xem setOnReceiveContentListener()
.
Sau đó, phương thức onDragEvent()
sẽ thực hiện những việc sau theo mặc định:
- Trả về giá trị true (đúng) cho lệnh gọi đến
startDragAndDrop()
. Gọi
performReceiveContent()
nếu dữ liệu kéo và thả được thả vào khung hiển thị. Dữ liệu được truyền đến phương thức dưới dạng đối tượngContentInfo
. Phương thức này sẽ gọiOnReceiveContentListener
.Trả về giá trị true nếu dữ liệu kéo và thả được thả vào khung hiển thị và
OnReceiveContentListener
sử dụng bất kỳ nội dung nào.
Xác định OnReceiveContentListener
để xử lý dữ liệu dành riêng cho ứng dụng của bạn. Để tương thích ngược xuống API cấp 24, hãy sử dụng phiên bản Jetpack của OnReceiveContentListener
.
Bạn có thể có trình nghe sự kiện kéo và phương thức gọi lại cho đối tượng View
, trong trường hợp này, hệ thống sẽ gọi trình nghe trước tiên. Hệ thống sẽ không gọi phương thức gọi lại trừ phi trình nghe trả về false
.
Tổ hợp phương thức onDragEvent()
và View.OnDragListener
tương tự như tổ hợp onTouchEvent()
và View.OnTouchListener
dùng với các sự kiện chạm.