Setting multiple custom elements to MultiAutoCompleteTextView : Android
Asked Answered
Z

2

8

Continuing from my previous post, I was able to set multiple elements to the MultiAutoCompleteTextView but I was not able to wrap those items with custom background and close button as in that link picture.

I was able to do the same with single element but for multiple, ran out of luck.

This is what I tried.

// set text to MultiAutoCompleteTextView

private void setTextSample(String contactName) {

    final SpannableStringBuilder sb = new SpannableStringBuilder();
    TextView tv = (TextView) LayoutInflater.from(this).inflate(R.layout.textview, null);
    tv.setText(contactName);
    BitmapDrawable bd = (BitmapDrawable) convertViewToDrawable(tv);
    bd.setBounds(0, 0, bd.getIntrinsicWidth(), bd.getIntrinsicHeight());

    sb.append(contactName + ",");
    sb.setSpan(new ImageSpan(bd), sb.length()-(contactName.length()+1), 
            sb.length()-1,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

    mMultiAutoCompleteTextView.setText(sb);
}

// wrap text with custom elements

private static Object convertViewToDrawable(View view) {
  int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
  view.measure(spec, spec);
  view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
  Bitmap b = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(),
            Bitmap.Config.ARGB_8888);
  Canvas c = new Canvas(b);
  c.translate(-view.getScrollX(), -view.getScrollY());
  view.draw(c);
  view.setDrawingCacheEnabled(true);
  Bitmap cacheBmp = view.getDrawingCache();
  Bitmap viewBmp = cacheBmp.copy(Bitmap.Config.ARGB_8888, true);
  view.destroyDrawingCache();
  return new BitmapDrawable(viewBmp);
}

Any help is greatly appreciated.

Edit :

If I do

mMultiAutoCompleteTextView.setText(mMultiAutoCompleteTextView.getText().toString()+", "+sb);

I am getting multiple texts but they are not wrapped with custom background. Not getting where I am going wrong.

Edit :

Sample multiple elements would look something like this

enter image description here

Zolnay answered 30/10, 2013 at 7:34 Comment(3)
cross button? what cross button?Matterhorn
i meant close button which is used as an indicator to remove itemZolnay
If you write smth like that mMultiAutoCompleteTextView.setText(sb);, is it Works?Doorstop
M
11

try this:

class MyMultiAutoCompleteTextView extends MultiAutoCompleteTextView {

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

    @Override
    protected void replaceText(CharSequence text) {
        Log.d(TAG, "replaceText " + text.getClass() + " " + text);
        super.replaceText(getSpanned(text.toString()));
    }
}

