Pertanyaan Apakah ada contoh tentang cara menggunakan TouchDelegate di Android untuk meningkatkan ukuran target klik suatu tampilan?


Pemahaman saya adalah bahwa ketika Anda memiliki pandangan yang terlalu kecil untuk mudah disentuh, Anda seharusnya menggunakan TouchDelegate untuk meningkatkan wilayah yang dapat diklik untuk tampilan itu.

Namun, mencari contoh penggunaan di Google mendatangkan banyak orang mengajukan pertanyaan, tetapi hanya sedikit jawaban.

Apakah ada yang tahu cara yang tepat untuk mengatur delegasi sentuhan untuk melihat, katakanlah, meningkatkan wilayah yang dapat diklik oleh 4 piksel di setiap arah?


75
2017-08-27 19:13


asal


Jawaban:


Saya bertanya kepada seorang teman di Google dan mereka dapat membantu saya mencari cara menggunakan TouchDelegate. Inilah yang kami temukan:

final View parent = (View) delegate.getParent();
parent.post( new Runnable() {
    // Post in the parent's message queue to make sure the parent
    // lays out its children before we call getHitRect()
    public void run() {
        final Rect r = new Rect();
        delegate.getHitRect(r);
        r.top -= 4;
        r.bottom += 4;
        parent.setTouchDelegate( new TouchDelegate( r , delegate));
    }
});

93
2017-08-27 21:21



Saya bisa mencapai ini dengan beberapa tampilan (kotak centang) pada satu gambar layar sebagian besar dari posting blog ini. Pada dasarnya Anda mengambil solusi emmby dan menerapkannya ke setiap tombol dan induknya secara individual.

public static void expandTouchArea(final View bigView, final View smallView, final int extraPadding) {
    bigView.post(new Runnable() {
        @Override
        public void run() {
            Rect rect = new Rect();
            smallView.getHitRect(rect);
            rect.top -= extraPadding;
            rect.left -= extraPadding;
            rect.right += extraPadding;
            rect.bottom += extraPadding;
            bigView.setTouchDelegate(new TouchDelegate(rect, smallView));
        }
   });
}

Dalam kasus saya, saya memiliki tampilan grid dari tampilan gambar dengan kotak centang dihamparkan di atas, dan memanggil metode sebagai berikut:

CheckBox mCheckBox = (CheckBox) convertView.findViewById(R.id.checkBox1);
final ImageView imageView = (ImageView) convertView.findViewById(R.id.imageView1);

// Increase checkbox clickable area
expandTouchArea(imageView, mCheckBox, 100);

Bekerja bagus untukku.


20
2018-03-04 03:01



Solusi ini diposting oleh @BrendanWeinstein di komentar.

Alih-alih mengirim TouchDelegate Anda dapat mengganti getHitRect(Rect) metode Anda View (jika Anda memperpanjang satu).

public class MyView extends View {  //NOTE: any other View can be used here

    /* a lot of required methods */

    @Override
    public void getHitRect(Rect r) {
        super.getHitRect(r); //get hit Rect of current View

        if(r == null) {
            return;
        }

        /* Manipulate with rect as you wish */
        r.top -= 10;
    }
}

9
2017-11-07 13:33



Pendekatan emmby tidak berhasil untuk saya, tetapi setelah sedikit perubahan, hal itu terjadi:

private void initApplyButtonOnClick() {
    mApplyButton.setOnClickListener(onApplyClickListener);
    final View parent = (View)mApplyButton.getParent();
    parent.post(new Runnable() {

        @Override
        public void run() {
            final Rect hitRect = new Rect();
            parent.getHitRect(hitRect);
            hitRect.right = hitRect.right - hitRect.left;
            hitRect.bottom = hitRect.bottom - hitRect.top;
            hitRect.top = 0;
            hitRect.left = 0;
            parent.setTouchDelegate(new TouchDelegate(hitRect , mApplyButton));         
        }
    });
}

Mungkin itu bisa menyelamatkan waktu seseorang


6
2018-06-13 13:16



Bukankah Ide yang lebih baik memberikan Padding ke komponen tertentu (Button).


1
2017-07-05 08:19



Sedikit terlambat ke pesta, tetapi setelah banyak penelitian, saya sekarang menggunakan:

