Android控件EditText插入表情

实现效果如下图所示。



代码下载链接:http://download.csdn.net/detail/laukaka/5657891

代码如下:

MainActivity.java

package com.example.textfacedemo;

import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.ImageSpan;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;

import com.example.textfacedemo.FaceLayout.OnFaceClickListener;

public class MainActivity extends Activity implements OnClickListener {

	private View btnFace;
	private View btnSend;
	private FaceLayout faceLayout;
	private EditText editText;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initView();
		initListener();
	}

	private void initView() {
		btnFace = findViewById(R.id.msg_comm_btn_menu);
		btnSend = findViewById(R.id.msg_comm_btn_send_msg);
		editText = (EditText) findViewById(R.id.msg_comm_msg_edit);
		faceLayout = (FaceLayout) findViewById(R.id.msg_comm_face_layout);
	}
	
	private void initListener() {
		btnFace.setOnClickListener(this);
		btnSend.setOnClickListener(this);
		editText.setOnClickListener(this);
		faceLayout.setOnFaceClickListener(faceClickListener);
	}

	@Override
	public void onClick(View v) {
		if(v.getId() == btnFace.getId()) {
			((InputMethodManager) getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE))
			.hideSoftInputFromWindow(btnFace.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
			if(faceLayout.getVisibility() == View.GONE) {
				faceLayout.setVisibility(View.VISIBLE);
			} else {
				faceLayout.setVisibility(View.GONE);
			}
		} else if(v.getId() == btnSend.getId()) {
		} else if(v.getId() == editText.getId()) {
    		faceLayout.setVisibility(View.GONE);
		}
	}

	private OnFaceClickListener faceClickListener = new OnFaceClickListener() {
		@Override
		public void faceClick(String face) {
			if(face != null && !face.equals("")) {
				int selection = editText.getSelectionEnd();
				String newStr = editText.getText().toString();
				int origLength = newStr.length();
				if(face.equals("delete")) {
					KeyEvent keyEventDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL);
					editText.onKeyDown(KeyEvent.KEYCODE_DEL, keyEventDown);
					newStr = editText.getText().toString();
				} else {
					newStr = newStr.substring(0, editText.getSelectionEnd()) + face + newStr.substring(editText.getSelectionEnd(), newStr.length());
				}
				SpannableStringBuilder spannableString = getContentList(newStr);
				if(spannableString != null) {
					int newLength = newStr.length();
					selection += (newLength - origLength);
					editText.setText(spannableString);
					Log.d("DEBUG", "orig length: " + origLength + "; new length: " + newLength + "; selection:" + selection);
					editText.setSelection(selection);
				}
			}
		}
	};;

	public static final String FACE_STRING = 
			"[可怜],[微笑],[撇嘴],[色],[发呆],[得意],[流泪],[害羞],[闭嘴],[睡]," +
			"[大哭],[尴尬],[发怒],[调皮],[呲牙],[惊讶],[难过],[酷],[冷汗],[抓狂]," +
			"[吐],[偷笑],[愉快],[白眼],[傲慢],[饥饿],[困],[惊恐],[流汗],[憨笑]," +
			"[悠闲],[奋斗],[咒骂],[疑问],[嘘],[晕],[疯了],[衰],[骷髅],[敲打]," + 
			"[再见],[擦汗],[抠鼻],[鼓掌],[糗大了],[坏笑],[左哼哼],[右哼哼],[哈欠],[鄙视]," +
			"[委屈],[快哭了],[阴险],[亲亲],[吓]";
	
    private static final HashMap<String, SoftReference<Bitmap>> mFaceBitmapCache = new HashMap<String, SoftReference<Bitmap>>();
    private static final String FACE_PATTERN = "\\[.*?\\]";
	public static HashMap<Integer, String> FACE_STR = new HashMap<Integer, String>();			//表情的位置对应的字符串
	public static HashMap<String, Integer> FACE_STR_MAP_ID = new HashMap<String, Integer>();	//表情的字符串对应的资源ID	
	public static HashMap<Integer, Integer> FACE_IMG_RES_ID = new HashMap<Integer, Integer>();	//表情的位置对应的资源ID
	
	static {
		String[] faceStr = FACE_STRING.split(",");
		for(int i=0; i<faceStr.length; i++) {
			FACE_IMG_RES_ID.put(i, R.drawable.face_00 + i);
			FACE_STR_MAP_ID.put(faceStr[i], R.drawable.face_00 + i);
			FACE_STR.put(i, faceStr[i]);
		}
	}
    
