RecipientEditTextView在短信中的使用

手头只有mtk的代码,短信代码位于在vendor/mediatek/proprietary/packages/apps/Mms,只能看MTKRecipientEditTextView的使用了。

ChipsRecipientAdapter

public class ChipsRecipientAdapter extends BaseRecipientAdapter
继承BaseRecipientAdapter,代码量很少。
    private static final int DEFAULT_PREFERRED_MAX_RESULT_COUNT = 10; //设置匹配列表项最大数量

    public ChipsRecipientAdapter(Context context) {
        super(context, DEFAULT_PREFERRED_MAX_RESULT_COUNT, QUERY_TYPE_PHONE); //设置uri是号码,因为默认是显示邮件地址
        setShowDuplicateResults(false); //不显示重复的联系人
    }

    @Override
    protected int getItemLayout() {
        return R.layout.mms_chips_recipient_dropdown_item; //最主要的是替换了匹配列表项默认的布局显示
    }

RecipientsEditor

public class RecipientsEditor extends MTKRecipientEditTextView
继承了MTKRecipientEditTextView

验证器

控件用到的字符串验证器,不做任何处理。
    private class AddressValidator implements Validator {
        public CharSequence fixText(CharSequence invalidText) {
            return invalidText; //直接返回源字符,不做处理
        }

        public boolean isValid(CharSequence text) {
            return true; //所有字符都是合法的,不做判断
        }
    }

搜索延时

设置搜索延时,不会输入字符就马上搜索,处理连续输入字符的情况,减少代码处理量
    public void setGalSearchDelayer() {
        Filter filter = getFilter();
        if (filter != null) {
            filter.setDelayer(new Filter.Delayer() {
                private int mPreviousLength = 0;

                public long getPostingDelay(CharSequence constraint) {
                    if (constraint == null) {
                        return 0;
                    }
                    long delay = constraint.length() < mPreviousLength
                            ? DELETE_KEY_POST_DELAY : ADD_POST_DELAY;
                    mPreviousLength = constraint.length();
                    return delay;
                }
            });
        }
    }


标记器

    private class RecipientsEditorTokenizer
            implements MultiAutoCompleteTextView.Tokenizer 
其中的findTokenStart和findTokenEnd用于确认一个token的开始和结束,使用它才能拆分出字符串中的一个个号码。


构造方法

除了上述的几个重要对象外,其它的重要代码如下:
    public RecipientsEditor(Context context, AttributeSet attrs) {
        ...

        setThreshold(1);    // 设置1个字符起就要显示匹配列表

        /// M:
        setInputType(getInputType() | InputType.TYPE_TEXT_FLAG_MULTI_LINE); //设置可以输入多行字符

        ...

        if (!getResources().getBoolean(R.bool.isWVGAScreen)) {
            setMaxLines(3); //可以配置控件行数最多为3行
        } else {
            setMaxLines(1);
        }

       
        addTextChangedListener(new TextWatcher() {...}); 从匹配列表选择的号码会有Annotation类型的Span,如果修改号码就要去除该Span
    }

生成数据

从会话列表进入某个会话,当然要填充联系人数据,这个方法就是populate
    public void populate(ContactList list) {   // ContactList是短信应用中的类     
        if (list.size() == 0) {
            setText(null);
        } else {      
            MTKRecipientList recipientList = new MTKRecipientList(); //MTKRecipientList是控件库中的类
            for (Contact c : list) {
                String displayName = c.getName();
                if (!TextUtils.isEmpty(displayName) && displayName.equals(c.getNumber())) {
                    displayName = "";
                }
                MTKRecipient recipient = new MTKRecipient(displayName, c.getNumberProtosomatic()); //MTKRecipient也是是控件库中的类
                recipientList.addRecipient(recipient);
            }
            appendList(recipientList); //使用控件中的方法
        }
    }

从ChipWatcher中解析数据


 public void parseRecipientsFromChipWatcher(ArrayList recipientList, ArrayList changedNumbers, String lastRecipient, int limit)