/**
 * Expand the given child View's touchable area by the given padding, by
 * setting a TouchDelegate on the given ancestor View whenever its layout
 * changes.
 */*emphasized text*
public static void expandTouchArea(final View ancestorView,
    final View childView, final Rect padding) {

    ancestorView.getViewTreeObserver().addOnGlobalLayoutListener(
        new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                TouchDelegate delegate = null;

                if (childView.isShown()) {
                    // Get hitRect in parent's coordinates
                    Rect hitRect = new Rect();
                    childView.getHitRect(hitRect);

                    // Translate to ancestor's coordinates
                    int ancestorLoc[] = new int[2];
                    ancestorView.getLocationInWindow(ancestorLoc);

                    int parentLoc[] = new int[2];
                    ((View)childView.getParent()).getLocationInWindow(
                        parentLoc);

                    int xOffset = parentLoc[0] - ancestorLoc[0];
                    hitRect.left += xOffset;
                    hitRect.right += xOffset;

                    int yOffset = parentLoc[1] - ancestorLoc[1];
                    hitRect.top += yOffset;
                    hitRect.bottom += yOffset;

                    // Add padding
                    hitRect.top -= padding.top;
                    hitRect.bottom += padding.bottom;
                    hitRect.left -= padding.left;
                    hitRect.right += padding.right;

                    delegate = new TouchDelegate(hitRect, childView);
                }

                ancestorView.setTouchDelegate(delegate);
            }
        });
}

Ini lebih baik daripada solusi yang diterima karena juga memungkinkan TouchDelegate untuk diatur pada leluhur View, bukan hanya induk Lihat.

Tidak seperti solusi yang diterima, itu juga memperbarui TouchDelegate setiap kali ada perubahan dalam tata letak leluhur View.


1
2017-09-08 15:45



Jika tidak ingin melakukannya secara sistematis maka cukup buat area transparan di sekitar gambar, Jika Anda menggunakan gambar sebagai latar belakang untuk tombol (tampilan).

Area abu-abu dapat transparan untuk meningkatkan area sentuh.

enter image description here


0
2017-11-07 13:25



Dalam kebanyakan kasus, Anda dapat membungkus tampilan yang membutuhkan area sentuh yang lebih besar di tampilan tanpa kepala (tampilan transparan buatan) dan menambahkan padding / margin ke tampilan pembungkus dan melampirkan klik / sentuh bahkan ke tampilan pembungkus bukan tampilan asli yang harus memiliki area sentuh yang lebih besar.


0
2018-02-26 03:52



Menurut komentar @Mason Lee, ini memecahkan masalah saya. Proyek saya memiliki tata letak relatif dan satu tombol. Jadi orang tua adalah -> tata letak dan anak adalah -> sebuah tombol.

Berikut ini contoh tautan google kode google

Dalam kasus menghapus jawaban yang sangat berharga, saya taruh di sini jawabannya.

Saya baru saja ditanya tentang cara menggunakan TouchDelegate. Saya sedikit berkarat sendiri dalam hal ini dan saya tidak dapat menemukan dokumentasi yang bagus.   Inilah kode yang saya tulis setelah sedikit trial and error.   touch_delegate_view adalah RelativeLayout sederhana dengan id   touch_delegate_root. Saya mendefinisikan dengan satu, anak dari tata letak,   tombol delegated_button. Dalam contoh ini saya memperluas area yang dapat diklik   dari tombol hingga 200 piksel di atas bagian atas tombol saya.

kelas publik TouchDelegateSample memperluas Kegiatan {

Tombol mButton; @Override void yang dilindungi onCreate (Bundle   savedInstanceState) {       super.onCreate (savedInstanceState);       setContentView (R.layout.touch_delegate_view);       mButton = (Tombol) findViewById (R.id.delegated_button);       Lihat parent = findViewById (R.id.touch_delegate_root);

// post a runnable to the parent view's message queue so its run after
// the view is drawn
parent.post(new Runnable() {
  @Override
  public void run() {
    Rect delegateArea = new Rect();
    Button delegate = TouchDelegateSample.this.mButton;
    delegate.getHitRect(delegateArea);
    delegateArea.top -= 200;
    TouchDelegate expandedArea = new TouchDelegate(delegateArea, delegate);
    // give the delegate to an ancestor of the view we're delegating the
    // area to
    if (View.class.isInstance(delegate.getParent())) {
      ((View)delegate.getParent()).setTouchDelegate(expandedArea);
    }
  }
});   } }

