Android 仿QQ 微信 即时通讯聊天listview和发送
2017-04-25 本文已影响1707人
ROOM先生
效果图1
效果图2
仿照QQ和微信类似页面聊天 发送表情页面的demo.
MainActivity.java
package com.example.liupanpan.chatimg;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.text.Editable;
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.ImageSpan;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.example.liupanpan.chatimg.adapter.ChatLVAdapter;
import com.example.liupanpan.chatimg.adapter.FaceGVAdapter;
import com.example.liupanpan.chatimg.adapter.FaceVPAdapter;
import com.example.liupanpan.chatimg.bean.ChatInfo;
import com.example.liupanpan.chatimg.view.DropdownListView;
import com.example.liupanpan.chatimg.view.MyEditText;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* */
public class MainActivity extends Activity implements OnClickListener, DropdownListView.OnRefreshListenerHeader {
private ViewPager mViewPager;
private LinearLayout mDotsLayout;
private MyEditText input;
private Button send;
private DropdownListView mListView;
private ChatLVAdapter mLvAdapter;
private LinearLayout chat_face_container;
private ImageView image_face;//表情图标
// 7列3行
private int columns = 6;
private int rows = 4;
private List<View> views = new ArrayList<View>();
private List<String> staticFacesList;
private LinkedList<ChatInfo> infos = new LinkedList<ChatInfo>();
private SimpleDateFormat sd;
private String reply = "";//模拟回复
@SuppressLint("SimpleDateFormat")
private void initViews() {
mListView = (DropdownListView) findViewById(R.id.message_chat_listview);
sd = new SimpleDateFormat("MM-dd HH:mm");
//模拟收到信息
infos.add(getChatInfoFrom("你好啊!"));
infos.add(getChatInfoFrom("认识你很高兴#[face/png/f_static_018.png]#"));
mLvAdapter = new ChatLVAdapter(this, infos);
mListView.setAdapter(mLvAdapter);
//表情图标
image_face = (ImageView) findViewById(R.id.image_face);
//表情布局
chat_face_container = (LinearLayout) findViewById(R.id.chat_face_container);
mViewPager = (ViewPager) findViewById(R.id.face_viewpager);
mViewPager.setOnPageChangeListener(new PageChange());
//表情下小圆点
mDotsLayout = (LinearLayout) findViewById(R.id.face_dots_container);
input = (MyEditText) findViewById(R.id.input_sms);
input.setOnClickListener(this);
send = (Button) findViewById(R.id.send_sms);
InitViewPager();
//表情按钮
image_face.setOnClickListener(this);
// 发送
send.setOnClickListener(this);
mListView.setOnRefreshListenerHead(this);
mListView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View arg0, MotionEvent arg1) {
if (arg1.getAction() == MotionEvent.ACTION_DOWN) {
if (chat_face_container.getVisibility() == View.VISIBLE) {
chat_face_container.setVisibility(View.GONE);
}
}
return false;
}
});
}
@Override
public void onClick(View arg0) {
switch (arg0.getId()) {
case R.id.input_sms://输入框
if (chat_face_container.getVisibility() == View.VISIBLE) {
chat_face_container.setVisibility(View.GONE);
}
break;
case R.id.image_face://表情
hideSoftInputView();//隐藏软键盘
if (chat_face_container.getVisibility() == View.GONE) {
chat_face_container.setVisibility(View.VISIBLE);
} else {
chat_face_container.setVisibility(View.GONE);
}
break;
case R.id.send_sms://发送
reply = input.getText().toString();
if (!TextUtils.isEmpty(reply)) {
infos.add(getChatInfoTo(reply));
mLvAdapter.setList(infos);
mLvAdapter.notifyDataSetChanged();
mListView.setSelection(infos.size() - 1);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
infos.add(getChatInfoFrom(reply));
mLvAdapter.setList(infos);
mLvAdapter.notifyDataSetChanged();
mListView.setSelection(infos.size() - 1);
}
}, 1000);
input.setText("");
}
break;
}
}
/*
* 初始表情 *
*/
private void InitViewPager() {
// 获取页数
for (int i = 0; i < getPagerCount(); i++) {
views.add(viewPagerItem(i));
LayoutParams params = new LayoutParams(16, 16);
mDotsLayout.addView(dotsItem(i), params);
}
FaceVPAdapter mVpAdapter = new FaceVPAdapter(views);
mViewPager.setAdapter(mVpAdapter);
mDotsLayout.getChildAt(0).setSelected(true);
}
private View viewPagerItem(int position) {
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.face_gridview, null);//表情布局
GridView gridview = (GridView) layout.findViewById(R.id.chart_face_gv);
/**
* 注:因为每一页末尾都有一个删除图标,所以每一页的实际表情columns * rows - 1; 空出最后一个位置给删除图标
* */
List<String> subList = new ArrayList<String>();
subList.addAll(staticFacesList
.subList(position * (columns * rows - 1),
(columns * rows - 1) * (position + 1) > staticFacesList
.size() ? staticFacesList.size() : (columns
* rows - 1)
* (position + 1)));
/**
* 末尾添加删除图标
* */
subList.add("emotion_del_normal.png");
FaceGVAdapter mGvAdapter = new FaceGVAdapter(subList, this);
gridview.setAdapter(mGvAdapter);
gridview.setNumColumns(columns);
// 单击表情执行的操作
gridview.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
try {
String png = ((TextView) ((LinearLayout) view).getChildAt(1)).getText().toString();
if (!png.contains("emotion_del_normal")) {// 如果不是删除图标
insert(getFace(png));
} else {
delete();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
return gridview;
}
private SpannableStringBuilder getFace(String png) {
SpannableStringBuilder sb = new SpannableStringBuilder();
try {
/**
* 经过测试,虽然这里tempText被替换为png显示,但是但我单击发送按钮时,获取到輸入框的内容是tempText的值而不是png
* 所以这里对这个tempText值做特殊处理
* 格式:#[face/png/f_static_000.png]#,以方便判斷當前圖片是哪一個
* */
String tempText = "#[" + png + "]#";
sb.append(tempText);
sb.setSpan(
new ImageSpan(MainActivity.this, BitmapFactory
.decodeStream(getAssets().open(png))), sb.length()
- tempText.length(), sb.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
} catch (Exception e) {
e.printStackTrace();
}
return sb;
}
/**
* 向输入框里添加表情
*/
private void insert(CharSequence text) {
int iCursorStart = Selection.getSelectionStart((input.getText()));
int iCursorEnd = Selection.getSelectionEnd((input.getText()));
if (iCursorStart != iCursorEnd) {
((Editable) input.getText()).replace(iCursorStart, iCursorEnd, "");
}
int iCursor = Selection.getSelectionEnd((input.getText()));
((Editable) input.getText()).insert(iCursor, text);
}
/**
* 删除图标执行事件
* 注:如果删除的是表情,在删除时实际删除的是tempText即图片占位的字符串,所以必需一次性删除掉tempText,才能将图片删除
*/
private void delete() {
if (input.getText().length() != 0) {
int iCursorEnd = Selection.getSelectionEnd(input.getText());
int iCursorStart = Selection.getSelectionStart(input.getText());
if (iCursorEnd > 0) {
if (iCursorEnd == iCursorStart) {
if (isDeletePng(iCursorEnd)) {
String st = "#[face/png/f_static_000.png]#";
((Editable) input.getText()).delete(
iCursorEnd - st.length(), iCursorEnd);
} else {
((Editable) input.getText()).delete(iCursorEnd - 1,
iCursorEnd);
}
} else {
((Editable) input.getText()).delete(iCursorStart,
iCursorEnd);
}
}
}
}
/**
* 判断即将删除的字符串是否是图片占位字符串tempText 如果是:则讲删除整个tempText
**/
private boolean isDeletePng(int cursor) {
String st = "#[face/png/f_static_000.png]#";
String content = input.getText().toString().substring(0, cursor);
if (content.length() >= st.length()) {
String checkStr = content.substring(content.length() - st.length(),
content.length());
String regex = "(\\#\\[face/png/f_static_)\\d{3}(.png\\]\\#)";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(checkStr);
return m.matches();
}
return false;
}
private ImageView dotsItem(int position) {
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.dot_image, null);
ImageView iv = (ImageView) layout.findViewById(R.id.face_dot);
iv.setId(position);
return iv;
}
/**
* 根据表情数量以及GridView设置的行数和列数计算Pager数量
*
* @return
*/
private int getPagerCount() {
int count = staticFacesList.size();
return count % (columns * rows - 1) == 0 ? count / (columns * rows - 1)
: count / (columns * rows - 1) + 1;
}
/**
* 初始化表情列表staticFacesList
*/
private void initStaticFaces() {
try {
staticFacesList = new ArrayList<String>();
String[] faces = getAssets().list("face/png");
//将Assets中的表情名称转为字符串一一添加进staticFacesList
for (int i = 0; i < faces.length; i++) {
staticFacesList.add(faces[i]);
}
//去掉删除图片
staticFacesList.remove("emotion_del_normal.png");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 表情页改变时,dots效果也要跟着改变
*/
class PageChange implements OnPageChangeListener {
@Override
public void onPageScrollStateChanged(int arg0) {
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageSelected(int arg0) {
for (int i = 0; i < mDotsLayout.getChildCount(); i++) {
mDotsLayout.getChildAt(i).setSelected(false);
}
mDotsLayout.getChildAt(arg0).setSelected(true);
}
}
/**
* 发送的信息
*
* @param message
* @return
*/
private ChatInfo getChatInfoTo(String message) {
ChatInfo info = new ChatInfo();
info.content = message;
info.fromOrTo = 1;
info.time = sd.format(new Date());
return info;
}
/**
* 接收的信息
*
* @param message
* @return
*/
private ChatInfo getChatInfoFrom(String message) {
ChatInfo info = new ChatInfo();
info.content = message;
info.fromOrTo = 0;
info.time = sd.format(new Date());
return info;
}
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
mLvAdapter.setList(infos);
mLvAdapter.notifyDataSetChanged();
mListView.onRefreshCompleteHeader();
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chat_main);
initStaticFaces();
initViews();
}
@Override
public void onRefresh() {
new Thread() {
@Override
public void run() {
try {
sleep(1000);
Message msg = mHandler.obtainMessage(0);
mHandler.sendMessage(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
public void hideSoftInputView() {
InputMethodManager manager = ((InputMethodManager) this.getSystemService(Activity.INPUT_METHOD_SERVICE));
if (getWindow().getAttributes().softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) {
if (getCurrentFocus() != null)
manager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/chat_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/header"
layout="@layout/header" />
<com.example.liupanpan.chatimg.view.DropdownListView
android:id="@+id/message_chat_listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/bottom"
android:layout_below="@id/header"
android:background="@color/white"
android:cacheColorHint="@color/transparent"
android:divider="@null"
android:listSelector="@color/transparent" />
<LinearLayout
android:id="@+id/bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="0.1dp"
android:background="@color/gray" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/chat_bottom_shape">
<ImageView
android:id="@+id/image_face"
android:layout_width="30dip"
android:layout_height="30dip"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="4dip"
android:src="@drawable/chat_emo_normal"
android:visibility="visible" />
<com.example.liupanpan.chatimg.view.MyEditText
android:id="@+id/input_sms"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_centerVertical="true"
android:layout_marginLeft="9dip"
android:layout_marginRight="9dip"
android:layout_toLeftOf="@+id/send_sms"
android:layout_toRightOf="@id/image_face"
android:background="@null"
android:hint="@string/edittext_notice_0"
android:padding="4dip"
android:singleLine="true"
android:textSize="14sp" />
<Button
android:id="@+id/send_sms"
android:layout_width="50dp"
android:layout_height="40dp"
android:layout_alignBottom="@id/input_sms"
android:layout_alignParentRight="true"
android:layout_alignTop="@id/input_sms"
android:layout_centerVertical="true"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:background="@drawable/button_shape"
android:gravity="center"
android:text="@string/send"
android:textColor="#578fbe"
android:textSize="14sp" />
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.1dp"
android:background="@color/gray" />
<include
android:id="@+id/chat_face_container"
layout="@layout/chat_face_container"
android:visibility="gone" />
</LinearLayout>
</RelativeLayout>
自定义DropdownListView
package com.example.liupanpan.chatimg.view;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import com.example.liupanpan.chatimg.R;
public class DropdownListView extends ListView implements OnScrollListener {
private static final String TAG = "listview";
private final static int RELEASE_To_REFRESH = 0;
private final static int PULL_To_REFRESH = 1;
private final static int REFRESHING = 2;
private final static int DONE = 3;
private final static int LOADING = 4;
// 实际的padding的距离与界面上偏移距离的比例
private final static int RATIO = 3;
private LayoutInflater inflater;
private FrameLayout fl;
private LinearLayout headView;
// private View line;
private ProgressBar progressBar;
// private RotateAnimation animation;
// private RotateAnimation reverseAnimation;
// 用于保证startY的值在一个完整的touch事件中只被记录一次
private boolean isRecored;
private int headContentWidth;
private int headContentHeight;
private int startY;
private int firstItemIndex;
private int state;
private boolean isBack;
private OnRefreshListenerHeader refreshListenerHeader;
private boolean isRefreshableHeader;
public DropdownListView(Context context) {
super(context);
init(context);
}
public DropdownListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
setCacheColorHint(context.getResources().getColor(R.color.transparent));
inflater = LayoutInflater.from(context);
fl = (FrameLayout)inflater.inflate(R.layout.dropdown_lv_head, null);
headView = (LinearLayout) fl.findViewById(R.id.drop_down_head);
progressBar = (ProgressBar) fl.findViewById(R.id.loading);
measureView(headView);
headContentHeight = headView.getMeasuredHeight();
headContentWidth = headView.getMeasuredWidth();
headView.setPadding(0, -1 * headContentHeight, 0, 0);
headView.invalidate();
Log.v("size", "width:" + headContentWidth + " height:"
+ headContentHeight);
addHeaderView(fl, null, false);
// addHeaderView(headView, null, false);
setOnScrollListener(this);
state = DONE;
isRefreshableHeader = false;
}
public void onScroll(AbsListView arg0, int firstVisiableItem, int arg2,
int arg3) {
firstItemIndex = firstVisiableItem;
}
public void onScrollStateChanged(AbsListView arg0, int scrollState) {
if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
// 判断滚动到底部
}
}
public boolean onTouchEvent(MotionEvent event) {
if (isRefreshableHeader) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (firstItemIndex == 0 && !isRecored) {
isRecored = true;
startY = (int) event.getY();
Log.v(TAG, "在down时候记录当前位置‘");
}
break;
case MotionEvent.ACTION_UP:
if (state != REFRESHING && state != LOADING) {
if (state == DONE) {
// 什么都不做
}
if (state == PULL_To_REFRESH) {
state = DONE;
changeHeaderViewByState();
Log.v(TAG, "由下拉刷新状态,到done状态");
}
if (state == RELEASE_To_REFRESH) {
state = REFRESHING;
changeHeaderViewByState();
// recoverLine();
onRefresh();
Log.v(TAG, "由松开刷新状态,到done状态");
}
}
isRecored = false;
isBack = false;
break;
case MotionEvent.ACTION_MOVE:
int tempY = (int) event.getY();
if (!isRecored && firstItemIndex == 0) {
Log.v(TAG, "在move时候记录下位置");
isRecored = true;
startY = tempY;
}
if (state != REFRESHING && isRecored && state != LOADING) {
// 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动
// 可以松手去刷新了
if (state == RELEASE_To_REFRESH) {
setSelection(0);
// 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步
if (((tempY - startY) / RATIO < headContentHeight)
&& (tempY - startY) > 0) {
state = PULL_To_REFRESH;
changeHeaderViewByState();
Log.v(TAG, "由松开刷新状态转变到下拉刷新状态");
}
// 一下子推到顶了
else if (tempY - startY <= 0) {
state = DONE;
changeHeaderViewByState();
Log.v(TAG, "由松开刷新状态转变到done状态");
}
// 往下拉了,或者还没有上推到屏幕顶部掩盖head的地步
else {
// 不用进行特别的操作,只用更新paddingTop的值就行了
}
}
// 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态
if (state == PULL_To_REFRESH) {
setSelection(0);
// 下拉到可以进入RELEASE_TO_REFRESH的状态
if ((tempY - startY) / RATIO >= headContentHeight) {
state = RELEASE_To_REFRESH;
isBack = true;
changeHeaderViewByState();
Log.v(TAG, "由done或者下拉刷新状态转变到松开刷新");
}
// 上推到顶了
else if (tempY - startY <= 0) {
state = DONE;
changeHeaderViewByState();
Log.v(TAG, "由DOne或者下拉刷新状态转变到done状态");
}
}
// done状态下
if (state == DONE) {
if (tempY - startY > 0) {
state = PULL_To_REFRESH;
changeHeaderViewByState();
}
}
// 更新headView的size
if (state == PULL_To_REFRESH) {
headView.setPadding(0, -1 * headContentHeight
+ (tempY - startY) / RATIO, 0, 0);
}
// 更新headView的paddingTop
if (state == RELEASE_To_REFRESH) {
headView.setPadding(0, (tempY - startY) / RATIO
- headContentHeight, 0, 0);
}
}
break;
}
}
return super.onTouchEvent(event);
}
// 当状态改变时候,调用该方法,以更新界面
private void changeHeaderViewByState() {
switch (state) {
case RELEASE_To_REFRESH:
progressBar.setVisibility(View.VISIBLE);
Log.v(TAG, "当前状态,松开刷新");
break;
case PULL_To_REFRESH:
progressBar.setVisibility(View.VISIBLE);
// 是由RELEASE_To_REFRESH状态转变来的
if (isBack) {
isBack = false;
} else {
}
Log.v(TAG, "当前状态,下拉刷新");
break;
case REFRESHING:
headView.setPadding(0, 0, 0, 0);
progressBar.setVisibility(View.VISIBLE);
Log.v(TAG, "当前状态,正在刷新...");
break;
case DONE:
headView.setPadding(0, -1 * headContentHeight, 0, 0);
progressBar.setVisibility(View.GONE);
Log.v(TAG, "当前状态,done");
break;
}
}
public void setOnRefreshListenerHead(
OnRefreshListenerHeader refreshListenerHeader) {
this.refreshListenerHeader = refreshListenerHeader;
isRefreshableHeader = true;
}
public interface OnRefreshListenerHeader {
public void onRefresh();
}
public interface OnRefreshListenerFooter {
public void onRefresh();
}
public void onRefreshCompleteHeader() {
state = DONE;
changeHeaderViewByState();
}
private void onRefresh() {
if (refreshListenerHeader != null) {
refreshListenerHeader.onRefresh();
}
}
// 此方法直接照搬自网络上的一个下拉刷新的demo,此处是“估计”headView的width以及height
private void measureView(View child) {
ViewGroup.LayoutParams p = child.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
int lpHeight = p.height;
int childHeightSpec;
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(0,
MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}
public void setAdapter(BaseAdapter adapter) {
super.setAdapter(adapter);
}
}
自定义MyEditText
package com.example.liupanpan.chatimg.view;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.ContextMenu;
import android.view.MenuItem;
import android.widget.EditText;
import android.widget.Toast;
/**
* An EditText, which notifies when something was cut/copied/pasted inside it.
*
* @author Lukas Knuth
* @version 1.0
*/
@SuppressLint("NewApi") public class MyEditText extends EditText implements
MenuItem.OnMenuItemClickListener {
private static final int ID_SELECTION_MODE = android.R.id.selectTextMode;
// Selection context mode
private static final int ID_SELECT_ALL = android.R.id.selectAll;
private static final int ID_CUT = android.R.id.cut;
private static final int ID_COPY = android.R.id.copy;
private static final int ID_PASTE = android.R.id.paste;
private final Context mContext;
/*
* Just the constructors to create a new EditText...
*/
public MyEditText(Context context) {
super(context);
this.mContext = context;
}
public MyEditText(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
}
public MyEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.mContext = context;
}
@Override
protected void onCreateContextMenu(ContextMenu menu) {
// menu.add(0, ID_PASTE, 0, "粘贴").setOnMenuItemClickListener(this);
// menu.add(0, ID_CUT, 1, "剪切").setOnMenuItemClickListener(this);
// menu.add(0, ID_COPY, 1, "复制").setOnMenuItemClickListener(this);
// menu.add(0, ID_SELECT_ALL, 1, "全选").setOnMenuItemClickListener(this);
super.onCreateContextMenu(menu);
}
@Override
public boolean onMenuItemClick(MenuItem item) {
// TODO Auto-generated method stub
return onTextContextMenuItem(item.getItemId());
}
@Override
public boolean onTextContextMenuItem(int id) {
// Do your thing:
boolean consumed = super.onTextContextMenuItem(id);
// React:
switch (id) {
case android.R.id.cut:
onTextCut();
break;
case android.R.id.paste:
onTextPaste();
break;
case android.R.id.copy:
onTextCopy();
}
return consumed;
}
/**
* Text was cut from this EditText.
*/
public void onTextCut() {
Toast.makeText(mContext, "Cut!", Toast.LENGTH_SHORT).show();
}
/**
* Text was copied from this EditText.
*/
public void onTextCopy() {
Toast.makeText(mContext, "Copy!", Toast.LENGTH_SHORT).show();
}
/**
* Text was pasted into the EditText.
*/
public void onTextPaste() {
Toast.makeText(mContext, "Paste!", Toast.LENGTH_SHORT).show();
}
}
最后附上 源码 关注我的公众号 回复:(QQ发送表情)即可得到demo链接
图片.png