Các khái niệm quan trọng

Các phần sau đây giải thích một số khái niệm chính về quy trình kéo và thả.

Quy 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ỏ qua 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 của bạn sẽ gọi startDragAndDrop() để yêu cầu hệ thống bắt đầu thao tác kéo và thả. Chiến lược phát hành đĩa đơn các đối số của phương thức cung cấp những nội dung 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 để yêu cầu kéo bóng. 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 kèm theo loại thao tác ACTION_DRAG_STARTED đến sự kiện kéo trình nghe của tất cả đối tượng View trong bố cục hiện tại. Người nhận tiếp tục nhận được các sự kiện kéo—bao gồm cả khả năng thả sự kiện – trình nghe sự kiện kéo phải trả về true. Thanh ghi này trình nghe cùng với hệ thống. Chỉ những người nghe đã đăng ký mới tiếp tục nhận các sự kiện kéo. Tại thời điểm này, người nghe cũng có thể thay đổi của đối tượng View đích thả để cho thấy rằng thành phần hiển thị này có thể chấp nhận sự kiện thả.
  • Nếu trình nghe sự kiện kéo trả về false, thì trình nghe sự kiện kéo này sẽ không nhận được thao tác kéo các sự kiện cho thao tác hiện tại cho đến khi hệ thống gửi sự kiện kéo với loại hành động ACTION_DRAG_ENDED. Khi trả về false, trình nghe sẽ cho hệ thống biết rằng ứng dụng không quan tâm trong thao tác kéo và thả và 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 bóng khi kéo đi vào hộp giới hạn của hộp thả loại hành động mục tiêu ACTION_DRAG_ENTERED — trình nghe có thể phản ứng bằng cách làm nổi bật View.
Thả
Người dùng thả bóng khi kéo trong hộp giới hạn của hộp thả . Hệ thống gửi một sự kiện kéo kèm theo thao tác cho trình nghe của mục tiêu thả loại ACTION_DROP. Đối tượng sự kiện kéo chứa dữ liệu truyền đến hệ thống trong gọi đến startDragAndDrop() để bắt đầu thao tác. Trình nghe là dự kiến sẽ trả về giá trị boolean true cho hệ thống nếu trình nghe thành công xử lý 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ủa View có trình nghe được đăng ký để nhận các 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ỳ không có sự kiện kéo ACTION_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 bằng 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ác ACTION_DRAG_ENDED để cho biết rằng thao tác kéo và thả đã kết thúc. Thực hiện việc này bất kể người dùng đang ở đâu thả bóng khi kéo. Sự kiện này sẽ được gửi đến mọi trình nghe đã đăng ký nhận các sự kiện kéo, ngay cả khi trình nghe cũng nhận được Sự kiện ACTION_DROP.

Mỗi bước trong số 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ạng đối tượng DragEvent. Sự kiện này chứa loại thao tác mô tả những gì sẽ diễn ra trong thao tác kéo và thả của chúng tôi. 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, được mô tả trong bảng 1:

Bảng 1. Các loại thao tác sự kiện kéo

Loại thao tác Ý nghĩa
ACTION_DRAG_STARTED Ứng dụng gọi startDragAndDrop() và nhận bóng khi kéo. Nếu trình nghe muốn tiếp tục nhận các sự kiện kéo cho thao tác này, nó phải trả về giá trị boolean true cho hệ thống.
ACTION_DRAG_ENTERED Bóng khi kéo đi vào hộp giới hạn của View. Đâ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 đi vào hộp giới hạn.
ACTION_DRAG_LOCATION Sau một ACTION_DRAG_ENTERED sự kiện, bóng khi kéo vẫn là trong hộp giới hạn của trình nghe sự kiện kéo View
ACTION_DRAG_EXITED Đang theo dõi ACTION_DRAG_ENTERED và ít nhất một Sự kiện ACTION_DRAG_LOCATION, bóng khi kéo sẽ di chuyển bên ngoài hộp giới hạn của trình nghe sự kiện kéo View.
ACTION_DROP Bóng khi kéo thả ra trên trình nghe sự kiện kéo View. Loại thao tác này được gửi đến View trình nghe của đối tượng chỉ khi trình nghe trả về boolean true để phản hồi Sự kiện kéo ACTION_DRAG_STARTED. Loại hành động này 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 được đăng ký hoặc nếu người dùng thả thao tác kéo đổ bóng lên bất kỳ mục nào không thuộc bố cục hiện tại.

