Trình chỉnh sửa văn bản tuỳ chỉnh

Trình chỉnh sửa văn bản tuỳ chỉnh là các khung hiển thị không phải là thành phần EditText hoặc tiện ích văn bản WebView nhưng vẫn hỗ trợ nhập văn bản bằng cách triển khai lệnh gọi lại onCreateInputConnection(). Lệnh gọi lại này được gọi khi một khung hiển thị được lấy làm tâm điểm và hệ thống yêu cầu một InputConnection cho khung hiển thị đó.

Lệnh gọi đến onCheckIsTextEditor() từ trình chỉnh sửa văn bản tuỳ chỉnh sẽ trả về true.

Hỗ trợ tính năng viết tay bằng bút cảm ứng trong trình chỉnh sửa văn bản tuỳ chỉnh

Theo mặc định, Android 14 (API cấp 34) trở lên hỗ trợ phương thức nhập bằng bút cảm ứng trong các thành phần nhập văn bản tiêu chuẩn của Android (xem nội dung Nhập bằng bút cảm ứng trong trường văn bản). Tuy nhiên, các trường nhập văn bản tuỳ chỉnh (hoặc trình chỉnh sửa) cần phải phát triển thêm.

Để tạo trình chỉnh sửa văn bản tuỳ chỉnh, hãy làm như sau:

  1. Bật tính năng bắt đầu viết tay
  2. Khai báo chức năng hỗ trợ chữ viết tay
  3. Hỗ trợ cử chỉ viết tay (chọn, xoá, chèn, v.v.)
  4. Cung cấp vị trí con trỏ và các dữ liệu khác về vị trí cho IME
  5. Hiện biểu tượng di chuột qua chữ viết tay của bút cảm ứng

Bật tính năng bắt đầu viết tay

Nếu khung hiển thị chỉ bao gồm một trình chỉnh sửa văn bản, thì hệ thống khung hiển thị có thể tự động bắt đầu viết tay bằng bút cảm ứng cho khung hiển thị. Nếu không, khung hiển thị phải triển khai logic khởi tạo chữ viết tay riêng.

Tạo chữ viết tay tự động

Nếu một khung hiển thị chỉ hiện một trình chỉnh sửa văn bản và không có nội dung nào khác, thì khung hiển thị đó có thể chọn bắt đầu chữ viết tay tự động của hệ thống khung hiển thị bằng cách gọi setAutoHandwritingEnabled(true).

Khi bật tính năng tự động viết tay, chuyển động của bút cảm ứng bắt đầu từ bất kỳ vị trí nào trong giới hạn viết tay của chế độ xem sẽ tự động bắt đầu chế độ viết tay. Trình chỉnh sửa phương thức nhập (IME) nhận các sự kiện chuyển động của bút cảm ứng và xác nhận văn bản đã nhận dạng.

Trường nhập dữ liệu có hình chữ nhật bao quanh cho biết các ranh giới giúp phát hiện sự kiện chuyển động của bút cảm ứng.
Hình 1. Chữ viết tay trong giới hạn của trường EditText.

Bắt đầu chữ viết tay tuỳ chỉnh

Nếu một khung hiển thị chứa nhiều trình chỉnh sửa văn bản hoặc nội dung ngoài một trình chỉnh sửa văn bản, thì khung hiển thị đó phải triển khai logic khởi tạo chữ viết tay riêng như sau:

  1. Chọn không bắt đầu tính năng viết tay tự động của hệ thống chế độ xem bằng cách gọi setAutoHandwritingEnabled(false).

  2. Theo dõi tất cả trình chỉnh sửa văn bản xuất hiện trong chế độ xem.

  3. Theo dõi các sự kiện chuyển động mà khung hiển thị nhận được trong dispatchTouchEvent().

    • Khi bút cảm ứng chuyển động trong ranh giới chữ viết tay của trình chỉnh sửa văn bản, hãy lấy nét vào trình chỉnh sửa văn bản (nếu chưa đặt tiêu điểm).

    • Nếu trình chỉnh sửa chưa được đặt tiêu điểm, hãy khởi động lại IME của trình chỉnh sửa với nội dung mới bằng cách gọi InputMethodManager#restartInput().

    • Bắt đầu phiên viết tay bằng bút cảm ứng bằng cách gọi InputMethodManager#startStylusHandwriting().

