android在EditText中插入表情图片

jopen 10年前

EditText通常用于显示文字,但有时候也需要在文字中夹杂一些图片,比如QQ中就可以使用表情图片,又比如需要的文字高亮显示等等,如何在android中也做到这样呢? 
记得android中有个android.text包,这里提供了对文本的强大的处理功能。 

添加图片主要用SpannableStringImageSpan类,具体参考sdk文档 SpannableString

 

这里以人人网客户端发布消息的界面为例

 

布局文件main.xml

    <?xml version="1.0" encoding="utf-8"?>        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"            android:layout_width="fill_parent"            android:layout_height="fill_parent"            android:background="#FFFFFF"            android:orientation="vertical" >                    <LinearLayout                android:layout_width="fill_parent"                android:layout_height="48dip"                android:background="@drawable/v5_0_1_flipper_head_blue_background"                android:orientation="horizontal" >                        <ImageView                    android:id="@+id/newsfeedpublish_back"                    android:layout_width="54dip"                    android:layout_height="fill_parent"                    android:layout_gravity="center"                    android:background="@drawable/v5_0_1_flipper_head_title_wrapper_background"                    android:clickable="true"                    android:scaleType="centerInside"                    android:src="@drawable/v5_0_1_flipper_head_back" />                        <ImageView                    android:layout_width="2px"                    android:layout_height="24dip"                    android:layout_gravity="center"                    android:src="@drawable/v5_0_1_flipper_head_separator" />                        <TextView                    android:layout_width="wrap_content"                    android:layout_height="fill_parent"                    android:layout_weight="1"                    android:gravity="center_vertical"                    android:paddingLeft="8dip"                    android:text="发布新鲜事"                    android:textColor="#FFFFFF"                    android:textSize="16sp"                    android:textStyle="bold" />                        <ImageView                    android:id="@+id/newsfeedpublish_publish"                    android:layout_width="54dip"                    android:layout_height="fill_parent"                    android:background="@drawable/v5_0_1_flipper_head_title_wrapper_background"                    android:clickable="true"                    android:scaleType="centerInside"                    android:src="@drawable/v5_0_1_flipper_head_publish" />            </LinearLayout>                    <EditText                android:id="@+id/newsfeedpublish_content"                android:layout_width="fill_parent"                android:layout_height="wrap_content"                android:layout_marginBottom="8dip"                android:layout_weight="1"                android:background="#00000000"                android:gravity="top"                android:hint="您正在干嘛?"                android:maxLength="140"                android:padding="8dip"                android:textColor="#000000"                android:textSize="16sp" >                        <requestFocus />            </EditText>                    <View                android:layout_width="fill_parent"                android:layout_height="1dip"                android:layout_marginLeft="8dip"                android:layout_marginRight="8dip"                android:background="@drawable/v5_0_1_publisher_split_line" />                    <LinearLayout                android:layout_width="fill_parent"                android:layout_height="40dip"                android:orientation="horizontal" >                        <LinearLayout                    android:layout_width="wrap_content"                    android:layout_height="fill_parent"                    android:layout_margin="5dip"                    android:layout_weight="1"                    android:background="@drawable/v5_0_1_publisher_poi_text_bg"                    android:orientation="horizontal" >                            <Button                        android:id="@+id/newsfeedpublish_poi_place"                        android:layout_width="wrap_content"                        android:layout_height="fill_parent"                        android:layout_weight="1"                        android:background="#00000000"                        android:drawableLeft="@drawable/v5_0_1_publisher_poi_icon"                        android:drawablePadding="8dip"                        android:ellipsize="start"                        android:gravity="left|center_vertical"                        android:singleLine="true"                        android:text="正在定位..."                        android:textColor="#ff005092" />                            <ImageView                        android:id="@+id/newsfeedpublish_poi_sperator"                        android:layout_width="1dip"                        android:layout_height="fill_parent"                        android:src="@drawable/v5_0_1_publisher_poi_area_sperator" />                            <ImageView                        android:id="@+id/newsfeedpublish_poi_list"                        android:layout_width="wrap_content"                        android:layout_height="wrap_content"                        android:layout_gravity="center_vertical"                        android:src="@drawable/v5_0_1_publisher_poi_list_icon"                        android:visibility="invisible" />                </LinearLayout>                        <LinearLayout                    android:layout_width="100dip"                    android:layout_height="fill_parent"                    android:layout_weight="1"                    android:gravity="right"                    android:padding="8dip" >                            <TextView                        android:id="@+id/newsfeedpublish_count"                        android:layout_width="wrap_content"                        android:layout_height="fill_parent"                        android:gravity="center"                        android:text="0"                        android:textColor="#80333333"                        android:textSize="14sp" />                            <TextView                        android:layout_width="wrap_content"                        android:layout_height="fill_parent"                        android:gravity="center"                        android:text="/140"                        android:textColor="#80333333"                        android:textSize="14sp" />                </LinearLayout>            </LinearLayout>                    <LinearLayout                android:layout_width="fill_parent"                android:layout_height="40dip"                android:background="@drawable/v5_0_1_publisher_buttons_area_bg"                android:orientation="horizontal" >                        <ImageButton                    android:id="@+id/newsfeedpublish_voice"                    android:layout_width="wrap_content"                    android:layout_height="fill_parent"                    android:layout_weight="1"                    android:background="@drawable/v5_0_1_publisher_button_bg"                    android:src="@drawable/v5_0_1_publisher_voice_button" />                        <ImageButton                    android:id="@+id/newsfeedpublish_poi"                    android:layout_width="wrap_content"                    android:layout_height="fill_parent"                    android:layout_weight="1"                    android:background="@drawable/v5_0_1_publisher_button_bg"                    android:src="@drawable/v5_0_1_publisher_poi_button_on" />                        <ImageButton                    android:id="@+id/newsfeedpublish_image"                    android:layout_width="wrap_content"                    android:layout_height="fill_parent"                    android:layout_weight="1"                    android:background="@drawable/v5_0_1_publisher_button_bg"                    android:src="@drawable/v5_0_1_publisher_image_button" />                        <ImageButton                    android:id="@+id/newsfeedpublish_at"                    android:layout_width="wrap_content"                    android:layout_height="fill_parent"                    android:layout_weight="1"                    android:background="@drawable/v5_0_1_publisher_button_bg"                    android:src="@drawable/v5_0_1_publisher_at_button" />                        <ImageButton                    android:id="@+id/newsfeedpublish_emoticon"                    android:layout_width="wrap_content"                    android:layout_height="fill_parent"                    android:layout_weight="1"                    android:background="@drawable/v5_0_1_publisher_button_bg"                    android:src="@drawable/v5_0_1_publisher_emotion_button" />            </LinearLayout>                    <GridView                android:id="@+id/newsfeedpublish_emoticons"                android:layout_width="fill_parent"                android:layout_height="200dip"                android:background="@drawable/v5_0_1_publisher_emotion_area_bg"                android:cacheColorHint="#00000000"                android:focusableInTouchMode="true"                android:horizontalSpacing="5dip"                android:listSelector="#00000000"                android:numColumns="8"                android:stretchMode="columnWidth"                android:verticalSpacing="5dip"                android:visibility="gone" >            </GridView>                </LinearLayout>  