//	在使用SpannableString对象时要注意Spanned.SPAN_EXCLUSIVE_EXCLUSIVE等的作用:
//	用来标识在 Span 范围内的文本前后输入新的字符时是否把它们也应用这个效果。
//	分别有 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE(前后都不包括)、
//	Spanned.SPAN_INCLUSIVE_EXCLUSIVE(前面包括,后面不包括)、
//	Spanned.SPAN_EXCLUSIVE_INCLUSIVE(前面不包括,后面包括)、
//	Spanned.SPAN_INCLUSIVE_INCLUSIVE(前后都包括)。

	public SpannableStringBuilder getContentList(String line) {
		if(line == null || line.equals("")) {
			return null;
		}
		SpannableStringBuilder ssb = new SpannableStringBuilder(line);
		Pattern pattern = Pattern.compile("(" + FACE_PATTERN + ")");
		Matcher matcher = pattern.matcher(line);
		while(matcher.find()) {
			int start = matcher.start();
			int end = matcher.end();
			String words = line.substring(start, end);
			if(words.matches("^" + FACE_PATTERN + "$") && FACE_STRING.contains(words)) {
				try{
					Bitmap bitmap = null;
					SoftReference<Bitmap> bitmapReference = mFaceBitmapCache.get(words);
					if(bitmapReference != null) {
						bitmap = bitmapReference.get();
						if(bitmap == null) {
							bitmap = getBitMap(FACE_STR_MAP_ID.get(words));
							mFaceBitmapCache.put(words, new SoftReference<Bitmap>(bitmap));
						}
					} else {
						bitmap = getBitMap(FACE_STR_MAP_ID.get(words));
						mFaceBitmapCache.put(words, new SoftReference<Bitmap>(bitmap));
					}
					if(bitmap != null) {
						ImageSpan imageSpan = new ImageSpan(bitmap);
						ssb.setSpan(imageSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
					}
				} catch (Exception e){
					e.printStackTrace();
				}
			}
			matcher.region(end, line.length());
		}
		return ssb;
	}

	private Bitmap getBitMap(int id) {
		try {
			Bitmap bm = BitmapFactory.decodeResource(getResources(), id);
			return bm;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}	
}


FaceLayout.java

package com.example.textfacedemo;

import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.ImageSpan;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class FaceLayout extends LinearLayout {

	private ViewPager layoutFaceQQ;
	private LinearLayout faceLayoutIndexLayout;
	private OnFaceClickListener faceClickListener;
	private int currentPageIndex = 0;
	
	public FaceLayout(Context context) {
		super(context);
		init();
	}

	public FaceLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}
	
	private void init() {
		LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		inflater.inflate(R.layout.face_layout, this);
		layoutFaceQQ = (ViewPager) findViewById(R.id.msg_face_layout_qq);
		faceLayoutIndexLayout = (LinearLayout) findViewById(R.id.msg_face_layout_index);
		layoutFaceQQ.setAdapter(new ViewPageAdapter(MainActivity.FACE_IMG_RES_ID, 24));
		layoutFaceQQ.setOnPageChangeListener(new OnPageChangeListener() {
			@Override
			public void onPageSelected(int arg0) {
				initPageIndex(layoutFaceQQ.getAdapter().getCount(), arg0);
			}
			@Override
			public void onPageScrollStateChanged(int arg0) { }
			@Override
			public void onPageScrolled(int arg0, float arg1, int arg2) { }
		});
	}
	
	private void initPageIndex(int pageNum, int index) {
		currentPageIndex = index;
		if(pageNum > 1) {
			faceLayoutIndexLayout.removeAllViews();
			for(int i=0; i<pageNum; i++) {
				ImageView iv = new ImageView(getContext());
				if(i == index) {
					iv.setBackgroundResource(R.drawable.dot_abled);
				} else {
					iv.setBackgroundResource(R.drawable.dot_unabled);
				}
				LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
				lp.setMargins(8, 5, 8, 5);
				faceLayoutIndexLayout.addView(iv, lp);
			}
		}
	}
	
	private View getFaceViews(HashMap<Integer, Integer> faceMap, final int index, final int num) {
		GridView  gv = new GridView(getContext());
		gv.setNumColumns(8);
		gv.setAdapter(new FaceGridViewAdapter(faceMap, index, num));
		gv.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
				String face = null;
				if(arg2 == (num - 1)) {
					face = "delete";
				} else {
					face = MainActivity.FACE_STR.get((currentPageIndex * (num - 1)) + arg2);
				}
				if(face != null && faceClickListener != null) {
					faceClickListener.faceClick(face);
				}
			}
		});
		gv.setSelector(R.drawable.face_sel_bg);
		return gv;
	}
	
	
	public void setOnFaceClickListener(OnFaceClickListener listener) {
		faceClickListener = listener;
	}
	
	class ViewPageAdapter extends PagerAdapter {
		
		private List<View> views;			
		private HashMap<Integer, Integer> facesResIdMap;			//表情的资源ID列表
		private int pageNum;							//表情的页数
		private int iconNumOfPage;						//一个页面具有的表情数
		
		public ViewPageAdapter(HashMap<Integer, Integer> facesMap, int iconNumOfPage) {
			this.facesResIdMap = facesMap;
			this.iconNumOfPage = iconNumOfPage;
			this.views = new ArrayList<View>();
			if(facesMap == null) {
				this.pageNum = 0;
			} else {
				this.pageNum = facesMap.size() % iconNumOfPage > 0 ? facesMap.size() / iconNumOfPage + 1 : facesMap.size() / iconNumOfPage;
				initPageIndex(pageNum, 0);
			}
		}

		@Override
		public int getCount() {
			return pageNum;
		}

		@Override
		public boolean isViewFromObject(View arg0, Object arg1) {
			return arg0 == arg1;
		}
		
		@Override
		public void destroyItem(ViewGroup container, int position, Object object) {
			container.removeView(views.get(position));
		}
		
		@Override
		public Object instantiateItem(ViewGroup container, int position) {
			View view = getFaceViews(facesResIdMap, position, iconNumOfPage);
			views.add(view);
			container.addView(view);
			return view;
		}
		
	}
	
	class FaceGridViewAdapter extends BaseAdapter {
		
		private HashMap<Integer, Integer> facesResIdMap;
		private int pageIconNum;
		private int pageIndex = 0;
		
		public FaceGridViewAdapter(HashMap<Integer, Integer> faceMap, int index, int num) {
			this.facesResIdMap = faceMap;
			this.pageIconNum = num;
			this.pageIndex = index;
		}
	
		@Override
		public int getCount() {
			return pageIconNum;
		}
	
		@Override
		public Object getItem(int position) {
			return null;
		}
	
		@Override
		public long getItemId(int position) {
			return 0;
		}
	
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			if(convertView == null) {
				convertView = new ImageView(getContext());
			}
			if(position == (pageIconNum - 1)) {
				((ImageView) convertView).setImageResource(R.drawable.face_delete);
			} else {
				Integer imgId = facesResIdMap.get((pageIndex * (pageIconNum - 1)) + position);
				if(imgId != null) {
					((ImageView) convertView).setImageResource(imgId);
				} else {
					((ImageView) convertView).setImageResource(R.drawable.face_delete);
					convertView.setVisibility(View.INVISIBLE);
				}
			}
			convertView.setPadding(2, 6, 2, 6);
			return convertView;
		}
		
	}

	public interface OnFaceClickListener {
		public void faceClick(String face);
	}
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现图文混排,可以使用一个自定义的 EditText 控件,并在其中添加一个 ImageView 控件来实现。 以下是实现方法: 1.创建一个自定义的带有 ImageView 控件EditText 控件。 ```java public class RichEditText extends androidx.appcompat.widget.AppCompatEditText { public RichEditText(Context context) { super(context); } public RichEditText(Context context, AttributeSet attrs) { super(context, attrs); } public RichEditText(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } //插入图片 public void insertImage(Bitmap bitmap) { SpannableString ss = new SpannableString(" "); ImageSpan span = new ImageSpan(getContext(), bitmap); ss.setSpan(span, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); append(ss); } } ``` 2.在布局文件中使用自定义的 EditText 控件。 ```xml <com.example.richedittextdemo.RichEditText android:id="@+id/edit_text" android:layout_width="match_parent" android:layout_height="wrap_content" /> ``` 3.在 Activity 中获取自定义的 EditText 控件,并添加一个点击事件。 ```java public class MainActivity extends AppCompatActivity { private RichEditText editText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); editText = findViewById(R.id.edit_text); editText.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //调用选择图片的方法 chooseImage(); } }); } //选择图片 private void chooseImage() { Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); startActivityForResult(intent, 1); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK && requestCode == 1) { try { Uri selectedImage = data.getData(); InputStream inputStream = getContentResolver().openInputStream(selectedImage); Bitmap bitmap = BitmapFactory.decodeStream(inputStream); editText.insertImage(bitmap); } catch (FileNotFoundException e) { e.printStackTrace(); } } } } ``` 4.在 onActivityResult 方法中获取选择的图片,并调用自定义的 EditText 控件的 insertImage 方法,将图片插入EditText 中。 以上就是在 Android 中实现 EditText 插入图片并实现图文混排的方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值