【问题标题】:Creating a custom editText with tag-like feature创建具有类似标签功能的自定义 editText
【发布时间】:2012-07-04 08:03:38
【问题描述】:

我一直在寻找,但找不到任何答案。我要实现的是一个类似于 ICS gmail 应用程序的撰写屏幕中的“收件人”字段的 EditText。

这是一张描述我想要的图片:

我正在考虑扩展 EditText 并实现我自己的自定义 EditText 类,但我不确定如何做到这一点,或者即使这是最好的解决方案。有什么想法吗?

【问题讨论】:

  • 即兴发挥,我猜您在Spannable 上看到了一个常规的EditText,其中包含“标签”的ImageSpan 元素。但是,如果那些“x”部分意味着点击标签会删除它,那么我认为ImageSpan 是不可能的。
  • 嗯,这听起来很合理,但是是的,谷歌让它在他们的 gmail 应用程序上工作(用小“x”删除它)所以我很确定某处有一个完整的解决方案。希望这不是太多的黑客攻击
  • @BillX:我可以知道您决定使用什么解决方案吗?谢谢!
  • @LocHa 抱歉回复晚了,这是不久前的事了 :)。但我认为我选择了与我在下面发布的内容接近的内容。我后来发现的另一个好资源是kpbird.com/2013/02/android-chips-edittext-token-edittext.html

标签: android android-edittext custom-component


【解决方案1】:

改编自 this answer 的解决方案。插入逗号时自动分隔输入(分隔符可以调整)。创建一个 ImageSpan 和一个 ClickableSpan(可以通过单击右侧部分来删除条目)。

public class TagEditText extends EditText {

    TextWatcher textWatcher;

    String lastString;

    String separator = ",";

