上一篇讲到了表情符号在EditText中的显示:Go
=======
这回来讲讲这个面板中的一些功能
1、面板的显示、继承于ViewPager,先上比较完整的代码
public class EmojiPanel extends ViewPager{
private final static int EMOJI_INDEX_START = 1;
private final static int EMOJI_INDEX_END = 93;
private Context mContext;
private EditText mEditText;
public EmojiPanel(Context context) {
this(context, null);
}
public EmojiPanel(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
init();
}
public void bindEditText(EditText editText){
mEditText = editText;
}
private void init(){
List<View> views = new ArrayList<View>();
for(int i = EMOJI_INDEX_START; i <= EMOJI_INDEX_END;){
views.add( getGridView(i) );
i += LocalEmojiAdapter.MAX_ITEM_COUNT;
}
this.setAdapter(new EmoViewPagerAdapter(views));
}
private View getGridView(int startIndex) {
View view = View.inflate(mContext, R.layout.include_emo_gridview, null);
GridView gridview = (GridView) view.findViewById(R.id.gridview);
final LocalEmojiAdapter gridAdapter = new LocalEmojiAdapter(mContext, startIndex);
gridview.setAdapter(gridAdapter);
gridview.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
Datas name = (Datas) gridAdapter.getItem(position);
String key = name.code.toString();
if (mEditText != null && !TextUtils.isEmpty(key)) {
int start = mEditText.getSelectionStart();
CharSequence content = mEditText.getText().insert(start, key);
mEditText.setText(content);
// 定位光标位置
CharSequence info = mEditText.getText();
if (info instanceof Spannable) {
Spannable spanText = (Spannable) info;
Selection.setSelection(spanText, start + key.length());
}
}
}
});
return view;
}
private class LocalEmojiAdapter extends SimpleAdapter {
public final static int MAX_ITEM_COUNT = 17;
private int mStartIndex;
public LocalEmojiAdapter(Context context, int startIndex) {
super(context, null, 0, null, null);
mStartIndex = startIndex;
}
@Override
public int getCount() {
return MAX_ITEM_COUNT + 1;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if(convertView != null){
holder =(ViewHolder) convertView.getTag();
}else{
convertView = View.inflate(mContext, R.layout.iv_emo, null);
holder = new ViewHolder();
holder.mIvImage = (ImageView) convertView.findViewById(R.id.iv_emo);
convertView.setTag(holder);
}
if(position < MAX_ITEM_COUNT){
String key = String.format("face_%03d", mStartIndex + position);
int id = getResources().getIdentifier(key, "drawable", mContext.getPackageName());
holder.mIvImage.setImageResource(id);
}else{//delete button
holder.mIvImage.setImageResource(R.drawable.icon_reply_delete);
}
convertView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mEditText != null) {
if(position < MAX_ITEM_COUNT){
String key = "{:" + (mStartIndex + position) + ":}";
int start = mEditText.getSelectionStart();
CharSequence content = mEditText.getText().insert(start, key);
mEditText.setText(content);
// 定位光标位置
CharSequence info = mEditText.getText();
if (info instanceof Spannable) {
Spannable spanText = (Spannable) info;
Selection.setSelection(spanText, start + key.length());
}
}else{//delete
// int start = mEditText.getSelectionStart();
// Editable content = mEditText.getText();
//check if the last item is emoji
// Matcher matcher = Pattern.compile("\\{:\\d{1,2}:\\}$", Pattern.CASE_INSENSITIVE).matcher(content);
// if(matcher.find()){
// String faceText = matcher.group();
// int index = content.toString().lastIndexOf(faceText);
// mEditText.setText( content.delete(index, index+faceText.length()) );
// }else{
// }
// mEditText.setText( content.delete(content.length()-1, content.length()) );
// CharSequence info = mEditText.getText();
// if (info instanceof Spannable) {
// Spannable spanText = (Spannable) info;
//
// if(start > spanText.length()){
// start = spanText.length();
// }
// Selection.setSelection(spanText, start);
// }
mEditText.onKeyDown(KeyEvent.KEYCODE_DEL, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL));
}
}
}
});
return convertView;
}
class ViewHolder {
ImageView mIvImage;
}
}
}
一个表情界面:include_emo_gridview.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<GridView
android:id="@+id/gridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_marginBottom="6dp"
android:layout_marginTop="6dp"
android:fadingEdge="none"
android:gravity="center"
android:numColumns="6"
android:scrollbars="none"
android:horizontalSpacing="5dp"
android:verticalSpacing="5dp" />
</LinearLayout>
一个表情:iv_emo.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="3dp">
<ImageView
android:id="@+id/iv_emo"
android:layout_centerInParent="true"
android:layout_width="25dp"
android:layout_height="25dp"
android:scaleType="fitXY"
/>
</RelativeLayout>
代码贴完了,稍微说一些点
2、图片嵌入、删除
1)绑定了EditText (这个其实是上一篇自定义的)
public void bindEditText(EditText editText){
mEditText = editText;
}
2)嵌入表情
if (mEditText != null && !TextUtils.isEmpty(key)) {
//获取光标的位置
int start = mEditText.getSelectionStart();
//将表情对应的文本("{:n:}")插入到text中
CharSequence content = mEditText.getText().insert(start, key);
mEditText.setText(content);
// 重新定位光标位置
CharSequence info = mEditText.getText();
if (info instanceof Spannable) {
Spannable spanText = (Spannable) info;
Selection.setSelection(spanText, start + key.length());
}
}
3)删除表情
3.1)输入法中的删除,很自然的一个字符就删除一个,一个表情就删除一个表情(OK)
3.2)表情面板中的删除按钮,一开始考虑是从text最后删除一个符号,或者匹配一个表情删除掉
int start = mEditText.getSelectionStart();
Editable content = mEditText.getText();
//正则表达式去判读最后一个符号是不是表情
Matcher matcher = Pattern.compile("\\{:\\d{1,2}:\\}$", Pattern.CASE_INSENSITIVE).matcher(content);
if(matcher.find()){
String faceText = matcher.group();
int index = content.toString().lastIndexOf(faceText);
mEditText.setText( content.delete(index, index+faceText.length()) );
}else{
mEditText.setText( content.delete(content.length()-1, content.length()) );
}
//然后再重新定位光标
CharSequence info = mEditText.getText();
if (info instanceof Spannable) {
Spannable spanText = (Spannable) info;
if(start > spanText.length()){
start = spanText.length();
}
Selection.setSelection(spanText, start);
}
3.3)很明显3.2中的方法比较麻烦,而且凌乱(貌似也有Bug)。另一种方法是于3.1的效果一致,就是直接调用系统的删除方式
//一句话搞定,我也是醉了
mEditText.onKeyDown(KeyEvent.KEYCODE_DEL, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL));
4)最后封装一个输入框与表情合并的Dialog(使用WindowManager创建)
public class ReplyDialog implements View.OnClickListener{
...
private WindowManager mWindowManager;
public static LayoutParams mLayoutParams;
private View mView;
private OnSendListener mListener;
private Context mContext;
public ReplyDialog(Context context) {
mContext = context;
mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
mLayoutParams = new LayoutParams();
mLayoutParams.type = LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
mLayoutParams.format = PixelFormat.RGBA_8888;
// mLayoutParams.flags = LayoutParams.FLAG_ALT_FOCUSABLE_IM;
mLayoutParams.gravity = Gravity.LEFT|Gravity.TOP;
// mLayoutParams.softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
mView = View.inflate(mContext,R.layout.layout_dongtai_reply_dialog,null);
ViewUtils.inject(this, mView);
//
pager_emo.bindEditText(et_dongtai_dialog_content);
v_dongtai_input_outside.setOnClickListener(this);
tv_dongtai_dialog_cancel.setOnClickListener(this);
iv_dongtai_dialog_biaoqing.setOnClickListener(this);
et_dongtai_dialog_content.setOnClickListener(this);
btn_dongtai_dialog_send.setOnClickListener(this);
et_dongtai_dialog_content.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN){
hide();
return true;
}
return false;
}
});
}
public void show(OnSendListener listener){
mListener = listener;
try{
et_dongtai_dialog_content.setText("");
mWindowManager.addView(mView, mLayoutParams);
mView.postDelayed(new Runnable() {
@Override
public void run() {
// et_dongtai_dialog_content.requestFocus();
showSoftInputView();
}
}, 200);
}catch(Exception e){
e.printStackTrace();
}
}
public void hide(){
try{
pager_emo.setVisibility(View.GONE);
mWindowManager.removeView(mView);
}catch(Exception e){
e.printStackTrace();
}
}
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.v_dongtai_input_outside:
case R.id.tv_dongtai_dialog_cancel:
hideSoftInputView();
hide();
break;
case R.id.iv_dongtai_dialog_biaoqing:
hideSoftInputView();
pager_emo.setVisibility(View.VISIBLE);
break;
case R.id.et_dongtai_dialog_content:
pager_emo.setVisibility(View.GONE);
// showSoftInputView();
break;
case R.id.btn_dongtai_dialog_send:
{
String message = et_dongtai_dialog_content.getText().toString();
if("".equals(message)){
Toast.makeText(mContext, "请输入回复内容", Toast.LENGTH_LONG).show();
break;
}
mListener.onSend(message);
hide();
break;
}
}
}
public void hideSoftInputView() {
InputMethodManager manager = ((InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE));
manager.hideSoftInputFromWindow(et_dongtai_dialog_content.getWindowToken(), 0);
}
private void showSoftInputView() {
InputMethodManager manager = ((InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE));
manager.showSoftInput(et_dongtai_dialog_content, InputMethodManager.SHOW_FORCED);
}
public interface OnSendListener{
public void onSend(String content);
}
}
4.1)布局文件就不给了,仅供参考就行了
4.2)show()的时候输入法不能弹出问题
//可能是还未初始化完成,所以添加了延迟(这个地方试了好久,postDelayed在很多地方也可以用用)
mView.postDelayed(new Runnable() {
@Override
public void run() {
// et_dongtai_dialog_content.requestFocus();
showSoftInputView();
}
}, 200);
4.3)返回按键被windowManager拦截了,没有处理
//在view中来处理这个返回键
et_dongtai_dialog_content.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN){
hide();
return true;
}
return false;
}
});
4.4)最后把文本内容发送出去
//加了个接口,哈哈
public interface OnSendListener{
public void onSend(String content);
}
注意一点,这里从EditText中获取的文本其实还是表情符号对应的{:n:},而不是图片,或者图片stream
勉强的写完了