PearsonArtPhoto
PearsonArtPhoto

Reputation: 39698

Set an XML file as a custom View?

I have a custom Table Row that I am in the process of making. I want to use an XML file to define what a single row looks like. I would like to have a class extend TableRow and define itself to be the file as defined in the XML. The XML file might look like:

<TableRow xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <TextView
        android:id="@+id/label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingRight="10dp"
        android:text="@string/loading"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <TextView
        android:id="@+id/data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="right"
        android:text="@string/loading"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</TableRow>

And the code might look like:

public class SpecialTableRow extends TableRow {

    public SpecialTableRow (Context context) {
        }
}   

Is there something that I can put into the constructor to have the class assume it is the tableRow in it's entirety? Alternatively, is there another structure which would work better? The best that I've figured out is this:

    TableRow tr=(TableRow) LayoutInflater.from(context).inflate(R.layout.text_pair,null);
    TextView mFieldName=(TextView) tr.findViewById(R.id.label);
    TextView mValue=(TextView) tr.findViewById(R.id.data);
    tr.removeAllViewsInLayout();
    addView(mFieldName);
    addView(mValue);

But this removes the layout parameters from the XML. Anything better out there?

Upvotes: 1

Views: 2745

Answers (3)

PearsonArtPhoto
PearsonArtPhoto

Reputation: 39698

The real trick to doing this is actually quite simple. Use the second parameter of the inflate method. In fact, the best thing to do is this:

LayoutInflater.from(context).inflate(R.layout.text_pair,this);

This will inflate the R.layout.text_pair into this, effectively using the entire row. No need to add the view manually, Android takes care of it for you.

Upvotes: 1

KMDev
KMDev

Reputation: 615

Take a look at the tutorial on creating custom views. You will want to subclass TableRow and add the additional views you want to display. Then, you can use your new view directly in your XML layouts and additionally create any custom attributes you might want. I've included an example which creates a custom TableRow named TextPairRow, inflates a layout with two TextViews to show within the TableRow and adds showLabel and showData custom attributes which show/hide the two TextViews. Finally, I've included how you would use your new view directly in your XML layouts.

class TextPairRow extends TableRow {

    private TextView label, data;

     public TextPairRow (Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray a = context.getTheme().obtainStyledAttributes(
                                           attrs,
                                           R.styleable.TextPairRow, 0, 0);

        try {
            showLabel = a.getBoolean(R.styleable.TextPairRow_showLabel, false);
            showData = a.getBoolean(R.styleable.TextPairRow_showData, false);
        } finally {
            a.recycle();
        }

        initViews();
    }

    private void initViews(){

       // Here you can inflate whatever you want to be in your 
       // view or add views programatically.
       // In this example, we'll just assume you have a basic XML 
       // layout which defines a LinearLayout with two TextViews.
       LinearLayout mLayout = (LinearLayout) 
           LayoutInflater.from(getContext()).inflate(R.layout.textview_layout, this);

       label = (TextView) mLayout.findViewById(R.id.label);
       data = (TextView) mLayout.findViewById(R.id.data);

       if(showLabel)
           label.setVisibility(View.VISIBLE);
       else
           label.setVisibility(View.GONE); // can also use View.INVISIBLE 
                                           // depending on your needs

       if(showData){
           data.setVisibility(View.VISIBLE);
       else
           data.setVisibility(View.GONE); // can also use View.INVISIBLE 
                                           // depending on your needs
    }
}

This is where you define your custom XML attributes (locate or create this file: res/values/attrs.xml)

<resources>
   <declare-styleable name="TextPairRow">
       <attr name="showText" format="boolean" />
       <attr name="showLabel" format="boolean" />
   </declare-styleable>
</resources>

Finally, to use your new view directly in your XML layouts:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto">
 <com.thefull.packageforyourview.TextPairRow    
     android:orientation="horizontal"
     custom:showData="true"
     custom:showLabel="true" />
</LinearLayout>

Note that you might need to use xmlns:custom="http://schemas.android.com/apk/res/com.thefull.packageforyourview" depending on if your custom view will be in a library project. Regardless, either this or what's in the example will work.

Upvotes: 1

nstosic
nstosic

Reputation: 2614

The only thing I can think of is to use a static method instead of constructor. For example:

public static void newInstance (Context context) {
    this = context.getLayoutInflater().inflate(R.layout.text_pair, null, null);
}

Then don't use constructor for initializing an object, call this method.

Upvotes: 0

Related Questions