Cheers, Justin Android Team @ Google

Beberapa kata dari saya: jika Anda ingin memperluas sisi kiri Anda memberi nilai dengan minus, dan jika Anda ingin memperluas sisi kanan objek, Anda memberi nilai plus. Ini bekerja sama dengan bagian atas dan bawah.


0
2018-04-05 10:29



Untuk memperluas area sentuh secara umum dengan cukup sedikit pembatasan, gunakan kode berikut.

Ini memungkinkan Anda memperluas area sentuh yang diberikan view dalam yang diberikan ancestor lihat oleh yang diberikan expansion dalam piksel. Anda dapat memilih leluhur apa pun selama pandangan yang diberikan ada di pohon tata letak leluhur.

    public static void expandTouchArea(final View view, final ViewGroup ancestor, final int expansion) {
    ancestor.post(new Runnable() {
        public void run() {
            Rect bounds = getRelativeBounds(view, ancestor);
            Rect expandedBounds = expand(bounds, expansion);
            // LOG.debug("Expanding touch area of {} within {} from {} by {}px to {}", view, ancestor, bounds, expansion, expandedBounds);
            ancestor.setTouchDelegate(new TouchDelegate(expandedBounds, view));
        }

        private Rect getRelativeBounds(View view, ViewGroup ancestor) {
            Point relativeLocation = getRelativeLocation(view, ancestor);
            return new Rect(relativeLocation.x, relativeLocation.y,
                            relativeLocation.x + view.getWidth(),
                            relativeLocation.y + view.getHeight());
        }

        private Point getRelativeLocation(View view, ViewGroup ancestor) {
            Point absoluteAncestorLocation = getAbsoluteLocation(ancestor);
            Point absoluteViewLocation = getAbsoluteLocation(view);
            return new Point(absoluteViewLocation.x - absoluteAncestorLocation.x,
                             absoluteViewLocation.y - absoluteAncestorLocation.y);
        }

        private Point getAbsoluteLocation(View view) {
            int[] absoluteLocation = new int[2];
            view.getLocationOnScreen(absoluteLocation);
            return new Point(absoluteLocation[0], absoluteLocation[1]);
        }

        private Rect expand(Rect rect, int by) {
            Rect expandedRect = new Rect(rect);
            expandedRect.left -= by;
            expandedRect.top -= by;
            expandedRect.right += by;
            expandedRect.bottom += by;
            return expandedRect;
        }
    });
}

Batasan yang berlaku:

  • Area sentuhan tidak dapat melebihi batas leluhur pandangan karena leluhur harus dapat menangkap peristiwa sentuhan untuk meneruskannya ke tampilan.
  • Hanya satu TouchDelegate dapat diatur ke a ViewGroup. Jika Anda ingin bekerja dengan beberapa delegasi sentuh, pilih leluhur yang berbeda atau gunakan delegasi sentuh yang menyusun seperti yang dijelaskan di Bagaimana Menggunakan Multiple TouchDelegate.

0
2018-05-18 15:25



Karena saya tidak suka ide menunggu layout pass hanya untuk mendapatkan ukuran baru dari persegi panjang TouchDelegate, saya mencari solusi lain:

public class TouchSizeIncreaser extends FrameLayout {
    public TouchSizeIncreaser(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        final View child = getChildAt(0);
        if(child != null) {
            child.onTouchEvent(event);
        }
        return true;
    }
}

Dan kemudian, dalam tata letak:

<ch.tutti.ui.util.TouchSizeIncreaser
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="10dp">

    <Spinner
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"/>
</ch.tutti.ui.util.TouchSizeIncreaser>

Idenya adalah bahwa TouchSizeIncreaser FrameLayout akan membungkus Spinner (bisa saja setiap anak Lihat) dan meneruskan semua acara sentuhan yang diambil di itu hit rect ke View anak. Ia bekerja untuk klik, spinner terbuka bahkan jika diklik di luar batasnya, tidak yakin apa implikasinya untuk kasus lain yang lebih kompleks.


0
2018-06-15 13:43