jul
jul

Reputation: 37484

How to change adapter layout dynamically?

I have a custom Adapter in which I'd like the row layout to change according to the orientation.

I have a function setOrientation in which I modify the layout and call notifyDataSetChanged(), hoping that everything would be reset.

Unfortunately, it seems that it is not because even after notifyDataSetChanged(), the convertView in the first call of getView() is not null, so the layout is not changed.

Is there any way to reset this convertView?

public class TableRowsAdapter extends BaseAdapter {

    private LayoutInflater layoutInflater;

    private int layout;

    private TableRow[] items;

    private class ViewHolder {
        /* some stuff */
    }

    public TableRowsAdapter(Context context, TableRow[] tableRowList)
    {
        super();
        this.items = tableRowList;
        this.layoutInflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );

        /* Set default layout to portrait */
        layout = R.layout.table_row;
    }

    public void setOrientation(int orientation){

        if(orientation== Configuration.ORIENTATION_LANDSCAPE){
            layout = R.layout.table_row_land;
        }
        else{
            layout = R.layout.table_row;
        }

        notifyDataSetChanged();
    }

    public int getCount()
    {
        return items.length;
    }

    public TableRow getItem(int position)
    {
        return items[position];
    }

    public long getItemId(int position)
    {
        return position;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {

        ViewHolder holder;
        View v = convertView;

        if (v == null) {

            v = layoutInflater.inflate(layout, parent, false);

            holder = new ViewHolder();

            /* some stuff */

            v.setTag(holder);
        } else {
            holder = (ViewHolder) v.getTag();
        }

        TableRow item = getItem(position);

        /* some stuff */

        return v;
    }
}

Upvotes: 3

Views: 4973

Answers (3)

Palak
Palak

Reputation: 2215

Create one file table_row.xml and put res/layout folder and create another file with same name table_row.xml which is same as table_row_land.xml and put in to res/layout-land.

and in adapter set table_row.xml

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {

        ViewHolder holder;
        View v = convertView;

        if (v == null) {

            v = layoutInflater.inflate(R.layout.table_row, parent, false);
        }
        ...
        ...
        ...

     }

Upvotes: 1

tom91136
tom91136

Reputation: 8972

Fastest way: create a new instance of TableRowsAdapter and set it again(make the orientation a constructor parameter). Example:

 public TableRowsAdapter(Context context, TableRow[] tableRowList, int orientation)
  {
    super();
    this.items = tableRowList;
    this.layoutInflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );


    if(orientation== Configuration.ORIENTATION_LANDSCAPE){
        layout = R.layout.table_row_land;
    }
    else{
        layout = R.layout.table_row;
    }

}

The proper way:

when you setOrientation, inflate the new layout and replace convertView with that

Reason: notifyDatasetChanged() does not know that you'll replace the layout, so it simply recycles the view thus making convertView not null.

In layout R.layout.table_row_land and R.layout.table_row, add an unique id for the root view,

Example:

id for R.layout.table_row_land is R.id.row_land and R.layout.table_row is R.id.row_normal

The root view would become something like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@+id/row_normal"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:orientation="vertical" >
<!-- the rest of the layout  -->

</LinearLayout>

And here's a simple pseudo implementation:

@Override
public View getView(final int position, View convertView, ViewGroup parent) {

    ViewHolder holder;
    View v = convertView;

    // check if convertView needs a new layout here
    if (v == null || (v.getId() == R.id.row_normal && layout == R.layout.table_row_land)) {

        v = layoutInflater.inflate(layout, parent, false);

        holder = new ViewHolder();

        /* some stuff */

        v.setTag(holder);
    } else {
        holder = (ViewHolder) v.getTag();
    }

    TableRow item = getItem(position);

    /* some stuff */

    return v;
}

Upvotes: 4

Hradesh Kumar
Hradesh Kumar

Reputation: 1805

Make Both of Two Views in your layout(in same XML) and set visibility gone for second layout.inflate it as you have already done, and in get view method make visibility of view according to orientation.

@Override public View getView(final int position, View convertView, ViewGroup parent) {

    ViewHolder holder;
    View v = convertView;

    if (v == null) {

        v = layoutInflater.inflate(layout, parent, false);

        holder = new ViewHolder();

        /* some stuff */

        v.setTag(holder);
    } else {
        holder = (ViewHolder) v.getTag();
    }

    TableRow item = getItem(position);

    /* some stuff */

      if(portrait) {
      // then visiblity of first View or View Group set Visible and
      // visiblity of second View or View Group set Gone
   } else {
   // then visiblity of first View or View Group set GONE and
      // visiblity of second View or View Group set Visible. 
    }

    return v;
}

Upvotes: 0

Related Questions