Trình nghe sẽ trả về giá trị boolean true nếu đã xử lý thành công sự kiện thả. Nếu không, giá trị này phải trả về false.

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 sẽ gửi một ACTION_DROP, nhận Loại hành động ACTION_DRAG_ENDED không ngụ ý rằng thả 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ề nhằm phản hồi ACTION_DROP. Nếu một ACTION_DROP sự kiện chưa được gửi, sau đó getResult() 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 là chỉ hợp lệ đối với một số loại hành động nhất định 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 có tên là A thao tác kéo và thả.

Bảng 2. Dữ liệu DragEvent hợp lệ theo loại thao tác

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() thân mến! và toString() luôn sẽ trả về dữ liệu hợp lệ.

Nếu 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 suốt thao tác kéo và thả, hệ thống sẽ hiển thị 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 ứng dụng bằng các phương thức mà bạn khai báo một View.DragShadowBuilder . Bạn truyền trình tạo đến hệ thống khi bắt đầu kéo và thả bằng startDragAndDrop(). Để phản hồi lại startDragAndDrop(), hệ thống sẽ 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ượng View trong đối tượng View.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. Chế độ xem 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ẽ chọn thao tác kéo bóng có cùng hình thức với View mà bạn truyền dưới dạng đối số, chính giữa bên dưới 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ượng View.DragShadowBuilder. Trường này được đặt thành null. Bạn phải mở rộng View.DragShadowBuilder rồi ghi đè các phương thức của đối tượng đó, 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 để tạo ra thao tác kéo bóng:

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: Point . Chiều rộng của bóng khi kéo là x và chiều cao của nó tương ứng với y.

outShadowTouchPoint: đối tượng Point. Điểm tiếp xúc là vị trí trong bóng khi kéo phải ở dưới ngón tay của người dùng trong khi kéo. Vị trí X của tín hiệu tương ứng với x và vị trí Y rơi vào y.

onDrawShadow()

Ngay sau khi gọi onProvideShadowMetrics(), hệ thống sẽ gọi onDrawShadow() để tạo bóng khi kéo. Phương thức này có một đối số, một đối tượng Canvas hệ thống xây dựng từ các tham số mà bạn cung cấp trong onProvideShadowMetrics(). Phương thức này sẽ vẽ bóng khi kéo trên Canvas.

Để cải thiện hiệu suất, hãy giữ kích thước của bóng khi kéo nhỏ. Cho một người độc thân bạn nên sử dụng biểu tượng. Để chọn nhiều mục, bạn có thể muốn sử dụng các biểu tượng trong một ngăn xếp thay vì hình ảnh toàn bộ 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 để triển khai View.OnDragListener hoặc bằng phương thức gọi lại onDragEvent() của khung hiển thị. Thời gian hệ thống gọi phương thức hoặc trình nghe, nó 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 lớp này dưới dạng một lớp cùng dòng ẩn danh hoặc biểu thức lambda. Để thiết lập trình nghe cho đối tượng View, hãy gọi setOnDragListener()

Thay vào đó, 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 một OnReceiveContentListener trên một khung hiển thị; để biết thêm chi tiết, hãy xem setOnReceiveContentListener(). Sau đó, phương thức onDragEvent() sẽ thực hiện những thao tác sau theo mặc định:

  • Trả về giá trị true để phản hồi lệnh gọi đến startDragAndDrop().
  • Cuộc gọi performReceiveContent() nếu dữ liệu kéo và thả được thả vào khung hiển thị. Dữ liệu được chuyển đến làm đối tượng ContentInfo. Chiến lược phát hành đĩa đơn sẽ gọi OnReceiveContentListener.

  • Trả về 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 . Để có khả năng tương thích ngược xuống đến API cấp 24, hãy sử dụng phiên bản Jetpack OnReceiveContentListener.

Bạn có thể có một trình nghe sự kiện kéo và phương thức gọi lại cho đối tượng View trong trong trường hợp này, hệ thống sẽ gọi trình nghe trước tiên. Hệ thống không gọi hàm trừ phi trình nghe trả về false.

Tổ hợp phương thức onDragEvent()View.OnDragListener là tương tự như sự kết hợp của onTouchEvent()View.OnTouchListener được dùng với các sự kiện chạm.