How to refer to one control over another during inflation?

I am trying to reference a control using XML.

To declare an attribute for an id link from MyTextView:

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

fragment_example.xml - How to use a custom attribute:

 <!-- 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 - Overlay controls

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

MyTextView class constructor - during inflation, do something with a link to a text image:

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

in this example, v always null . I assume that controls are not yet added during the Inflation layout. Another thing to note is that this is in Fragment , so this may be the reason that I cannot find a representation in the parent activity.

Is it possible to associate a control with another in this way?

+6
source share
4 answers

Is it possible to associate a control with another in this way?

You can reference another View with a View .

However, to check for properties in the constructor View not recommended.
There is no guarantee that any particular View is created in any other way during the Inflation View .

Compare these two layouts:
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" /> 

In this example, it is clear that checking properties from the constructor will not work in one of these layouts.

I agree that you can save a link to another View within the 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); } 

But you definitely need to check the properties and all properties in an Activity or 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 // } 
+2
source

if a text view with a row id is available within the bar id, you can do something like this.

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

and

 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 } 

I would just pass id as a tag in MyTextView, so you don't need to create a new attribute.

+1
source

Save the links in your own private fields in the constructor. In your case, save the refId in a private field. Then use them in the onMeasure function.


I would advise you not to use your approach to viewing links. If you look at ordinary cases, such as RelativeView children layout_toLeftOf , you will notice that the identifier is always one of the children of the RelativeView and, therefore, is a child of the current view. In this case, it is easy to get the view by getting the parent using getParent() , translating it into a ViewGroup (optional) and finding the view with the link using findViewById . If you can make this restriction (id must be a sibling), you can get rid of this context dependency, which will ultimately render your view unusable. You are probably better off customizing the view using setBla () instead of using your own attribute (perhaps throwing a runtime error in your onMeasure if this setter was not called).

+1
source

As far as I know, there is no guarantee that the Activity's layout is complete, created in the Fragment's onCreateView() method.

Instead, you can try:

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

onActivityCreated() is called when the action is completed and after onCreateView() in the Fragment life cycle .

+1
source

Source: https://habr.com/ru/post/945650/


All Articles