</div> </div>

MainActivity.java

    package com.yulore.emotion;                import android.app.Activity;        import android.os.Bundle;        import android.util.Log;        import android.view.View;        import android.view.View.OnClickListener;        import android.view.ViewGroup;        import android.view.inputmethod.InputMethodManager;        import android.widget.AdapterView;        import android.widget.AdapterView.OnItemClickListener;        import android.widget.BaseAdapter;        import android.widget.EditText;        import android.widget.GridView;        import android.widget.ImageButton;        import android.widget.ImageView;                public class MainActivity extends Activity implements OnClickListener {            private static final String TAG = "MainActivity";            private ImageButton ib_emotion;            private GridView gv_emotion;            private EmotionAdapter mAdapter;            private EditText et_content;            private ImageView iv_publish;                    /** Called when the activity is first created. */            @Override            public void onCreate(Bundle savedInstanceState) {                super.onCreate(savedInstanceState);                setContentView(R.layout.main);                                findViewById();                initEmotionIcons();                setListener();                                mAdapter = new EmotionAdapter();                gv_emotion.setAdapter(mAdapter);            }                    private void initEmotionIcons() {                String json = EmotionUtil.getInstance().readFromFile(EmotionUtil.DOWNLOAD_EMOTION_PATH, "Emoticons.json");                if(json!=null){                    Log.e(TAG, json);                    RenRenData.mEmotionList = new DataProvider().resolve(json);                }            }                    private void findViewById() {                ib_emotion = (ImageButton) findViewById(R.id.newsfeedpublish_emoticon);                gv_emotion = (GridView) findViewById(R.id.newsfeedpublish_emoticons);                et_content = (EditText) findViewById(R.id.newsfeedpublish_content);                iv_publish = (ImageView) findViewById(R.id.newsfeedpublish_publish);            }                        private void setListener() {                ib_emotion.setOnClickListener(this);                et_content.setOnClickListener(this);                                gv_emotion.setOnItemClickListener(new OnItemClickListener() {                            @Override                    public void onItemClick(AdapterView<?> parent, View view,                            int position, long id) {                                                String emotion = RenRenData.mEmotionList.get(position).getEmotion();                                                if(et_content.getText().length()+emotion.length()<=140){ //长度小于140                                    //                  et_content.setText(et_content.getText().toString()+emotion);                            CharSequence ret = EmotionUtil.getInstance().replace(getApplicationContext(), et_content.getText().toString()+emotion);                            Log.e(TAG, "ret="+ret);                            et_content.setText(ret);                        }                    }                });            }                    @Override            public void onClick(View v) {                switch (v.getId()) {                case R.id.newsfeedpublish_emoticon:                    if(gv_emotion.isShown()){                        gv_emotion.setVisibility(View.GONE);                        ib_emotion.setImageResource(R.drawable.v5_0_1_publisher_emotion_button);                    }else{                        gv_emotion.setVisibility(View.VISIBLE);                        ib_emotion.setImageResource(R.drawable.v5_0_1_publisher_pad_button);                                                //隐藏输入法界面                        InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);                        imm.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);                    }                    break;                case R.id.newsfeedpublish_content:                    if(gv_emotion.isShown()){                        gv_emotion.setVisibility(View.GONE);                        ib_emotion.setImageResource(R.drawable.v5_0_1_publisher_emotion_button);                    }                    break;                        default:                    break;                }            }                        private class EmotionAdapter extends BaseAdapter{                        @Override                public int getCount() {                                        return RenRenData.mEmotionList.size();                }                        @Override                public Object getItem(int position) {                                        return RenRenData.mEmotionList.get(position);                }                        @Override                public long getItemId(int position) {                                        return position;                }                        @Override                public View getView(int position, View convertView, ViewGroup parent) {                    View view;                    ViewHolder holder;                    if(convertView==null){                        holder = new ViewHolder();                        view = View.inflate(getApplicationContext(), R.layout.emotion_item, null);                        holder.iv_emotion = (ImageView) view.findViewById(R.id.emotcons_item_img);                                                view.setTag(holder);                    }else{                        view = convertView;                        holder = (ViewHolder) view.getTag();                    }                    EmotionIcon em = RenRenData.mEmotionList.get(position);                    holder.iv_emotion.setImageBitmap(EmotionUtil.getInstance().getLocalEmotionIcon(em.getEmotion()));                                        return view;                }            }                        public static class ViewHolder{                public ImageView iv_emotion;            }        }  
</div> </div>

EmotionUtil.java

package com.yulore.emotion;        import java.io.BufferedInputStream;    import java.io.BufferedReader;    import java.io.File;    import java.io.FileInputStream;    import java.io.IOException;    import java.io.InputStream;    import java.io.InputStreamReader;    import java.util.regex.Matcher;    import java.util.regex.Pattern;        import android.content.Context;    import android.graphics.Bitmap;    import android.graphics.BitmapFactory;    import android.os.Environment;    import android.text.Spannable;    import android.text.SpannableStringBuilder;    import android.text.style.ImageSpan;        public class EmotionUtil {            public static final String DOWNLOAD_EMOTION_PATH = Environment                .getExternalStorageDirectory().getAbsolutePath()                + "/RenRenForAndroid/Emoticons/";            private static EmotionUtil instance = new EmotionUtil();            private EmotionUtil() {        };            public static EmotionUtil getInstance() {                return instance;        }            /**        * 将文本中的表情符号替换为表情图片        *         * @param text        *            需要转换的字符        * @return 带有表情的字符        */        public CharSequence replace(Context context,CharSequence text) {            try {                SpannableStringBuilder builder = new SpannableStringBuilder(text);                Pattern pattern = buildPattern();                Matcher matcher = pattern.matcher(text);                while (matcher.find()) {                    Bitmap bitmap = getLocalEmotionIcon(matcher.group());                    ImageSpan span = new ImageSpan(context, bitmap);                    builder.setSpan(span, matcher.start(), matcher.end(),                            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);                }                return builder;            } catch (Exception e) {                return text;            }        }                /**        * 正则表达式        *         * @return        */        private Pattern buildPattern() {            /**            * 查看表情名称数据是否存在,不存在则从本地读取Json,并解析            */            if(RenRenData.mEmotionList==null || RenRenData.mEmotionList.size()==0){                                String json = EmotionUtil.getInstance().readFromFile(EmotionUtil.DOWNLOAD_EMOTION_PATH, "Emoticons.json");                    if(json!=null){                    RenRenData.mEmotionList = new DataProvider().resolve(json);                }            }                StringBuilder patternString = new StringBuilder(                    RenRenData.mEmotionList.size() * 3);            patternString.append('(');            for (EmotionIcon result : RenRenData.mEmotionList) {                String s = result.getEmotion();                patternString.append(Pattern.quote(s));                patternString.append('|');            }            patternString.replace(patternString.length() - 1,                    patternString.length(), ")");            return Pattern.compile(patternString.toString());        }            public String readFromFile(String filePath, String fileName) {            if (fileName == null || "".equals(fileName)) {                return null;            }            String ret = "";            if (Environment.MEDIA_MOUNTED.equals(Environment                    .getExternalStorageState())) {                    File dir = new File(filePath);                if (dir == null || !dir.exists()) {                    dir.mkdirs();                }                    File targetFile = new File(filePath + fileName);                try {                        if (targetFile == null || targetFile.exists()) {                        targetFile.createNewFile();                    }                        InputStream in = new BufferedInputStream(new FileInputStream(                            targetFile));                    BufferedReader br = new BufferedReader(new InputStreamReader(                            in, "UTF-8"));                    String tmp;                    while ((tmp = br.readLine()) != null) {                        ret += tmp;                    }                    br.close();                    in.close();                } catch (IOException e) {                    e.printStackTrace();                }            }                return ret;        }            /**        * 根据表情名称查找表情图片        * @param imageName        * @return        */        public Bitmap getEmotionIcon(String imageName) {                File cacheDir = new File(DOWNLOAD_EMOTION_PATH);                if (!cacheDir.exists()) {                cacheDir.mkdirs();            }                File[] cacheFiles = cacheDir.listFiles();            int i = 0;            if (cacheFiles != null) {                for (; i < cacheFiles.length; i++) {                    if (imageName.equals(cacheFiles[i].getName())) {                        break;                    }                }            }            if (i < cacheFiles.length) {                return BitmapFactory.decodeFile(DOWNLOAD_EMOTION_PATH + imageName);            }            return null;        }            /**        * 从SD卡中根据表情符号获取表情图片        *         * @param imageName        *            表情的名称        * @return 表情的Bitmap        */        public Bitmap getLocalEmotionIcon(String imageName) {                File dir = new File(DOWNLOAD_EMOTION_PATH);            if (!dir.exists()) {                dir.mkdirs();            }                File[] cacheFiles = dir.listFiles();                int index = 0;                for (int i = 0; cacheFiles != null && i < cacheFiles.length; i++) {                    if (imageName.equals(cacheFiles[i].getName())) {                    index = i;                    break;                }            }                Bitmap bitmap = null;                if (index < cacheFiles.length) {                /**                * 因表情图片较小,则这里返回了一个60*60的Bitmap,该数值可根据情况调整                */                bitmap = Bitmap                        .createScaledBitmap(                                BitmapFactory.decodeFile(DOWNLOAD_EMOTION_PATH                                        + imageName), 60, 60, true);            }                return bitmap;        }            /**        * 将文本中的表情符号转换为表情图片        *         * @param text        * @return        */        /*public CharSequence replace02(Context context, CharSequence text, int resId) {           // SpannableString连续的字符串,长度不可变,同时可以附加一些object;可变的话使用SpannableStringBuilder,参考sdk文档           SpannableString ss = new SpannableString(text.toString() + "[smile]");           // 得到要显示图片的资源           Drawable d = context.getResources().getDrawable(resId);           // 设置高度           d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());           // 跨度底部应与周围文本的基线对齐           ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BASELINE);           // 附加图片           ss.setSpan(span, text.length(), text.length() + "[smile]".length(),                   Spannable.SPAN_INCLUSIVE_EXCLUSIVE);              return ss;       }*/    }  
</div> </div>