这个方法其实就是对应MTKRecipientEditTextView控件中的
    public interface ChipWatcher {
        public void onChipChanged(ArrayList allChips, ArrayList changedChipAddresses, String lastString);
    }
chip数据有变化的时候通知应用。


ComposeMessageActivity中的使用

短信主要的只有两个界面,一个是会话列表,另外一个就是会话。该类就是会话界面
    private RecipientsEditor mRecipientsEditor;  // UI control for editing recipients     控件实例
    private ImageButton mRecipientsPicker;       // UI control for recipients picker     mRecipientsEditor右面选取联系人的按键


ChipWatcher

实现了ChipWatcher接口,代替了TextWatcher。功能有二:一是减少了调用次数,例如删除个空格键是不会引起ChipWatcher的调用的,而TextWatcher只要有变化就会引起回调;二是实现了联系人信息的更新,因为text内容不变但是联系人数据库可以变,例如一个无主号码因为联系人的添加而要显示成为一个联系人chip。
private final MTKRecipientEditTextView.ChipWatcher mChipWatcher = new MTKRecipientEditTextView.ChipWatcher() {...}

该实现中主要是使用之前提及的parseRecipientsFromChipWatcher方法解析数据,然后更新其它相关数据结构。


ContextMenu

    private final OnCreateContextMenuListener mRecipientsMenuCreateListener =
        new OnCreateContextMenuListener() {
        @Override
        public void onCreateContextMenu(ContextMenu menu, View v,
                ContextMenuInfo menuInfo) {
            mChipViewMenu = menu;
            if (menuInfo != null) {
                Contact c = ((RecipientContextMenuInfo) menuInfo).recipient;
                RecipientsMenuClickListener l = new RecipientsMenuClickListener(c); //菜单点击处理

                menu.setHeaderTitle(c.getName());

                if (c.existsInDatabase()) {
                    menu.add(0, MENU_VIEW_CONTACT, 0, R.string.menu_view_contact)
                            .setOnMenuItemClickListener(l); //查看联系人详情
                } else if (MessageUtils.canAddToContacts(c)) {
                    menu.add(0, MENU_ADD_TO_CONTACTS, 0, R.string.menu_add_to_contacts)
                            .setOnMenuItemClickListener(l); //添加联系人
                }
            }
        }
    };
RecipientsMenuClickListener处理代码就是发送intent,很简单

控件初始化

初始化都在initRecipientsEditor方法中

    private void initRecipientsEditor(Bundle bundle) {
      
        ContactList recipients = getRecipients(); //获取会话联系人数据
        while (!recipients.isEmpty() && recipients.size() > RECIPIENTS_LIMIT_FOR_SMS) { 
            recipients.remove(RECIPIENTS_LIMIT_FOR_SMS);//这里限制了短信发送人数上限是100,多于100后面的删掉
        }

        ...
        mRecipientsEditor = (RecipientsEditor) stubView.findViewById(R.id.recipients_editor);
        ...
     
        mRecipientsEditor.addChipChangedListener(mChipWatcher); //设置ChipWatcher
    
        ...
        if (mRecipientsEditor.getAdapter() == null) { //设置匹配列表adapter,搜索uri和延时
            ChipsRecipientAdapter chipsAdapter = new ChipsRecipientAdapter(this);
            chipsAdapter.setShowEmailAddress(showEmailAddress);
            mRecipientsEditor.setAdapter(chipsAdapter);
            mRecipientsEditor.setGalSearchDelayer();
        } 
        ...

        mRecipientsEditor.populate(recipients); //初始化数据
        
        mRecipientsEditor.setOnCreateContextMenuListener(mRecipientsMenuCreateListener); //ConextMenu初始化

        mRecipientsEditor.setOnSelectChipRunnable(...); //号码为一个的时候,点击弹出输入法

        mRecipientsEditor.setOnFocusChangeListener(...); //获取焦点的时候调整短信内容空间的高度

        ...

    }

你可能感兴趣的:(android)