unidades una tenga que figura ejemplos cuadradas android android-layout android-custom-view

una - Al dibujar fuera de los límites de clip de vista con Android: ¿cómo evito que las vistas subordinadas se dibujen en la parte superior de mi vista personalizada?



una figura que tenga 9 unidades cuadradas (1)

Encontré la solución yo mismo, incluso si esto no es óptimo para las actuaciones.

Solo agrega:

android:clipChildren="false"

a RelativeLayout (o el diseño que tenga).

Esto tiene 2 efectos (puede ser más, estos son los dos que me interesaron): - ViewGroup no recorta el dibujo de sus hijos (obvio) - ViewGroup no comprueba la intersección con regiones sucias (invalidadas) cuando se considera qué niños volver a dibujar

Cavé el código de la Vista sobre la invalidación.

El proceso va más o más, así:

  1. una Vista se invalida, la región que generalmente dibuja (una rectangular) se convierte en una "región sucia" para volver a dibujar
  2. la Vista le dice a su padre (un Grupo de Vista de algún tipo) que necesita volver a dibujarse
  3. los padres hacen lo mismo con sus padres a la raíz
  4. cada padre en el ciclo de jerarquía para cada hijo y verifica si la región sucia se cruza con algunos de ellos
  5. si lo hace también los vuelven a dibujar

En el paso 4 está involucrado el recorte: ViewGroup ver los límites de su hijo solo si clipChildren es verdadero: lo que significa que si lo coloca en falso, siempre vuelve a dibujar todos sus elementos secundarios cuando alguno de ellos se invalide .

Entonces, mi jerarquía de Vista era así:

ViewGroup A | |----- fragment subtree (containing buttons, map, | whatever element that I don''t want to draw | on top of my handle) | |----- ViewGroup B | |---- my handle (which draw outside its clip bounds)

En mi caso, el "mango" se dibuja fuera de su límite, encima de algo que normalmente está dibujado por algún elemento del subárbol de fragmentos.

Cuando se invalida cualquier vista dentro del fragmento, pasa su "región sucia" hacia arriba en el árbol de vista y cada grupo de vista comprueba si hay otros elementos secundarios que se deben volver a dibujar en esa región.

ViewGroup B recortaría lo que dibuje fuera de los límites del clip si no configuro clipBounds = "false" en él.

Si algo se invalida en el subárbol de fragmentos, ViewGroup A verá que la región sucia del ViewGroup B no está intersecando con la región del subárbol de fragmentos y omitirá el redibujado de ViewGroup B.

Pero si también le digo a ViewGroup A que no recorte niños, todavía le dará a ViewGroup B un comando de invalidación que luego causará un redibujado de mi manejador.

Entonces la solución es asegurarse de establecer

android:clipChildren="false"

en cualquier grupo de vista en la jerarquía sobre la vista que dibuja fuera de sus límites en los que el contenido puede quedar "debajo" de la región fuera de límite que está dibujando.

El efecto secundario obvio de esto es que cada vez que invalido cualquiera de las vistas dentro de ViewGroup A, se reenviará una llamada invalidada, con la región no válida, a toda la vista que contenga.

Sin embargo, cualquier vista que no intersecte con la región sucia que está dentro de un Grupo de Vista con clipChildren = "true" (predeterminado) se saltará.

Para evitar problemas de rendimiento al hacer esto, asegúrese de que sus grupos de vista con clipChildren = "true" no tengan muchos hijos directos "estándar". Y con "estándar" quiero decir que no dibujan fuera de sus límites de vista.

Así que, por ejemplo, si en mi ejemplo ViewGroup B contiene muchas vistas, considere envolver todas aquellas en un ViewGroup con clipChildren = "true" y solo deje este grupo de vistas y la vista que se dibuja fuera de su región como hijos directos de ViewGroup B. Lo mismo ocurre para ViewGroup A.

Este simple hecho asegurará que ninguna otra Vista obtenga un redibujado si no están en la región sucia invalidada minimizando los redibujados necesarios.

Todavía estoy abierto a escuchar más consideraciones si alguien tiene uno;)

Así que esperaré un poco antes de marcar esto como una respuesta aceptada.