    public TagEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }


    private void init() {
        setMovementMethod(LinkMovementMethod.getInstance());

        textWatcher = new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                String thisString = s.toString();
                if (thisString.length() > 0 && !thisString.equals(lastString)) {
                    format();

                }
            }
        };

        addTextChangedListener(textWatcher);
    }


    private void format() {

        SpannableStringBuilder sb = new SpannableStringBuilder();
        String fullString = getText().toString();

        String[] strings = fullString.split(separator);


        for (int i = 0; i < strings.length; i++) {

            String string = strings[i];
            sb.append(string);

            if (fullString.charAt(fullString.length() - 1) != separator.charAt(0) && i == strings.length - 1) {
                break;
            }

            BitmapDrawable bd = (BitmapDrawable) convertViewToDrawable(createTokenView(string));
            bd.setBounds(0, 0, bd.getIntrinsicWidth(), bd.getIntrinsicHeight());

            int startIdx = sb.length() - (string.length());
            int endIdx = sb.length();

            sb.setSpan(new ImageSpan(bd), startIdx, endIdx, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

            MyClickableSpan myClickableSpan = new MyClickableSpan(startIdx, endIdx);
            sb.setSpan(myClickableSpan, Math.max(endIdx-2, startIdx), endIdx, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

            if (i < strings.length - 1) {
                sb.append(separator);
            } else if (fullString.charAt(fullString.length() - 1) == separator.charAt(0)) {
                sb.append(separator);
            }
        }


        lastString = sb.toString();

        setText(sb);
        setSelection(sb.length());

    }

    public View createTokenView(String text) {


        LinearLayout l = new LinearLayout(getContext());
        l.setOrientation(LinearLayout.HORIZONTAL);
        l.setBackgroundResource(R.drawable.bordered_rectangle_rounded_corners);

        TextView tv = new TextView(getContext());
        l.addView(tv);
        tv.setText(text);
        tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);

        ImageView im = new ImageView(getContext());
        l.addView(im);
        im.setImageResource(R.drawable.ic_cross_15dp);
        im.setScaleType(ImageView.ScaleType.FIT_CENTER);

        return l;
    }

    public Object convertViewToDrawable(View view) {
        int spec = View.MeasureSpec.makeMeasureSpec(0, View.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(getContext().getResources(), viewBmp);
    }

    private class MyClickableSpan extends ClickableSpan{

        int startIdx;
        int endIdx;

        public MyClickableSpan(int startIdx, int endIdx) {
            super();
            this.startIdx = startIdx;
            this.endIdx = endIdx;
        }

        @Override
        public void onClick(View widget) {



            String s = getText().toString();

            String s1 = s.substring(0, startIdx);
            String s2 = s.substring(Math.min(endIdx+1, s.length()-1), s.length() );

            TagEditText.this.setText(s1 + s2);
        }

    }
}

R.drawable.bordered_rectangle_rounded_corners:

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid
        android:color="@color/transparent"/>
    <stroke android:width="1dp" android:color="#AAAAAA" />
    <corners
        android:radius="100dp" />
    <padding
        android:left="5dp"
        android:top="5dp"
        android:right="5dp"
        android:bottom="5dp" />
</shape>

最后要添加的是“x 按钮”的 png。到目前为止效果很好,唯一的问题是长按删除键不起作用(如果有人知道如何使它起作用,请随时发表评论)

【讨论】:

  • 那里做得很好,我想知道为什么当我添加这个时我最初看不到光标闪烁。
【解决方案2】:

嗯,花了一段时间才找到一个类似的问题,但这里是closest answer I found。我以前就知道其他人有这种问题!感谢 CommonsWare 为我指明了正确的方向。

【讨论】:

    【解决方案3】:

    我找不到好的解决方案,所以我会建立自己的库来处理这个问题:TokenAutoComplete。这是一个基本示例:

    public class ContactsCompletionView extends TokenCompleteTextView {
        public ContactsCompletionView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        protected View getViewForObject(Object object) {
            Person p = (Person)object;
    
            LayoutInflater l = (LayoutInflater)getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
            LinearLayout view = (LinearLayout)l.inflate(R.layout.contact_token, (ViewGroup)ContactsCompletionView.this.getParent(), false);
            ((TextView)view.findViewById(R.id.name)).setText(p.getName());
    
            return view;
        }
    
        @Override
        protected Object defaultObject(String completionText) {
            //Stupid simple example of guessing if we have an email or not
            int index = completionText.indexOf('@');
            if (index == -1) {
                return new Person(completionText, completionText.replace(" ", "") + "@example.com");
            } else {
                return new Person(completionText.substring(0, index), completionText);
            }
        }
    }
    

    contact_token 的布局代码(您需要找到自己的 x drawable)

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:background="@drawable/token_background">
        <TextView android:id="@+id/name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@android:color/white"
            android:textSize="14sp"
            android:text="Test Me"
            android:padding="2dp" />
    
        <ImageView
            android:layout_height="10dp"
            android:layout_width="10dp"
            android:src="@drawable/x"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="3dp"
            android:layout_marginRight="5dp" />
    </LinearLayout>
    

    令牌背景可绘制

    <shape xmlns:android="http://schemas.android.com/apk/res/android" >
        <solid android:color="#ffafafaf" />
        <corners
            android:topLeftRadius="5dp"
            android:bottomLeftRadius="5dp"
            android:topRightRadius="5dp"
            android:bottomRightRadius="5dp" />
    </shape>
    

    人物对象代码

    public class Person implements Serializable {
        private String name;
        private String email;
    
        public Person(String n, String e) { name = n; email = e; }
    
        public String getName() { return name; }
        public String getEmail() { return email; }
    
        @Override
        public String toString() { return name; }
    }
    

    示例活动

    public class TokenActivity extends Activity {
        ContactsCompletionView completionView;
        Person[] people;
        ArrayAdapter<Person> adapter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            people = new Person[]{
                    new Person("Marshall Weir", "marshall@example.com"),
                    new Person("Margaret Smith", "margaret@example.com"),
                    new Person("Max Jordan", "max@example.com"),
                    new Person("Meg Peterson", "meg@example.com"),
                    new Person("Amanda Johnson", "amanda@example.com"),
                    new Person("Terry Anderson", "terry@example.com")
            };
    
            adapter = new ArrayAdapter<Person>(this, android.R.layout.simple_list_item_1, people);
    
            completionView = (ContactsCompletionView)findViewById(R.id.searchView);
            completionView.setAdapter(adapter);
            completionView.setTokenClickStyle(TokenCompleteTextView.TokenClickStyle.Delete);
        }
    }
    

    布局代码

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <com.tokenautocomplete.ContactsCompletionView
            android:id="@+id/searchView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
    </RelativeLayout>
    

    【讨论】:

    • 我和 BillX 的情况一样。我可以知道您的解决方案与 x-close 按钮​​一起使用吗?谢谢。
    • @LocHa 您是否找到任何解决 x-close 按钮​​功能的方法?
    • @SwapnilSonar:我没有找到任何完整的解决方案。我创建了自己的标签编辑方式(不像 BillX 想要的那样)。你可以从 kpbird.com/2013/02/android-chips-edittext-token-edittext.html 学到一些东西
    猜你喜欢
    • 2012-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多