现在的位置: 首页 > 综合 > 正文

android在EditText中插入表情图片

2013年03月13日 ⁄ 综合 ⁄ 共 13811字 ⁄ 字号 评论关闭

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>

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;
	}
}

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;
	}*/
}

抱歉!评论已关闭.