5

I want to create a listview that is similar in functionality to the Gmail android app. By that I mean that you can select rows by clicking an image on the left or view an email by clicking anywhere else on the row. I can come close, but it's not quite there.

My custom row consists of an ImageView on the left and some TextViews on the right. Here's the gist of the getView on my Adapter.

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        View row = super.getView(position, convertView, parent);

        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getListView().setItemChecked(position, !getListView().isItemChecked(position));
            }
        });

        row.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getActivity(), "" + position, Toast.LENGTH_SHORT).show();
            }
        });
     }

This comes very close! What's missing is the highlighting of the row on the row click listener.

user140550
  • 919
  • 2
  • 11
  • 21
  • You are talking about `Contextual Menus` ? – Ye Lin Aung Aug 26 '13 at 03:05
  • No. Open the Gmail app, if you click on the left side of a row the row becomes selected. If you click anywhere else you are taken to the detail view (the contents of the email). – user140550 Aug 26 '13 at 03:08
  • Do you get the animation that flips your image into a check-box with this code? I'm trying to do the same, but I can't imagine that would be that simple? For the selection you need to set the background color of your row object when the row is actually selected and for that you need to save selection states yourself. Chanu's answer seems to be exactly what you need? – 3c71 Feb 16 '15 at 20:39

6 Answers6

4

Option 1: Use listView's inbuilt choiceMode feature. Unfortunately, I've never implemented. So, can't give you a detailed answer. But you can take a hint from here and other answers.

Option 2: Implement it on your own. Define an array/list or any work-around that keeps indexes of selected element of your list. And then use it to filter backgrounds in getView(). Here is a working example:

public class TestAdapter extends BaseAdapter {

List<String> data;
boolean is_element_selected[];

public TestAdapter(List<String> data) {
    this.data = data;
    is_element_selected = new boolean[data.size()];
}

public void toggleSelection(int index) {
    is_element_selected[index] = !is_element_selected[index];
    notifyDataSetChanged();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    //Initialize your view and stuff

    if (is_element_selected[position])
        convertView.setBackgroundColor(context.getResources().getColor(R.color.blue_item_selector));
    else
        convertView.setBackgroundColor(Color.TRANSPARENT);

     imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                toggleSelection(position);
            }
        });

      row.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //get to detailed view page
            }
        });

    return convertView;
}

Good luck!

Community
  • 1
  • 1
Gaurav Arora
  • 17,124
  • 5
  • 33
  • 44
2

This is how i made my getview method:

public View getView(final int position, View convertView, ViewGroup parent) {
    ViewHolder holder;

    LayoutInflater inflater = (LayoutInflater) context.getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    if (convertView == null) {
        convertView = inflater.inflate(R.layout.list_item, null);
        holder = new ViewHolder();
        holder.title = (TextView) convertView.findViewById(R.id.title);
        holder.selectBox = (ImageView) convertView.findViewById(R.id.selectBox);
        convertView.setTag(holder);
    }

    holder = (ViewHolder) convertView.getTag();

    holder.title.setText(getItem(position).getTitle());
    holder.selectBox.setTag("" + position);
    holder.selectBox.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            ivFlip = (ImageView) v;
            ivFlip.clearAnimation();
            ivFlip.setAnimation(animation1);
            ivFlip.startAnimation(animation1);
            setAnimListners(mailList.get(Integer.parseInt(v.getTag().toString())));
        }

    });

    if (mailList.get(position).isChecked()) {
        holder.selectBox.setImageResource(R.drawable.cb_checked);
        convertView.setBackgroundColor(context.getResources().getColor(R.color.list_highlight));

    } else {
        holder.selectBox.setImageResource(R.drawable.cb_unchecked);
        convertView.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.list_selector));

    }

    return convertView;

}

