41

I am using an AlertDialog (see the below code) and would like to put an image before each text.

For example, email icon then text "Email", Facebook icon then text "Facebook", etc.

Using the following code, how to add an icon before each text value?

final CharSequence[] items = { "Email", "Facebook", "Twitter", "LinkedIn" };
AlertDialog.Builder builder = new AlertDialog.Builder(More.this);
builder.setTitle("Share Appliction");
builder.setItems(items, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int item) {
        if (item == 0) {

        } else if (item == 1) {

        } else if (item == 2) {

        } else if(item == 3) {

        }
    }
});
AlertDialog alert = builder.create();
alert.show();
Alexander Farber
  • 21,519
  • 75
  • 241
  • 416
UMAR-MOBITSOLUTIONS
  • 77,236
  • 95
  • 209
  • 278

4 Answers4

92

You need custom ListAdapter to add your image. One way is to subclass the ArrayAdapter (used by default by the AlertDialog). Here is an example:

final Item[] items = {
    new Item("Email", android.R.drawable.ic_menu_add),
    new Item("Facebook", android.R.drawable.ic_menu_delete),
    new Item("...", 0),//no icon for this one
};

ListAdapter adapter = new ArrayAdapter<Item>(
    this,
    android.R.layout.select_dialog_item,
    android.R.id.text1,
    items){
        public View getView(int position, View convertView, ViewGroup parent) {
            //Use super class to create the View
            View v = super.getView(position, convertView, parent);
            TextView tv = (TextView)v.findViewById(android.R.id.text1);

            //Put the image on the TextView
            tv.setCompoundDrawablesWithIntrinsicBounds(items[position].icon, 0, 0, 0);

            //Add margin between image and text (support various screen densities)
            int dp5 = (int) (5 * getResources().getDisplayMetrics().density + 0.5f);
            tv.setCompoundDrawablePadding(dp5);

            return v;
        }
    };


new AlertDialog.Builder(this)
    .setTitle("Share Appliction")
    .setAdapter(adapter, new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int item) {
            //...
        }
    }).show();

Here is the Item class

public static class Item{
    public final String text;
    public final int icon;
    public Item(String text, Integer icon) {
        this.text = text;
        this.icon = icon;
    }
    @Override
    public String toString() {
        return text;
    }
}
Tom Esterez
  • 21,567
  • 8
  • 39
  • 44
  • 1
    Is there a way to set the drawable size ? – Muzikant Aug 30 '11 at 22:11
  • 1
    Never mind, just found out how to do it... call setBounds with the required size and then call setCompoundDrawables instead of setCompoundDrawablesWithIntrinsicBounds – Muzikant Aug 31 '11 at 18:40
  • Hi, this works but the size of the text of an item is not the default - it is too big. Any thoughts how I can set it to the default texts size? – Nedko Dec 03 '15 at 14:38
  • 1
    Ok, I managed to get the right size. Instead of `android.R.layout.select_dialog_item` use `typedArray.getResourceId(R.styleable.AlertDialog_listItemLayout, 0)`. The typed array is defined like that: `TypedArray typedArray = context.obtainStyledAttributes(null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);` . I took this directly from the support library code for the alert dialog listview. – Nedko Dec 04 '15 at 16:41
  • Even with `getResourceId` like how @Nedko showed above, it still doesn't render the items like how it looks when using `setItems()`. The item left padding seems to be smaller and makes the items misaligned with title. Any idea how to fix this? – Don Box Jul 14 '19 at 08:20
  • Hey, Do you mind helping me, why it does not accept tap? – Samrez Ikram May 11 '20 at 02:22
2

Do something like this:

ViewGroup layout=new LinearLayout(context);
TextView tv=new TextView(context); //your text
tv.setText("my text"); 
ImageView imageView=new ImageView(context); //your icon
//filling image view with icon bitmap (in this case from resource)
imageView.setImageBitmap(BitmapFactory.decodeStream(context.getResources().openRawResource(resourceId)));
//ensuring that icon size will be more or less like text height
imageView.setAdjustViewBounds(true);
imageView.setMaxHeight((int )(tv.getLineHeight()*1.5));
imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
layout.addView(imageView); //adding icon
tv.setGravity(Gravity.BOTTOM|Gravity.LEFT);
layout.addView(tv); //adding text

Total idea is to create layout/viewgroup and add icon+text+whatever you want into viewgroup

naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
Barmaley
  • 16,638
  • 18
  • 73
  • 146
  • how to associate it with alert? – UMAR-MOBITSOLUTIONS Oct 13 '10 at 06:05
  • AlertDialog usually contains ListView which shows messages. So try to get like AlertDialog.getListView(); And then add your layout containing whole stuff with Icon/Text add to listView. like: AlertDialog.getListview().add(layout) – Barmaley Oct 15 '10 at 09:56
1

To scale images:

//Put the image on the TextView
int dp50 = (int) (50 * getResources().getDisplayMetrics().density + 0.5f);
Drawable dr = getResources().getDrawable(R...YOUR_DRAWABLE);
Bitmap bitmap = ((BitmapDrawable) dr).getBitmap();
Drawable d = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(bitmap, dp50, dp50, true));
tv.setCompoundDrawablesWithIntrinsicBounds(d, null, null, null);

// Add margin between image and text (support various screen densities)
int dp10 = (int) (10 * getResources().getDisplayMetrics().density + 0.5f);
tv.setCompoundDrawablePadding(dp10);
Jared Rummler
  • 37,824
  • 19
  • 133
  • 148
Geltrude
  • 1,093
  • 3
  • 17
  • 35
1

I like Tom Esterez's solution but recommend using the relative function instead for RTL support.

So use this:

tv.setCompoundDrawablesRelativeWithIntrinsicBounds(items[position].iconID, 0, 0, 0);

instead of this:

tv.setCompoundDrawablesWithIntrinsicBounds(items[position].iconID, 0, 0, 0);
Alexander Farber
  • 21,519
  • 75
  • 241
  • 416
Barina
  • 53
  • 8