¿Cómo referenciar un control de otro durante la inflación?

Estoy tratando de hacer referencia a un control de hermanos a través de XML.

Para declarar un atributo para hacer referencia a un identificador de MyTextView:

<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MyTextView"> <attr name="valueTextViewId" format="reference" /> </declare-styleable> </resources> 

Fragment_example.xml – Cómo utilizar el atributo personalizado:

 <!-- Declare a "Title" text view that references a "Value" --> <com.example.MyTextView android:id="@+id/foo" example:valueTextViewId="@id/bar" ... /> <!-- Depending on the "text" attribute of this "Value" textview --> <!-- Do something within "Title" textview --> <com.example.MyTextView android:id="@+id/bar" /> 

MyFragment.java – Inflando los controles

 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // calls MyTextView Ctor View v = inflater.inflate(R.layout.fragment_example, container, false); } 

Constructor de la clase MyTextView – Durante la inflación, haga algo con la referencia textview:

 public TextView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.MyTextView); int refId = a.getResourceId(R.styleable.MyTextView_valueTextViewId); // Updated to use context if (refId > -1 && context instanceof Activity) { Activity a = (Activity)context; View v = a.findViewById(refId); // THE PROBLEM: v is null if (v != null) { // In my case, I want to check if the "Value" textview // is empty. If so I will set "this" textColor to gray } } } 

En este ejemplo v siempre es null . Supongo que durante la inflación de diseño, los controles no se añaden todavía. Otra cosa a tener en cuenta es que esto está en un Fragment , por lo tanto, podría ser la razón por la que no puedo encontrar la vista en la actividad de los padres.

¿Es posible referenciar un control de otro como este?

¿Es posible referenciar un control de otro como este?

Es posible hacer referencia a otra View desde una View .

Pero no se recomienda realizar comprobaciones de propiedades en el constructor de una View .
No hay garantía de que una View determinada se instancia antes de cualquier otra durante la visualización de la inflación .

Compare estos dos diseños:
first_layout.xml

 <com.example.MyTextView ... android:id="@+id/foo" example:valueTextViewId="@+id/bar" /> <com.example.MyTextView ... android:id="@+id/bar" /> 

second_layout.xml

 <com.example.MyTextView ... android:id="@+id/bar" /> <com.example.MyTextView ... android:id="@+id/foo" example:valueTextViewId="@+id/bar" /> 

En este ejemplo, está claro que la comprobación de propiedades del constructor no funcionará en uno de estos diseños.

Estoy de acuerdo en que es posible almacenar la referencia a otra View dentro de una View :

 public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyTextView); mReferenceId = a.getResourceId(R.styleable.MyTextView_valueTextViewId); ... } private int mReferenceId; public View getReferenceViewFromActivity() { if (getContext() instanceof Activity) { return ((Activity)getContext()).findViewById(mReferenceId); return null; } public View getReferenceView(View view) { return view.findViewById(mReferenceId); } 

Pero definitivamente debe hacer cualquier y toda la propiedad de verificación dentro de la Activity o Fragment :

 @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); MyTextView myTextView = (MyTextView)view.findViewById(R.id.foo); MyReferenceView refView = (MyReferenceView)myTextView.getReferenceView(view); // // do property checking // } 

Si un textview con el id de barra está disponible dentro del id de barra, puede hacer algo como esto.

 <com.example.MyTextView android:id="@+id/foo" ... android:tag="bar" /> <com.example.MyTextView android:id="@+id/bar" /> 

y

 public TextView(Context context, AttributeSet attrs) { super(context, attrs); int barId = getResources().getIdentifier(getTag(), "id", packageName); TextView bar = mActivity.findViewById(barId); if (bar.getText() == "") { // Gray out this "title" textview setColor(android.R.color.gray); } // maybe set a text change listener to bar to make it future-proof } 

Me gustaría simplemente pasar el ID como una etiqueta en su MyTextView por lo que no necesita crear un nuevo atributo.

Guarde las referencias en sus propios campos privados en el constructor. En su caso, guarde el refId en un campo privado. A continuación, utilícelos en la función onMeasure .


Yo le aconsejo que no use su enfoque de obtener la vista referenciada. Si nos fijamos en los casos habituales, como el layout_toLeftOf los hijos de layout_toLeftOf , notará que el id es siempre uno de los hijos de RelativeView y, por tanto, un hermano de la vista actual. En ese caso, es fácil obtener la vista obteniendo el padre, usando getParent() , lanzándolo a ViewGroup (no necesariamente) y encontrando la vista con la referencia, usando findViewById . Si usted puede hacer este tipo de limitación (id debe ser un hermano), tal vez puede deshacerse de esta dependencia en el contexto, que finalmente hará que su vista inutilizable. Probablemente es mejor ajustar la vista usando setBla () en lugar de usar su propio atributo (Tal vez lanzar un error de ejecución en su onMeasure si este setter no se llamó).

Por lo que sé, no hay garantía de que el diseño de la Activity's esté terminado de ser creado en el método onCreateView() del Fragment's .

Usted podría intentar este acercamiento en lugar de otro:

 @Override public void onActivityCreated(Bundle savedInstanceState){ mView.customMethodToSetTextColor(...) } 

onActivityCreated() se llama cuando se finaliza la creación de actividad y después de onCreateView() en el ciclo de vida del Fragment .

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.