private void setAnimListners(final MyListItem curMail) {
    AnimationListener animListner;
    animListner = new AnimationListener() {

        @Override
        public void onAnimationStart(Animation animation) {
            if (animation == animation1) {
                if (curMail.isChecked()) {
                    ivFlip.setImageResource(R.drawable.cb_unchecked);
                } else {
                    ivFlip.setImageResource(R.drawable.cb_checked);
                }
                ivFlip.clearAnimation();
                ivFlip.setAnimation(animation2);
                ivFlip.startAnimation(animation2);
            } else {
                curMail.setIsChecked(!curMail.isChecked());
                setCount();
                setActionMode();
            }
        }

        // Set selected count
        private void setCount() {
            if (curMail.isChecked()) {
                checkedCount++;
            } else {
                if (checkedCount != 0) {
                    checkedCount--;
                }
            }

        }

        // Show/Hide action mode
        private void setActionMode() {
            if (checkedCount > 0) {
                if (!isActionModeShowing) {
                    mMode = ((MainActivity) context).startActionMode(new MainActivity.AnActionModeOfEpicProportions(context));
                    isActionModeShowing = true;
                }
            } else if (mMode != null) {
                mMode.finish();
                isActionModeShowing = false;
            }

            // Set action mode title
            if (mMode != null)
                mMode.setTitle(String.valueOf(checkedCount));

            notifyDataSetChanged();

        }

        @Override
        public void onAnimationRepeat(Animation arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onAnimationEnd(Animation arg0) {
            // TODO Auto-generated method stub

        }
    };

    animation1.setAnimationListener(animListner);
    animation2.setAnimationListener(animListner);

}

And i used two animations:

a) to_middle.xml :

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="200"
    android:fromXScale="1.0"
    android:fromYScale="1.0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toXScale="0.0"
    android:toYScale="1.0" />

b) from_middle.xml :

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="200"
    android:fromXScale="1.0"
    android:fromYScale="1.0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toXScale="0.0"/>

Hope this link will help you further: http://techiedreams.com/gmail-like-flip-animated-multi-selection-list-view-with-action-mode/

Chanakya Vadla
  • 3,019
  • 2
  • 22
  • 24
1

What you need is to set a listSelector.

What you'll need to do to create a listSelector is a xml drawable similar to the one Karl posted.

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <shape>
            <solid android:color="#929292" />
        </shape>
    </item>
    <!-- if you need even a disabled state -->
    <item android:state_enabled="false" android:drawable="@drawable/my_drawable" />
    <item>
        <shape>
            <solid android:color="#FFFFFF" />
        </shape>
    </item>
</selector>

As you can see, item tags can even use android:drawable attribute in case you have a png you want to use to highlight a row. Look for all the attributes this tags has to offer and implements what you need.

Finally, to make sure your ListView uses this selector, you must set it inside the xml layout:

<ListView
    android:id="@id/android:list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:choiceMode="multipleChoice"
    android:listSelector="@drawable/enel_list_selector"/>

or via code:

ListView listView = (ListView) <activity|view>.findViewById(android.R.id.list);
listView.setSelector(R.drawable.<nameOfYourXmlDrawable>);
0

You have to set a choiceMode to your ListView.

myListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
myListView().setSelector(android.R.color.BLUE);
pumpkee
  • 3,357
  • 3
  • 27
  • 34
  • This isn't it. I am setting choiceMode to `CHOICE_MODE_MULTIPLE_MODAL` - I want it to work just like the Gmail app so I need to be able to select multiple rows. – user140550 Aug 25 '13 at 06:43
0

What's missing is the highlighting of the row on the row click listener.

Sounds like you need to theme the listview row...

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true"
        <shape>
            <solid android:color="#929292" />
        </shape>
    </item>

    <item>
        <shape>
            <solid android:color="#FFFFFF" />
        </shape>
    </item>
</selector>

From here: How do I style selected item in Android ListView?

Community
  • 1
  • 1
Karl
  • 3,394
  • 2
  • 22
  • 31
0

Isn't that like some custom listview with imagebuttom instead of checkbox ?

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >

<ImageView
    android:id="@+id/ivImage"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_launcher"
    android:layout_gravity="left"
    android:contentDescription="@string/app_name" >
</ImageView>

<LinearLayout
    android:id="@+id/linearLayout1"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginLeft="5dp"
    android:orientation="vertical"
    android:layout_weight="1" >

    <TextView
        android:id="@+id/tvDescr"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:text=""
        android:textSize="20sp" >
    </TextView>

    <TextView
        android:id="@+id/tvPrice"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5dp"
        android:text="" >
    </TextView>
   </LinearLayout>


  </LinearLayout>
  • Yep, but apply the code I posted to this custom layout and then compare it to the Gmail app. The click on the ImageView works fine but if you click anywhere else on the row it does not highlight on click like the normal onItemListClick handler does. Here's a concrete example: In Gmail highlight 2 emails and then click in the non-select area. The row flashes blue and you are brought to the details view. My code with a layout like this does not flash blue when you click on the non-select area. – user140550 Aug 30 '13 at 03:59