private Spanned getSpanned(String name) {
    TextView tv = (TextView) LayoutInflater.from(this).inflate(R.layout.test, null);
    tv.setText(name);
    SpannableStringBuilder sb = new SpannableStringBuilder(name);
    sb.setSpan(new ViewReplacementSpan(tv), 0, sb.length(),Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    return sb;
}

class ViewReplacementSpan extends DynamicDrawableSpan {
    private View v;
    private Drawable drawable;

    public ViewReplacementSpan(View v) {
        super(ALIGN_BOTTOM);
        this.v = v;
        int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        v.measure(spec, spec);
        v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
        drawable = new SpanDrawable();
        drawable.setBounds(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
    }

    @Override
    public Drawable getDrawable() {
        return drawable;
    }

    class SpanDrawable extends Drawable {
        @Override
        public void draw(Canvas canvas) {
            canvas.clipRect(getBounds());
            v.draw(canvas);
        }

        @Override
        public void setAlpha(int alpha) {
        }

        @Override
        public void setColorFilter(ColorFilter cf) {
        }

        @Override
        public int getOpacity() {
            return PixelFormat.TRANSLUCENT;
        }
    }
}

test it with the following in onCreate():

LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);

MultiAutoCompleteTextView mactv = new MyMultiAutoCompleteTextView(this);
ArrayAdapter<Spanned> a = new ArrayAdapter<Spanned>(this, android.R.layout.simple_dropdown_item_1line);
String[] names = { "Jane", "John", "Mary", "Mark" };
for (String name: names) {
    a.add(getSpanned(name));
}

Tokenizer tokenizer = new MultiAutoCompleteTextView.CommaTokenizer();
mactv.setTokenizer(tokenizer);
mactv.setAdapter(a);
mactv.setThreshold(1);
SpannableStringBuilder sb = new SpannableStringBuilder();
for (int i = 0; i < 2; i++) {
    sb.append(tokenizer.terminateToken(a.getItem(i)));
}
mactv.setText(sb);
ll.addView(mactv);

TextView tv = new TextView(this);
tv.setGravity(Gravity.CENTER);
tv.setText("try: Jane, John, Mary or Mark");
tv.setTextSize(32);
ll.addView(tv);
setContentView(ll);
Matterhorn answered 30/10, 2013 at 7:34 Comment(29)
Its setting initial items properly now but if i delete and/or try to set items from suggestion drop down, i am getting plain text.Zolnay
no, items from drop down list are inserted into mactv as spans, did you run all of my code or just part of it?Matterhorn
oops... if i run it as separate app, working fine. Something wrong with integration with existing app. Will revert back in some time. Thanks.Zolnay
Got it working. Thanks a lot for d response. Finally it was SpannableStringBuilder i was missing.Zolnay
@Matterhorn what is this R.layout.test?Frisky
@Matterhorn Is there any library that mimics this? Can you please post the whole code for this?Telekinesis
@androiddeveloper mimics what?Matterhorn
@Matterhorn mimics the way hangouts and gmail shows the "TO" field, which you can put some text, and it auto-suggests it, and you can delete items there by either clicking them (to select, and them click again to remove) or pressing the backspace... I've found the next libraries: github.com/arriolac/TokenAutoComplete , github.com/splitwise/TokenAutoComplete . are they good at mimicking gmail/hangouts ?Telekinesis
@androiddeveloper see blog.splitwise.com/2013/09/24/…Matterhorn
@androiddeveloper it works but what they did. is hudreds of lines of redundant codeMatterhorn
i've now tested their sample. it work, but: I don't get how to set the layout to change based on clicking on items before deleting them (like on gmail/hangouts) , and it has some rare crashing bugs which I'm not sure when they occur (I think it's related to losing the focus), and some other weird bugs (example: try to have it empty on the beginning, write "max" and complete it, and then press backspace)Telekinesis
@androiddeveloper thats why i said that they wrote more than 1000 lines of cide and it could be done in more or less 100 lines... that is 10 times shorterMatterhorn
@Matterhorn do you know of an alternative? if so, can you please show a link to it? maybe, if you already have a nice SDK , could you please post it to github ?Telekinesis
@androiddeveloper this what i wrote in 30 mins (ok i had already working auto complete text view with contacts support, just added chips): gist.github.com/pskink/5fe9c0bb4677c1debc5eMatterhorn
@Matterhorn didn't test it yet since i left the office. hopefully will try in the next few days.Telekinesis
@Matterhorn The code works, but it's quite buggy. for example, try typing the beginning of a name of someone, and select the second contact, and then continue typing . instead of resetting what you've written, it will continue from the previous one. also, clicking on an item will immediatly remove it without the ability to handle it myself (allowing to long click or change how it looks before removing it). also, the deletion leaves 2 "," instead of one (or zero).Telekinesis
@androiddeveloper these cosmetic things can be easly changed, after all, chips feature was added in half an hour...Matterhorn
@Matterhorn what about the bugs ?Telekinesis
@androiddeveloper as i said they are cosmetic changes, see it nowMatterhorn
@Matterhorn but it's not cosmetic. I type "ab", then choose an item. then press backspace, and you will see the "ab" again... How do I even do something when clicking on the ChipSpan (the completed items), or customize how they look? the context menu also doesn't work...Telekinesis
@androiddeveloper pressing the backspace on selected item works that way, its default behaviour of MACTV, you can change look of ChipSpan in its draw methodMatterhorn
@Matterhorn well that's not how gmail and hangouts work. deleting will delete the item and leave no trace of what you've written before. it's also more intuitive this way, since the app knows that the item was selected and therefore deletion should be of the item including its text that made it. Also, what's "MACTV" ?Telekinesis
@Matterhorn ok, anyway, i've also noticed that this behavior is different on my device (Galaxy S3) then on others (like the Nexus 4). only on mine it shows the text instead of removing it. in fact, the text doesn't get reset even if I continue writing (instead of deleting) , so it's 2 bugs on my device.Telekinesis
@Matterhorn in the end, I've decided to use Google's code. I've found it here: plus.google.com/+RichHyndman/posts/TSxaARVsRjF , and you can grab the code here: android.googlesource.com/platform/frameworks/ex/+/…Telekinesis
@androiddeveloper great but if its not standalone component it will probably require much work to integrate withMatterhorn
@Matterhorn correct. I have looked at the code and it's awful to read and change. thankfully, i think I won't need to (even though I wanted).Telekinesis
@androiddeveloper but still it can be helpful to look for some specific tricks/tips they used for some featuresMatterhorn
@Matterhorn it's quite hard. they made a very long code for some of their classes, and made everything very tight to it. I've now written a post hoping that if I ever wish to customize it, maybe someone will have the answer: #22836388Telekinesis
@androiddeveloper i made some modifications to my gist snippet and now it is more similar to the image you posted in your additional questionMatterhorn
M
2

I think you have problem here:

mMultiAutoCompleteTextView.setText(mMultiAutoCompleteTextView.getText().toString()+", "+sb);

When you call mMultiAutoCompleteTextView.getText().toString(), you convert your spannableString to ordinary string, which can't hold background or smth else.

Try to save your current SpannableStringBuilder somewhere and work like that:

mBuilder.append(sb);
  mMultiAutoCompleteTextView.setText(mBuilder);
Mobley answered 30/10, 2013 at 7:34 Comment(2)
Thanks a lot for d response. Will try it.Zolnay
Got it working. Thanks a lot for d response. Finally it was SpannableStringBuilder i was missingZolnay

© 2022 - 2024 — McMap. All rights reserved.