[React Native] Gesture Responder System

Với các ứng dụng mà việc xây dựng giao diện tầng tầng lớp lớp các view, trong khi đó yêu cầu của phần mềm các view chồng lên nhau này lại có những khả năng điều khiển sự kiện touch trên màn hình khác nhau. Vấn đề này luôn làm cho các lập trình viên phải đau đầu với những câu hỏi như: khi nào thì cho view này nhận được sự kiện? Khi nào thi cho view khác nhận sự kiện, khi nào thì view cha được nhận touch, khi nào thì view con nhận touch. Sau những câu hỏi khi nào là đến câu hỏi làm thế nào. Cách để giải quyết vấn đề này chưa bao giờ là đơn giản, và trước hết người lập trình viên cần phải nắm rõ được cách thức xử lý, vòng đời xử lý của một sự kiện, các phương thức, các thuộc tính đi kèm với sự kiện điều khiển để có thể đưa ra được phương án bắt sự kiện. Phần này sẽ đưa ra những hiểu biết cơ bản nhất về thuộc tính, phương thức và vòng đời của sự kiện thao tác trên màn hình trong React Native.

Hệ thống phản hồi cử chỉ sẽ quản lý vòng đời các cử chỉ trên ứng dụng của bạn. Một hành động chạm có thể sẽ trải qua nhiều giai đoạn để ứng dụng của bạn phát hiện được hành động mà người dùng mong muốn. Ví dụ, ứng dụng cần phát hiện ra việc chạm vào màn hình của người dùng đang phục vụ cho việc scrolling, sliding trên một widget, hay chỉ là tap vào màn hình. Điều này có thể bị thay đổi trong thời gian chạm trên màn hình. Hoặc cũng có thể quản lý việc multi touch trên màn hình.

Hệ thống phản hồi hành động chạm là cần thiết để cho phép các thành phần giao tiếp với nhau mà không cần biết việc thực thi đó trên các thành phần cha hay thành phần con. Hệ thống này được triển khai trong ResponderEventPlugin.js, trong đó đã bao hôm đầy đủ chi tiết và tài liệu.

Best Practices

Để tạo ra một ứng dụng tốt, mỗi một hành động nên tuân theo các thuộc tính sau:

  • Phản hồi/tạo điểm nhấn: cho người dùng biết rằng người dùng đang điều khiển việc chạm vào màn hình, và điều gì sẽ xảy ra khi người dùng kết thúc tương tác cử chỉ.
  • Có khả năng bỏ qua: khi tạo ra một hành động, người dùng nên có khả năng hủy nó bằng cách kéo ngón tay sang một chỗ bất kỳ khác.

Những đặc điểm này làm cho người người dùng có được sự thoải mái trong khi sử dụng ứng dung, bởi vì nó cho phép người có những trải nghiệm thú vụ mà không gặp phải bất kỳ sự nhầm lẫn nào.

TouchableHighlight và Touchable*

Hệ thống phản hồi có thể gặp phải sự phức tap khi sử dung. thế nên chúng tôi cung cấp một đối tượng trừu tượng Touchable để thực hiện những việc mà bạn muốn làm và nó nên sử dụng cho những thành phần "tappable". Sử dụng hệ thống phản hồi này cho phép bạn dễ dàng cấu hình để mô tả sự tượng tác của hành động tap. Sử dụng TouchableHighlight ở bất kỳ đâu, ở nơi mà bạn muốn sử dụng một button hay một link trên trang web.

Vòng đời của sự phản hồi

Một view có thể trở thành một đối tượng phản hồi của việc touch bằng cách implement đúng phương thức. có hai phưởng thức để cài đặt khi một view muốn phản hồi hành động chạm:

  • View.props.onStartShouldSetResponder: (evt) => true - Xác định view này có muốn phản hồi hành động chạm hay không.
  • View.props.onMoveShouldSetResponder: (evt) => true được gọi đến mỗi lần mà sự kiện chạm di chuyển trên view đó khi mà nó không phải là một reponder: xác định view này có yêu cầu cần phản hồi hành động touch hay không.