Nếu trình chỉnh sửa văn bản nằm trong chế độ xem có thể cuộn, thì chuyển động của bút cảm ứng trong ranh giới chữ viết tay của trình chỉnh sửa phải được coi là chữ viết tay, chứ không phải cuộn. Sử dụng ViewParent#requestDisallowInterceptTouchEvent() để ngăn khung hiển thị đối tượng cấp trên có thể cuộn chặn các sự kiện chạm từ trình chỉnh sửa văn bản.

Thông tin chi tiết về API

  • MotionEvent#getToolType() – Cho biết liệu MotionEvent có phải là từ bút cảm ứng hay không, trong trường hợp nào thì giá trị trả về là TOOL_TYPE_STYLUS hoặc TOOL_TYPE_ERASER.

  • InputMethodManager#isStylusHandwritingAvailable() – Cho biết liệu IME có hỗ trợ chữ viết tay bằng bút cảm ứng hay không. Hãy gọi phương thức này trước mỗi lệnh gọi đến InputMethodManager#startStylusHandwriting() vì tính năng chữ viết tay có thể đã thay đổi.

  • InputMethodManager#startStylusHandwriting() — Làm cho IME chuyển sang chế độ viết tay. Một sự kiện chuyển động ACTION_CANCEL sẽ được gửi đến ứng dụng để huỷ cử chỉ hiện tại. Các sự kiện chuyển động của bút cảm ứng không còn được gửi đến ứng dụng nữa.

    Các sự kiện chuyển động bằng bút cảm ứng của cử chỉ hiện tại đã được gửi đến ứng dụng sẽ được chuyển tiếp đến IME. IME cần để hiển thị một cửa sổ mực bút cảm ứng mà qua đó IME nhận tất cả các đối tượng MotionEvent sau đây. IME thay đổi văn bản chữ viết tay được nhận dạng bằng các API InputConnection.

    Nếu IME không thể chuyển sang chế độ viết tay, thì lệnh gọi phương thức này sẽ không hoạt động.

Khai báo chức năng hỗ trợ chữ viết tay

Khi điền vào đối số EditorInfo của lệnh gọi View#onCreateInputConnection(EditorInfo) setStylusHandwritingEnabled() để thông báo cho IME biết rằng trình chỉnh sửa văn bản có hỗ trợ chữ viết tay. Khai báo các cử chỉ được hỗ trợ bằng setSupportedHandwritingGestures()setSupportedHandwritingGesturePreviews().

Hỗ trợ cử chỉ viết tay

IME có thể hỗ trợ nhiều cử chỉ viết tay, chẳng hạn như khoanh tròn văn bản để chọn văn bản hoặc viết nguệch ngoạc trên văn bản để xoá.

Hình 2. Khoanh tròn để chọn văn bản.
Hình 3. Vẽ nguệch ngoạc để xoá văn bản.

Trình chỉnh sửa tuỳ chỉnh sẽ triển khai InputConnection#performHandwritingGesture()InputConnection#previewHandwritingGesture() để hỗ trợ nhiều loại HandwritingGesture, chẳng hạn như SelectGesture, DeleteGestureInsertGesture.

Khai báo các cử chỉ viết tay được hỗ trợ khi điền vào đối số EditorInfo của View#onCreateInputConnection(EditorInfo) (xem phần Khai báo hỗ trợ chữ viết tay).

