Java Android TextWatcher为撤消/重做保存类似更改的批处理
每次对EditText内容进行一批类似的更改后,我都会尝试对其进行快照 例如:Java Android TextWatcher为撤消/重做保存类似更改的批处理,java,android,android-edittext,undo,textwatcher,Java,Android,Android Edittext,Undo,Textwatcher,每次对EditText内容进行一批类似的更改后,我都会尝试对其进行快照 例如: 当我对连续/重叠文本执行几次连续删除时,这是一个批处理,我对由此产生的EditText内容进行快照 当我在连续/重叠的文本上进行几个连续添加时,这是一个批处理,我对由此产生的EditText内容进行快照 当我对连续/重叠的文本执行多个连续替换(=修改)时,这是一个批处理,我对由此产生的EditText内容进行快照 我希望你能明白 仅供参考:我需要一个撤销/重做机制,因为我不想/可以在每次文本更改时创建快照 我怎样才能
editBigField.addTextChangedListener(new TextWatcher() {
private static final int NONE = -1;
private static final int DELETE = 0;
private static final int ADD = 1;
private static final int MODIFY = 2;
private int lastAction = NONE;
private int delete;
private int addstart;
private int addend;
private int modstart;
private int modend;
@Override
public void afterTextChanged(Editable s) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
if (after == 0) // delete text
{
if (lastAction != DELETE || !(start <= delete && start + count - 1 >= delete)) {
// save state here TODO
lastAction = DELETE;
}
delete = start;
}
else if (count == 0 && after > 0) // add text
{
if (lastAction != ADD || !(start >= addstart - 1 && start <= addend)) {
// save state here TODO
lastAction = ADD;
}
addstart = start;
addend = start + after;
}
else if (count != 0 && after > 0) // modify/replace text
{
if (lastAction != MODIFY || !(start + count - 1 >= modstart - 1 && start <= modend)) {
// save state here TODO
lastAction = MODIFY;
}
modstart = start;
modend = start + after;
}
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
});
editBigField.addTextChangedListener(新的TextWatcher(){
私有静态final int NONE=-1;
私有静态final int DELETE=0;
专用静态最终整数相加=1;
私有静态final int MODIFY=2;
private int lastAction=NONE;
私有int删除;
私有int addstart;
专用整数加数;
私人int modstart;
私有int模式;
@凌驾
公共无效后文本已更改(可编辑){
}
@凌驾
更改前文本之前的公共void(字符序列s、int start、int count、int after){
if(after==0)//删除文本
{
if(lastAction!=删除| |!(start=删除)){
//在此处保存状态待办事项
lastAction=删除;
}
删除=开始;
}
else if(count==0&&after>0)//添加文本
{
if(lastAction!=ADD | |!(start>=addstart-1&&start 0)//修改/替换文本
{
如果(lastAction!=MODIFY | | |!(start+count-1>=modstart-1&&start可能有人需要它。使用批撤消/重做实现:
public class UndoRedoHelper {
private static final String TAG = UndoRedoHelper.class.getCanonicalName();
private boolean mIsUndoOrRedo = false;
private EditHistory mEditHistory;
private EditTextChangeListener mChangeListener;
private TextView mTextView;
// =================================================================== //
public UndoRedoHelper(TextView textView) {
mTextView = textView;
mEditHistory = new EditHistory();
mChangeListener = new EditTextChangeListener();
mTextView.addTextChangedListener(mChangeListener);
}
// =================================================================== //
public void disconnect() {
mTextView.removeTextChangedListener(mChangeListener);
}
public void setMaxHistorySize(int maxHistorySize) {
mEditHistory.setMaxHistorySize(maxHistorySize);
}
public void clearHistory() {
mEditHistory.clear();
}
public boolean getCanUndo() {
return (mEditHistory.mmPosition > 0);
}
public void undo() {
EditItem edit = mEditHistory.getPrevious();
if (edit == null) {
return;
}
Editable text = mTextView.getEditableText();
int start = edit.mmStart;
int end = start + (edit.mmAfter != null ? edit.mmAfter.length() : 0);
mIsUndoOrRedo = true;
text.replace(start, end, edit.mmBefore);
mIsUndoOrRedo = false;
for (Object o : text.getSpans(0, text.length(), UnderlineSpan.class)) {
text.removeSpan(o);
}
Selection.setSelection(text, edit.mmBefore == null ? start : (start + edit.mmBefore.length()));
}
public boolean getCanRedo() {
return (mEditHistory.mmPosition < mEditHistory.mmHistory.size());
}
public void redo() {
EditItem edit = mEditHistory.getNext();
if (edit == null) {
return;
}
Editable text = mTextView.getEditableText();
int start = edit.mmStart;
int end = start + (edit.mmBefore != null ? edit.mmBefore.length() : 0);
mIsUndoOrRedo = true;
text.replace(start, end, edit.mmAfter);
mIsUndoOrRedo = false;
// This will get rid of underlines inserted when editor tries to come
// up with a suggestion.
for (Object o : text.getSpans(0, text.length(), UnderlineSpan.class)) {
text.removeSpan(o);
}
Selection.setSelection(text, edit.mmAfter == null ? start
: (start + edit.mmAfter.length()));
}
public void storePersistentState(Editor editor, String prefix) {
// Store hash code of text in the editor so that we can check if the
// editor contents has changed.
editor.putString(prefix + ".hash",
String.valueOf(mTextView.getText().toString().hashCode()));
editor.putInt(prefix + ".maxSize", mEditHistory.mmMaxHistorySize);
editor.putInt(prefix + ".position", mEditHistory.mmPosition);
editor.putInt(prefix + ".size", mEditHistory.mmHistory.size());
int i = 0;
for (EditItem ei : mEditHistory.mmHistory) {
String pre = prefix + "." + i;
editor.putInt(pre + ".start", ei.mmStart);
editor.putString(pre + ".before", ei.mmBefore.toString());
editor.putString(pre + ".after", ei.mmAfter.toString());
i++;
}
}
public boolean restorePersistentState(SharedPreferences sp, String prefix)
throws IllegalStateException {
boolean ok = doRestorePersistentState(sp, prefix);
if (!ok) {
mEditHistory.clear();
}
return ok;
}
private boolean doRestorePersistentState(SharedPreferences sp, String prefix) {
String hash = sp.getString(prefix + ".hash", null);
if (hash == null) {
// No state to be restored.
return true;
}
if (Integer.valueOf(hash) != mTextView.getText().toString().hashCode()) {
return false;
}
mEditHistory.clear();
mEditHistory.mmMaxHistorySize = sp.getInt(prefix + ".maxSize", -1);
int count = sp.getInt(prefix + ".size", -1);
if (count == -1) {
return false;
}
for (int i = 0; i < count; i++) {
String pre = prefix + "." + i;
int start = sp.getInt(pre + ".start", -1);
String before = sp.getString(pre + ".before", null);
String after = sp.getString(pre + ".after", null);
if (start == -1 || before == null || after == null) {
return false;
}
mEditHistory.add(new EditItem(start, before, after));
}
mEditHistory.mmPosition = sp.getInt(prefix + ".position", -1);
if (mEditHistory.mmPosition == -1) {
return false;
}
return true;
}
// =================================================================== //
private final class EditHistory {
private int mmPosition = 0;
private int mmMaxHistorySize = -1;
private final LinkedList<EditItem> mmHistory = new LinkedList<EditItem>();
private void clear() {
mmPosition = 0;
mmHistory.clear();
}
private void add(EditItem item) {
while (mmHistory.size() > mmPosition) {
mmHistory.removeLast();
}
mmHistory.add(item);
mmPosition++;
if (mmMaxHistorySize >= 0) {
trimHistory();
}
}
private void setMaxHistorySize(int maxHistorySize) {
mmMaxHistorySize = maxHistorySize;
if (mmMaxHistorySize >= 0) {
trimHistory();
}
}
private void trimHistory() {
while (mmHistory.size() > mmMaxHistorySize) {
mmHistory.removeFirst();
mmPosition--;
}
if (mmPosition < 0) {
mmPosition = 0;
}
}
private EditItem getCurrent() {
if (mmPosition == 0) {
return null;
}
return mmHistory.get(mmPosition - 1);
}
private EditItem getPrevious() {
if (mmPosition == 0) {
return null;
}
mmPosition--;
return mmHistory.get(mmPosition);
}
private EditItem getNext() {
if (mmPosition >= mmHistory.size()) {
return null;
}
EditItem item = mmHistory.get(mmPosition);
mmPosition++;
return item;
}
}
private final class EditItem {
private int mmStart;
private CharSequence mmBefore;
private CharSequence mmAfter;
public EditItem(int start, CharSequence before, CharSequence after) {
mmStart = start;
mmBefore = before;
mmAfter = after;
}
@Override
public String toString() {
return "EditItem{" +
"mmStart=" + mmStart +
", mmBefore=" + mmBefore +
", mmAfter=" + mmAfter +
'}';
}
}
enum ActionType {
INSERT, DELETE, PASTE, NOT_DEF;
}
private final class EditTextChangeListener implements TextWatcher {
private CharSequence mBeforeChange;
private CharSequence mAfterChange;
private ActionType lastActionType = ActionType.NOT_DEF;
private long lastActionTime = 0;
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
if (mIsUndoOrRedo) {
return;
}
mBeforeChange = s.subSequence(start, start + count);
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (mIsUndoOrRedo) {
return;
}
mAfterChange = s.subSequence(start, start + count);
makeBatch(start);
}
private void makeBatch(int start) {
ActionType at = getActionType();
EditItem editItem = mEditHistory.getCurrent();
if ((lastActionType != at || ActionType.PASTE == at || System.currentTimeMillis() - lastActionTime > 1000) || editItem == null) {
mEditHistory.add(new EditItem(start, mBeforeChange, mAfterChange));
} else {
if (at == ActionType.DELETE) {
editItem.mmStart = start;
editItem.mmBefore = TextUtils.concat(mBeforeChange, editItem.mmBefore);
} else {
editItem.mmAfter = TextUtils.concat(editItem.mmAfter, mAfterChange);
}
}
lastActionType = at;
lastActionTime = System.currentTimeMillis();
}
private ActionType getActionType() {
if (!TextUtils.isEmpty(mBeforeChange) && TextUtils.isEmpty(mAfterChange)) {
return ActionType.DELETE;
} else if (TextUtils.isEmpty(mBeforeChange) && !TextUtils.isEmpty(mAfterChange)) {
return ActionType.INSERT;
} else {
return ActionType.PASTE;
}
}
public void afterTextChanged(Editable s) {
}
}
}
公共类{
私有静态最终字符串标记=UndoRedoHelper.class.getCanonicalName();
私有布尔值misundorredo=false;
私人编辑历史医学;
私有EditTextChangeListener-McChangeListener;
私有文本视图mTextView;
// =================================================================== //
公共撤消还原帮助程序(TextView TextView){
mTextView=textView;
mEditHistory=新编辑历史();
McChangeListener=新的EditTextChangeListener();
mTextView.addTextChangedListener(McChangeListener);
}
// =================================================================== //
公共空间断开连接(){
removeTextChangedListener(McChangeListener);
}
public void setMaxHistorySize(int maxHistorySize){
mEditHistory.setMaxHistorySize(maxHistorySize);
}
公共历史{
医学的;
}
公共布尔getCanUndo(){
返回(mEditHistory.mm位置>0);
}
公共作废撤消(){
EditItem edit=mEditHistory.getPrevious();
如果(编辑==null){
返回;
}
可编辑文本=mTextView.getEditableText();
int start=edit.mmStart;
int end=start+(edit.mmAfter!=null?edit.mmAfter.length():0);
misundorredo=正确;
text.replace(开始、结束、编辑.mmBefore);
misundorredo=假;
for(对象o:text.getSpans(0,text.length(),UnderlineSpan.class)){
文本。删除span(o);
}
Selection.setSelection(text,edit.mmBefore==null?start:(start+edit.mmBefore.length());
}
公共布尔getCanRedo(){
返回(mEditHistory.mmPosition