Xử lý đa chạm Multi Touch trong Android

Dịch vụ dạy kèm gia sư lập trình

Hầu hết các thiết bị Android bây giờ đang dùng màn hình hỗ trợ cảm ứng đa điểm. Việc phát hiện ra các vị trí touch (sự kiện chạm cảm ứng vào màn hình) hay gọi là multi touch. Multi touch trong Android là một tính năng rất hay, với nhiều ứng dụng trong thực tế.

Multi touch trong android giúp chúng ta biết được vị trí ngón tay thao tác. Từ đó giúp chúng ta tuỳ chỉnh theo yêu cầu của bài toán ứng dụng. Ví dụ như tính năng Zoom trong ứng dụng Gallery.

Bài viết này, mình sẽ hướng dẫn các bạn về xử lý Multi Touch để zoom ảnh trong ứng dụng Gallery.

Hướng dẫn viết code xử lý Multi touch trong Android

Ở bài viết viết này, mình sẽ hướng dẫn các bạn zoom ảnh bằng 2 ngón tay trong android.

Bản chất multi touch vẫn là xử lý sự kiện chạm vào màn hình cảm ứng, chỉ khác là dùng một ngón thì multi touch sẽ dùng nhiều ngón tay. Vì vậy, để hiển thị ảnh thì mình phải sử dụng một view nào đó như ImageView.

Tuy nhiên, ImageView theo mặc định thì lại không hỗ trợ multi touch. Đó là lý do mình sẽ tạo một custom view để build một view hiển thị ảnh có hỗ trợ multi touch.

👏 Bạn có thể đọc thêm về cách tạo một custom view cơ bản tại đây: Hướng dẫn tạo Custom View trong Android cho người mới

Đây là giao diện ứng dụng sau khi hoàn thành bài viết này. Nhìn giao diện rất cơ bản phải không?

Các sử dụng ứng dụng là bạn dụng 2 ngón tay để có thể zoom to nhỏ ảnh.

#1. Tạo một custom view

Đầu tiên các bạn tạo class ZoomImageView kế thừa từ ImageView để chúng ta bắt đầu customView.

public class ZoomImageView extends ImageView {
    public ZoomImageView(Context context) {
        super(context);
    }

    public ZoomImageView(Context context,  AttributeSet attrs) {
        super(context, attrs);
    }

    public ZoomImageView(Context context,  AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @SuppressLint("NewApi")
    public ZoomImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }
}

Android cung cấp lớp MotionEvent để hỗ trợ cảm ứng khi người dùng chạm vào màn hình thông qua view với phương thức onTouch().

Bạn chỉ cần overide lại phương thức onTouch() đối với view mà bạn muốn.

#2. Tìm hiểu hàm onTouch()

Lớp MotionEvent chứa các thông tin liên quan như: số lượng con trỏ, tọa độ X / Y, kích thước và áp lực của mỗi con trỏ.

@Override
public boolean onTouch(View v, MotionEvent event) {
    if (mGestureDetector.onTouchEvent(event)) return true;
    mScaleGestureDetetor.onTouchEvent(event);
    float x = 0;
    float y = 0;
    int pointCount = event.getPointerCount();
    for (int i = 0; i < pointCount; i++) {
        x = x + event.getX(i);
        y = y + event.getY(i);
    }
    x /= pointCount;
    y /= pointCount;

    if (mLastPointCount != pointCount) {
        isCanDrag = false;
        mLastX = x;
        mLastY = y;
    }
    mLastPointCount = pointCount;
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            break;
        case MotionEvent.ACTION_MOVE:
            float dx = x - mLastX;
            float dy = y - mLastY;
            if (!isCanDrag) {
                isCanDrag = isMoveAction(dx, dy);
            }
            if (isCanDrag) {
                RectF rectF = getMatrixRectF();
                if (getDrawable() != null) {
                    if (rectF.width() < getWidth()) {
                        dx = 0;
                    }
                    if (rectF.height() < getHeight()) {
                        dy = 0;
                    }
                    mMatrix.postTranslate(dx, dy);
                    checkBorderAndCenterWhenScale();
                    setImageMatrix(mMatrix);
                }
            }
            mLastX = x;
            mLastY = y;
            break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            mLastPointCount = 0;
            break;
    }
    return true;
}