EDITAR: Muchos dispositivos hacen algo diferente al manejar clipChildren = "false". Descubrí que tenía que establecer clipChildren = "false" en todas las vistas principales de mi widget personalizado que puede contener elementos en su jerarquía que deberían dibujar sobre la "región fuera de límite" del widget o puede ver su dibujo personalizado mostrando en la parte superior de otra vista que se suponía que lo cubriría. Por ejemplo, en mi diseño tenía un Cajón de navegación que se suponía que cubría mi "mango". Si no configuré clipChildren = "false" en el diseño de NavigationDrawer, a veces veo aparecer mi identificador frente al cajón abierto.

EDIT2: mi widget personalizado tenía 0 alto y dibujó "en la parte superior" de sí mismo. Funcionó bien en los dispositivos Nexus, pero muchos de los otros tenían alguna "optimización" en su lugar que omite por completo el dibujo de las vistas que tienen 0 de altura o 0 de ancho. Por lo tanto, tenga en cuenta esto si desea escribir un componente que se extraiga: debe asignarle al menos 1 píxel de alto / ancho.

Escribí una vista de Android personalizada que debe dibujar fuera de sus límites de recorte.

Esto es lo que tengo:

Esto es lo que sucede cuando hago clic en un botón, diga el botón derecho:

¿Cómo evito que la Vista a continuación dibuje sobre mi "mango"?

Siguen algunos pseudocódigos relacionados de mi proyecto.

Mi vista personalizada MyHandleView dibuja así:

@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Path p = mPath; int handleWidth = mHandleWidth; int handleHeight = mHandleHeight; int left = (getWidth() >> 1) - handleWidth; canvas.save(); // allow drawing out of bounds vertically Rect clipBounds = canvas.getClipBounds(); clipBounds.inset(0, -handleHeight); canvas.clipRect(clipBounds, Region.Op.REPLACE); // translate up to draw the handle canvas.translate(left, -handleHeight); // draw my background shape canvas.drawPath(p, mPaint); canvas.restore(); }

El diseño es algo como esto (simplifiqué un poco):

<RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <!-- Main content of the SlidingUpPanel --> <fragment android:above=@+id/panel" class="com.neosperience.projects.percassi.android.home.HomeFragment" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="?android:attr/actionBarSize" tools:layout="@layout/fragment_home" /> <!-- The Sliding Panel --> <LinearLayout android:id="@id/panel" android:layout_width="match_parent" android:layout_height="@dimen/myFixedSize" android:alignParentBottom="true" android:orientation="vertical" android:clipChildren="false"> <MyHandleView xmlns:custom="http://schemas.android.com/apk/res-auto.com/apk/res/android" android:layout_width="match_parent" android:layout_height="0dp" custom:handleHeight="@dimen/card_panel_handle_height" custom:handleWidthRatio="@dimen/card_panel_handle_width_ratio" custom:handleBackgroundColor="#000"/> <TextView android:id="@+id/loyaltyCardPanelTitle" android:layout_width="match_parent" android:layout_height="@dimen/card_panel_height" android:background="#000" android:gravity="center" android:textStyle="bold" android:textSize="24sp" android:textColor="#fff" android:text="My TEXT"/> </LinearLayout> </RelativeLayout>

Puede pensar en el fragmento como una vista que contiene dos botones en la parte inferior, en LinearLayout.

En lugar del RelativeLayout externo, realmente estoy usando una vista desde una biblioteca: SlidingUpPanelLayout ( https://github.com/umano/AndroidSlidingUpPanel ). Pero probé el comportamiento con este RelativeLayout: lo mismo, lo que significa que la biblioteca no está relacionada.

Digo esto solo para informarles que no puedo colocar allí FrameLayout y evitar dibujar fuera de los límites de recorte .

Sospecho que esto tiene algo que ver con el hecho de que cuando toco el botón se vuelve a dibujar, pero mi otra vista (que está en algún otro lugar de la jerarquía) no se vuelve a dibujar (esta es una optimización y dudo que pueda ser discapacitado).

Me gustaría poder invalidar mi vista personalizada cada vez que se invalide cualquier otra vista "cercana" (o cualquiera), así que necesito algún tipo de oyente en la invalidación de la vista, pero no conozco ninguna.

¿Alguien puede ayudar?