Nếu View trả về true và cố gắng để trở thành một responder, nó sẽ cần phải follow các vấn đề sau đây:

  • View.props.onResponderGrant: (evt) => {} View sẽ phản hồi ngay lập tức khi nhận sự kiện touch, và trong khoảng thời gian này view sẽ highlight để hiển thị cho người dùng biết điều gì đang xảy ra.
  • View.props.onResponderReject: (evt) => {} Trong một vài trường hợp, việc cài đặt này cho trường hợp sự kiện touch bị hủy.

Nếu view đang phản hồi, những phương thức sau có thể được gọi:

  • View.props.onResponderMove: (evt) => {} - Người dùng đang di chuyển ngón tay
  • View.props.onResponderRelease: (evt) => {} - Được gọi khi người dùng kết thúc hành đông touch "touchUp"
  • View.props.onResponderTerminationRequest: (evt) => true Một thành phần khác muốn có khả năng phản hồi. view đã không còn điều khiển việc phản hồi? Trả ra true để trả lại quyền phản hồi cho thành phần khác
  • View.props.onResponderTerminate: (evt) => {} Khả năng quản lý phản hồi đã được lấy từ View. điều này có nghĩa là nó lấy được quyền quản lý phản hồi từ một view khác sau khi thực hiện gọi onResponderTerminationRequest, hoặc bị lấy lại từ OS mà không cần hỏi (điều này xảy ra với control center/notification center trên iOS)

evt là một tổng hợp của các sự kiện với các thuộc tính sau:

  • nativeEvent
  • changedTouches - mảng của tất cả các hành động touch có sự thay đổi từ sự kiện cuối cùng
  • identifier ID của touch
  • locationX Tọa độ X của touch, liên quan đến thành phần
  • locationY Tọa độ Y của touch, liên quan đến thành phần
  • pageX Tọa độ X của touch, liên quan đến thành phần gốc
  • pageY Tọa độ Y của touch, liên quan đến thành phần gốc
  • target Node ID của thành phần nhận được hành động touch
  • timestamp khoảng thời gian của hành đông touch, thời gian này hữu dụng để tính được tốc độ di chuyển
  • touches Mảng của tất cả các touch hiện tại trên màn hình

Capture ShouldSet Handlers

onStartShouldSetResponderonMoveShouldSetResponder được gọi theo mô hình bubbling pattern, tức là tại node sâu nhất sẽ được gọi đầu tiên. Điều này có nghĩa là thành phần sâu nhất trở thành đối tượng quản lý phản hồi khi có nhiều View đều trả về true khi điều khiển với ShouldSetResponder. Trong hầu hết các trường hợp thì cài đặt này đều hữu dụng vì nó sẽ đảm bảo răng tất cả các thành phần đều có thể nhận được sự kiện touch.

Dù thế nào đi nữa, đôi khi thành phần cha sẽ muốn chắc chắn rằng nó có khả năng điều khiển phản hồi. Điều này có thể được điều khiển bằng cách bắt từng thành phần một để xử lý. Trước khi hệ thống phản hồi được trao đổi từ thành phần sâu nhất, nó sẽ tạo ra capture phase, đọc trong on*ShouldSetResponderCapture. Vậy nếu như View cha muốn ngăn chặn việc thành phần view con có thể nhận được và điều khiển hảnh động touch khi một touch là bắt đầu, nó nên có phương thức onStartShouldSetResponderCapture điều khiển và trả ra giá trị true.

  • View.props.onStartShouldSetResponderCapture: (evt) => true,
  • View.props.onMoveShouldSetResponderCapture: (evt) => true,

PanResponder

Để có thể điều khiển thao tác ở mức độ nâng cao hơn, các bạn có thể tham khảo thêm PanResponder

Lời kết Thực sự phần điều khiển hành động này có rất nhiều các thuộc tính, khải niệm mà để diễn giải ra được cần phải có sự trải nghiệm thực sự, cũng như có kinh nghiệm trong việc xử lý việc touch trong lập trình native. Bản thân mình khi dịch bài này cũng thấy có rất nhiều điều khó để diễn tả được bằng tiếng việt nên nội dung sẽ có nhiều hạn chế, các bạn sẽ vỡ ra được khi thực sự bắt tay vào làm và implement từng thuộc tính của nó. Dưới đây là tài liệu gốc, các bạn nên tham khảo cùng với bản dịch này để hiểu được rõ hơn về phần này. Có điều gì dịch sai, không rõ nghĩa mong các bạn góp ý.

Nguồn: Gesture Responder System


All Rights Reserved