versiones pie oreo developer caracteristicas android

pie - android versiones



¿Hay algún ejemplo de cómo usar TouchDelegate en Android para aumentar el tamaño del objetivo de clic de una vista? (11)

Según tengo entendido, cuando tienes una vista demasiado pequeña para tocarla fácilmente, se supone que debes usar un TouchDelegate para aumentar la región en la que se puede hacer clic para esa vista.

Sin embargo, al buscar ejemplos de uso en Google aparecen muchas personas que hacen la pregunta, pero pocas respuestas.

¿Alguien sabe la forma correcta de configurar un delegado táctil para una vista para, digamos, aumentar su región cliqueable en 4 píxeles en todas las direcciones?


¿No es la mejor Idea de dar Padding a ese componente en particular (Botón)?


De acuerdo con el comentario de @Mason Lee, esto resolvió mi problema. Mi proyecto tenía un diseño relativo y un botón. Entonces parent es -> layout y child is -> un botón.

Aquí hay un código de Google ejemplo de google link

En caso de eliminar su muy valiosa respuesta, pongo aquí su respuesta.

Recientemente me preguntaron cómo usar TouchDelegate. Yo también estaba un poco oxidado sobre esto y no pude encontrar ninguna buena documentación al respecto. Aquí está el código que escribí después de un poco de prueba y error. touch_delegate_view es un RelativeLayout simple con el ID touch_delegate_root. Definí con un único hijo del diseño, el botón deleted_button. En este ejemplo, amplío el área seleccionable del botón a 200 píxeles por encima de la parte superior de mi botón.

La clase pública TouchDelegateSample extiende la actividad {

Botón mButton; @Override protected void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.touch_delegate_view); mButton = (Botón) findViewById (R.id.delegated_button); Ver padre = 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); } } }); } }

Saludos, Justin Android Team @ Google

Pocas palabras de mí: si quieres expandir el lado izquierdo, das valor con menos, y si quieres expandir el lado derecho del objeto, le das valor con más. Esto funciona igual con arriba y abajo.


Debido a que no me gustó la idea de esperar a que el diseño pase solo para obtener el nuevo tamaño del rectángulo de TouchDelegate, busqué una solución diferente:

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; } }

Y luego, en un diseño:

<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>

La idea es que TouchSizeIncreaser FrameLayout enrolle el Spinner (podría ser cualquier Vista secundaria) y reenvíe todos los eventos táctiles capturados en su acceso directo a la Vista secundaria. Funciona para clics, la ruleta se abre incluso si se hace clic fuera de sus límites, sin estar seguro de cuáles son las implicaciones para otros casos más complejos.


El acercamiento de Emmby no funcionó para mí, pero después de algunos cambios lo hizo:

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)); } }); }

Tal vez puede salvar el tiempo de alguien


En la mayoría de los casos, puede envolver la vista que requiere un área táctil más grande en otra vista sin cabeza (vista transparente artificial) y agregar relleno / margen a la vista de envoltura y adjuntar el clic / toque incluso a la vista de envoltura en lugar de la vista original tiene que tener un área táctil más grande.


Esta solución fue publicada por @BrendanWeinstein en comentarios.

En lugar de enviar un TouchDelegate puede anular el getHitRect(Rect) de su View (en caso de que esté extendiendo uno).

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; } }


Le pregunté a un amigo en Google y me ayudaron a descubrir cómo usar TouchDelegate. Esto es lo que se nos ocurrió:

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)); } });


Para expandir el área táctil genéricamente con algunas restricciones, use el siguiente código.

Le permite expandir el área táctil de la view dada dentro de la vista ancestor dada por la expansion dada en píxeles. Puedes elegir cualquier ancestro siempre que la vista dada esté en el árbol de diseño de antepasados.

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; } }); }

Restricciones que aplican:

  • El área táctil no puede superar los límites del antecesor de la vista, ya que el antecesor debe poder atrapar el evento táctil para poder reenviarlo a la vista.
  • Solo un TouchDelegate se puede establecer en un ViewGroup . Si desea trabajar con múltiples delegados táctiles, elija diferentes ancestros o use un delegado táctil de composición como se explica en Cómo usar Multiple TouchDelegate .

Pude lograr esto con vistas múltiples (casillas de verificación) en una pantalla dibujando principalmente de brendanweinstein.me/2012/06/26/… . Básicamente tomas la solución de emmby y la aplicas a cada botón y a su padre individualmente.

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)); } }); }

En mi caso, tuve una vista en cuadrícula de imageviews con casillas de verificación superpuestas en la parte superior, y llamé al método de la siguiente manera:

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);

Funcionando bien para mi


Si no desea hacerlo programáticamente, simplemente cree un área transparente alrededor de la imagen, si está usando la imagen como fondo para el botón (vista).

El área gris puede ser transparente para aumentar el área táctil.


Un poco tarde para la fiesta, pero después de mucha investigación, ahora estoy usando:

/** * 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); } }); }

Esto es mejor que la solución aceptada, ya que también permite configurar un TouchDelegate en cualquier Vista de antecesor, no solo en la Vista principal.

A diferencia de la solución aceptada, también actualiza el TouchDelegate cada vez que hay un cambio en el diseño de la vista del antecesor.