studio programacion herramientas fundamentos con avanzado aplicaciones android custom-view

programacion - ¿Cómo pasar la referencia de vista a la vista personalizada de Android?



manual de android en pdf (3)

Hice lo siguiente

1) Creando un styleable

<declare-styleable name="Viewee"> <attr name="linkedView" format="reference"/> </declare-styleable>

2) definiendo diseño de vista personalizado

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#ffc0"> <TextView android:id="@+id/custom_text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="[text]" /> </LinearLayout>

3) Creando la clase requerida

public class Viewee extends LinearLayout { public Viewee(Context context, AttributeSet attributeSet) { super(context, attributeSet); View.inflate(context, R.layout.viewee, this); TextView textView = (TextView) findViewById(R.id.custom_text); TypedArray typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.Viewee); int id = typedArray.getResourceId(R.styleable.Viewee_linkedView, 0); if (id != 0) { View view = findViewById(id); textView.setText(((TextView) view).getText().toString()); } typedArray.recycle(); } }

y finalmente en una actividad como la de abajo.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res/com.ns" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <TextView android:id="@+id/tvTest" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="android"/> <com.ns.Viewee android:layout_width="fill_parent" android:layout_height="fill_parent" app:linkedView="@+id/tvTest" /> </LinearLayout>

ahora, aunque recibo un id distinto de cero en ViewView constractor, findViewById(id) retuns null y ocurre NullPointerException .

¿Qué me estoy perdiendo?

Lo hice como se describe aquí


¡Encontré la respuesta!

El problema fue con findViewById(id) y donde lo llamé. findViewById solo busca una vista secundaria, no existe una vista en el nivel de jerarquía superior como dice la documentation . Así que tengo que llamar a algo como getRootView().findViewById(id) pero eso también devuelve null porque el lugar al que llamé no era correcto.

En Viewee constractor Viewee no se ha adjuntado a su raíz aún, por lo que la llamada causa NullPointerException .

Entonces, si llamo a getRootView().findViewById(id) algún otro lugar después de la construcción, funciona bien y tanto "@+id/tvTest" como "@id/tvTest" son correctos. ¡Lo he probado!

La respuesta es la siguiente

public class Viewee extends LinearLayout { public Viewee(Context context, AttributeSet a) { super(context, attributeSet); View.inflate(context, R.layout.main6, this); TextView textView = (TextView) findViewById(R.id.custom_text); TypedArray t = context.obtainStyledAttributes(a, R.styleable.Viewee); int id = t.getResourceId(R.styleable.Viewee_linkedView, 0); if (id != 0) { _id = id; } t.recycle(); } private int _id; public void Foo() { TextView textView = (TextView) findViewById(R.id.custom_text); View view = getRootView().findViewById(_id); textView.setText(((TextView) view).getText().toString()); } }

y se llama a Foo cuando se requiere que procese la vista adjunta a través de su ID de referencia en otro lugar de su actividad y similares.

El crédito es completamente para aquellos que contribuyeron en esta publicación . No había visto ese post antes de enviar la pregunta.


Sé que esta es una pregunta antigua, pero pensé que agregaría otra forma de hacerlo ya que quería resumir todo en mi vista personalizada.

En lugar de llamar desde el exterior, otra forma de obtener una vista más alta en la jerarquía, me he conectado a onAttachedToWindow() lugar:

public class MyCustomView extends LinearLayout { private int siblingResourceId; private View siblingView; public MyCustomView(Context context, AttributeSet a) { super(context, attributeSet); inflate(context, R.layout.main6, this); TextView textView = (TextView) findViewById(R.id.custom_text); TypedArray t = context.obtainStyledAttributes(a, R.styleable.Viewee); siblingResourceId = t.getResourceId(R.styleable.MyCustomView_siblingResourceId, NO_ID); t.recycle(); } @Override public void onAttachedToWindow() { super.onAttachedToWindow(); if (siblingResourceId != NO_ID) { siblingView = ((View) getParent()).findViewById(siblingResourceId); } } }

onAttachedToWindow se llama bastante pronto, pero aparentemente lo suficientemente tarde para que toda la jerarquía de vistas se haya establecido. Funciona impecable al menos para mis necesidades y está un poco más controlado y no necesita interacción desde el exterior para trabajar ;-)

EDITAR: código Kotlin añadido

class MyCustomView(context: Context, attributeSet: AttributeSet) : LinearLayout(context, attributeSet) { private val siblingResourceId: Int private lateinit var siblingView: View // All other constructors left out for brevity. init { inflate(context, R.layout.main6, this) val textView = findViewById<TextView>(R.id.custom_text) val t = context.obtainStyledAttributes(a, R.styleable.Viewee) siblingResourceId = t.getResourceId(R.styleable.MyCustomView_siblingResourceId, NO_ID) t.recycle() } override fun onAttachedToWindow() { super.onAttachedToWindow() if (siblingResourceId != NO_ID) { siblingView = (parent as View).findViewById(siblingResourceId) } } }

Nota: Suponemos que el elemento parent de esta View personalizada es una View sí misma.


Su android:id descrito se establece en app:linkedView="@+id/tvTest . Sin embargo, @+id/tvTest se usa para crear una nueva identificación con el nombre" tvTest ". Lo que desea hacer es usar app:linkedView="@id/tvTest .