Torsten Robitzki Torsten Robitzki - 2 months ago 9
Android Question

How to obtain the value for a reference attribute

I want to implement a SeekBar that automatically updates a TextView, for the actual value, the maximum value and a minimum value. I derive from SeekBar and define 3 named attributes with the

format
being
reference
.

In the constructor, I get a
TypedArray
by calling
obtainStyledAttributes()
.
TypedArray
contains a lot of getters for every kind of attribute types. What I am missing is some kind of
Object getReference()
or
int getReferenceId()
.

How do I obtain the value for a reference attribute?

Edit:

I have an attribute definition for a class
MinMaxSlider
, that looks like this:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MinMaxSlider">
<attr name="min" format="integer" />
<attr name="valueView" format="reference" />
</declare-styleable>
</resources>


a snipped out of the layout definition looks like this:

<LinearLayout
style="@style/ParameterLabelLayout"
android:orientation="horizontal">
<TextView
style="@style/ParameterSliderLabel"
android:text="min. Interval" />
<TextView
android:id="@+id/min_connection_interval_slider_value"
style="@style/ParameterSliderValue"/>
</LinearLayout>

<com.roche.rcpclient.MinMaxSlider
style="@style/ParameterSlider"
android:id="@+id/min_connection_interval_slider"
android:max="3200"
custom:valueView="@id/min_connection_interval_slider_value"
custom:min="1"/>


Here, the
MinMaxSlider
should reference one of the TextViews above to display its current value there.

From within the constructor of
MinMaxSlider
, I can lookup the min attributes value.

If I try to lookup the valueView attribute as an integer, I always get the default value (0), not
R.id.min_connection_interval_slider
as I would expect.

Edit: the right function to lookup a
reference
seems to be
getResourceId
. The obtained integer id can be used to use
findViewById
later, when the overall object hierarchy is constructed.

In my case, I register an
OnSeekBarChangeListener()
and lookup the View in the callback, when the callback is fired.

Answer

You can't receive reference via findViewById in constructor. Because it is not attached to layout yet. Reference: https://developer.android.com/training/custom-views/create-view.html#applyattr

When a view is created from an XML layout, all of the attributes in the XML tag are read from the resource bundle and passed into the view's constructor as an AttributeSet. Although it's possible to read values from the AttributeSet directly, doing so has some disadvantages:

Resource references within attribute values are not resolved Styles are not applied Instead, pass the AttributeSet to obtainStyledAttributes(). This method passes back a TypedArray array of values that have already been dereferenced and styled.

You can receive in another methods. For example:

attrs.xml

 <declare-styleable name="CustomTextView">
    <attr name="viewPart" format="reference"></attr>
 </declare-styleable>

yourLayout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:baselineAligned="false"
    android:gravity="center_vertical"
    android:orientation="horizontal">

  <tr.com.ui.utils.CustomTextView
                        android:id="@+id/chat_msg"                           
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="right|bottom"
                        android:focusableInTouchMode="false"
                        android:gravity="left"                          
                        android:text="test"
                        app:viewPart="@id/date_view" />



                    <TextView
                        android:id="@+id/date_view"                         
                        android:layout_alignParentBottom="true"
                        android:layout_alignParentRight="true"                          
                        android:gravity="right" />

</LinearLayout>

CustomTextView.java

   public class CustomTextView extends TextView {
    private View viewPart;
    private int viewPartRef;

    public CustomTextView(Context context) {
        super(context);
    }

    public CustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomTextView, 0, 0);

        try {
            viewPartRef = a.getResourceId(R.styleable.CustomTextView_viewPart, -1);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        viewPart = ((View) this.getParent()).findViewById(viewPartRef);
    }    

    public View getViewPart() {
        return viewPart;
    }

    public void setViewPart(View viewPart) {
        this.viewPart = viewPart;
    }}

You can decide your scenario and modify this code. Greets.

Comments