Thông tin chi tiết về API

  • InputConnection#performHandwritingGesture(HandwritingGesture, Executor, IntConsumer) – Triển khai các cử chỉ. Đối số HandwritingGesture chứa thông tin vị trí mà bạn có thể dùng để xác định vị trí trong văn bản để thực hiện cử chỉ. Ví dụ: SelectGesture cung cấp đối tượng RectF chỉ định dải ô văn bản đã chọn, còn InsertGesture cung cấp đối tượng PointF chỉ định độ lệch văn bản mà tại đó cần chèn văn bản.

    Sử dụng các tham số ExecutorIntConsumer để gửi lại kết quả của thao tác. Khi cả trình thực thi và đối số của người tiêu dùng được cung cấp, hãy sử dụng trình thực thi để gọi IntConsumer#accept(), ví dụ:

    
    executor.execute { consumer.accept(HANDWRITING_GESTURE_RESULT_SUCCESS) }
    
    
  • HandwritingGesture#getFallbackText() – Cung cấp văn bản dự phòng mà IME thực hiện tại vị trí con trỏ nếu không có văn bản áp dụng nào ở bên dưới vùng cử chỉ viết tay.

    Đôi khi, IME không thể xác định xem một cử chỉ dùng bút cảm ứng là nhằm thực hiện một thao tác cử chỉ hay để viết tay văn bản. Trình chỉnh sửa văn bản tuỳ chỉnh chịu trách nhiệm xác định ý định của người dùng và thực hiện thao tác thích hợp (tuỳ thuộc vào ngữ cảnh) tại vị trí cử chỉ.

    Ví dụ: nếu IME không thể xác định liệu người dùng có ý vẽ con nháy xuống ⋁ để thực hiện cử chỉ chèn dấu cách hay viết tay chữ cái "v", thì IME có thể gửi một InsertGesture với văn bản dự phòng "v".

    Trước tiên, trình chỉnh sửa nên thử thực hiện cử chỉ chèn dấu cách. Nếu không thể thực hiện cử chỉ (ví dụ: không có văn bản tại vị trí đã chỉ định), thì trình chỉnh sửa sẽ quay lại chèn "v" vào vị trí con trỏ.

  • InputConnection#previewHandwritingGesture(PreviewableHandwritingGesture, CancellationSignal) — Xem trước một cử chỉ đang diễn ra. Ví dụ: khi người dùng bắt đầu vẽ một vòng tròn xung quanh một số văn bản, bản xem trước trực tiếp của lựa chọn kết quả có thể hiển thị và liên tục được cập nhật khi người dùng tiếp tục vẽ. Chỉ một số loại cử chỉ nhất định có thể xem trước (xem PreviewableHandwritingGesture).

    IME có thể sử dụng tham số CancellationSignal để huỷ bản xem trước. Nếu các sự kiện khác làm gián đoạn bản xem trước (ví dụ: văn bản bị thay đổi theo phương thức lập trình hoặc xuất hiện lệnh InputConnection mới), thì trình chỉnh sửa tuỳ chỉnh có thể huỷ bản xem trước.

    Các cử chỉ xem trước chỉ dùng để hiển thị và không thay đổi trạng thái của trình chỉnh sửa. Ví dụ: bản xem trước SelectGesture sẽ ẩn phạm vi lựa chọn hiện tại của trình chỉnh sửa và đánh dấu phạm vi xem trước cử chỉ. Tuy nhiên, sau khi bản xem trước bị huỷ, trình chỉnh sửa sẽ khôi phục phạm vi lựa chọn trước đó.

Cung cấp dữ liệu vị trí con trỏ và dữ liệu khác về vị trí

Ở chế độ viết tay, IME có thể yêu cầu dữ liệu vị trí con trỏ và các dữ liệu khác về vị trí bằng cách sử dụng InputConnection#requestCursorUpdates(). Trình chỉnh sửa tuỳ chỉnh phản hồi bằng lệnh gọi tới InputMethodManager#updateCursorAnchorInfo(View, CursorAnchorInfo). Dữ liệu trong CursorAnchorInfo liên quan đến chữ viết tay của bút cảm ứng được cung cấp thông qua các phương thức CursorAnchorInfo.Builder sau:

  • setInsertionMarkerLocation() — Đặt vị trí của con trỏ. IME sử dụng giá trị để tạo ảnh động cho mực viết tay vào vị trí con trỏ.
  • setEditorBoundsInfo() — Đặt giới hạn của trình chỉnh sửa và giới hạn chữ viết tay. IME sử dụng dữ liệu này để định vị thanh công cụ viết tay của IME trên màn hình.
  • addVisibleLineBounds() – Đặt ranh giới của tất cả các dòng văn bản hiển thị (hoặc hiển thị một phần) của trình chỉnh sửa. IME sử dụng ranh giới dòng để cải thiện độ chính xác trong việc nhận dạng các cử chỉ viết tay.
  • setTextAppearanceInfo() – Thiết lập giao diện văn bản với thông tin bắt nguồn từ trường nhập văn bản. IME sử dụng thông tin để tạo kiểu cho mực viết tay.

Hiện biểu tượng di chuột qua chữ viết tay của bút cảm ứng

Hiển thị biểu tượng di chuột qua chữ viết tay của bút cảm ứng khi bút cảm ứng di qua ranh giới viết tay của trình chỉnh sửa văn bản tuỳ chỉnh và IME đã chọn hỗ trợ tính năng viết tay bằng bút cảm ứng (InputMethodManager#isStylusHandwritingAvailable()).

Ghi đè View#onResolvePointerIcon() để có biểu tượng di chuột cho tính năng viết tay bằng bút cảm ứng. Trong chế độ ghi đè, hãy gọi PointerIcon.getSystemIcon(context, PointerIcon.TYPE_HANDWRITING) để truy cập vào biểu tượng di bút cảm ứng viết tay của hệ thống.

Tài nguyên khác