Giống như các sự kiện khác, sự kiện Touch của một view có thể được phát hiện và xử lý thông qua việc đăng ký với trình lắng nghe sự kiện onTouchListener và thực thi phương thức onTouch() tương ứng.

Các phương thức onTouch trả về giá trị true nếu người dùng nhấn xuống hoặc nâng lên để chỉ ra rằng nó đã tiêu thụ các sự kiện. Tuy nhiên, đối với tất cả các hành động cảm ứng khác, phương thức này trả về giá trị false để chỉ ra rằng nó đã không nhận các sự kiện và các yếu tố khác có thể tiếp tục xử lý sự kiện này.

Khi xảy ra nhiều lần chạm vào màn hình tại cùng một thời điểm, mỗi một lần chạm được xem như là một con trỏ (pointer).

Mỗi con trỏ sẽ được tham chiếu đến một index và được gán một ID. Số con trỏ hay số lần chạm có thể được xác định nhờ phương thức getPointerCount() của đối tượng MotionEvent.

Giá trị trả về của hàm onTouch()

  • MotionEvent.ACTION_DOWN : Trả về với sự kiện khi bạn bắt đầu chạm vào view
  • MotionEvent.ACTION_MOVE : Trả về khi bạn di chuyển trên view đó.
  • MotionEvent.ACTION_UP : Trả về khi bạn nhấc tay ra khỏi view.
  • MotionEvent.ACTION_CANCEL : Trả về khi event touch cancel.
  • MotionEvent.ACTION_POINTER_DOWN : Chỉ có với multi-touch, trả về vị trí của mới khi bạn multiple touch
  • MotionEvent.ACTION_POINTER_UP : Chỉ có với multi-touch, trả ra khi bạn cancel một điểm mà bạn đã chạm trước đó.

💦 Bài viết khác có ích cho bạn: Xử lý sự kiện trong Android (Event Listeners)

#3. Xử lý scale ảnh khi phát hiện Multi touch trong android

Để scale được hình ảnh các bạn  kế thừa từ lớp ScaleGestureDetector.

public class ZoomImageView extends ImageView implements View.OnTouchListener, ScaleGestureDetector.OnScaleGestureListener

và chúng ta sẽ viết các tính toán trong hàm onScall().

@Override
public boolean onScale(ScaleGestureDetector detector) {
    float scale = getScale();
    float factor = detector.getScaleFactor();

    if (getDrawable() == null) return true;

    float dx = detector.getFocusX();
    float dy = detector.getFocusY();

    if ((scale < mMaxScale && factor > 1.0) || (scale > mInitScale && factor < 1.0f)) {
        if (scale * factor < mInitScale) {
            factor = mInitScale / scale;
        }

        if (scale * factor > mMaxScale) {
            factor = mMaxScale / scale;
        }

        mMatrix.postScale(factor, factor, dx, dy);

        checkBorderAndCenterWhenScale();

        setImageMatrix(mMatrix);
    }
    return true;
}

#4. Sử dụng ZoomImageView

Cuối cùng chúng ta chỉ cần khai báo trong file xml, giống bài trước mình đã hướng dẫn các bạn custom 1 view là xong và run project là chạy.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.example.zoomimageview.ZoomImageView
        android:id="@+id/action_infolinks_splash"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:src="@mipmap/bg_sontung" />

</LinearLayout>

Tổng kết

Như vậy là chúng ta đã hoàn thành việc tạo một custom view có hỗ trợ multi touch trong android.

Các bạn có thể download toàn bộ source code của bài hướng dẫn tại đây nhé.

Hy vọng bài viết này sẽ giúp bạn phần nào hiểu và có thể tự xử lý MultiTouch  cho ứng dụng của mình.

Ứng dụng của bạn có sử dụng Multi touch không? Để lại ý kiến của bạn ở bên dưới nhé.

Dịch vụ phát triển ứng dụng mobile giá rẻ - chất lượng
Bài trướcKotlin trên Android – từ cơ bản tới nâng cao
Bài tiếp theoHeadless CMS là gì? Có nên quan tâm tới Headless CMS lúc này?
Lương Văn Đông
Tất cả lập trình viên đều là những nhà viết kịch và tất cả máy tính đều là những diễn viên tồi.

Bình luận. Cùng nhau thảo luận nhé!

avatar
  Theo dõi bình luận  
Thông báo