多行文本样式的输入界面,我们首先联想到的是EditText,这一点问题都没有,但EditText貌似不能满足需求,需要实现每一行下面都带有一个横线,这就像我们小时候的横格子作业本。那么自然想到的是继承控件EditText去自定义控件,还是没有具体的实现想法。
我们知道,google android给我们的例子里面记事本NotePad其实是有实现这个功能的,那就赶紧去看看他是如何实现的吧,到这个路径下(X盘:\android-sdk-windows\samples\android-16\NotePad),这个就是对应的例程了,导入到eclipse。工程结构如下:
很明显的可以从类名知道NoteEditor.java就是我们要找的类,编辑文本的界面,在里面我们找到了如下带横线的EditText实现:
/**
* Defines a custom EditText View that draws lines between each line of text that is displayed.
*/
public static class LinedEditText extends EditText {
private Rect mRect;
private Paint mPaint;
// This constructor is used by LayoutInflater
public LinedEditText(Context context, AttributeSet attrs) {
super(context, attrs);
// Creates a Rect and a Paint object, and sets the style and color of the Paint object.
mRect = new Rect();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(0x800000FF);
}
/**
* This is called to draw the LinedEditText object
* @param canvas The canvas on which the background is drawn.
*/
@Override
protected void onDraw(Canvas canvas) {
// Gets the number of lines of text in the View.
int count = getLineCount();
// Gets the global Rect and Paint objects
Rect r = mRect;
Paint paint = mPaint;
/*
* Draws one line in the rectangle for every line of text in the EditText
*/
for (int i = 0; i < count; i++) {
// Gets the baseline coordinates for the current line of text
int baseline = getLineBounds(i, r);
/*
* Draws a line in the background from the left of the rectangle to the right,
* at a vertical position one dip below the baseline, using the "paint" object
* for details.
*/
canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint);
}
// Finishes up by calling the parent method
super.onDraw(canvas);
}
}
对应的布局如下:
/**
* @Description TODO 带下划线的EditText,实现每行下面都显示横线
*/
public class DividerEditText extends EditText {
private static final int MARGIN = 0;
private Rect mRect;
private Paint mPaint;
// This constructor is used by LayoutInflater
public DividerEditText(Context context, AttributeSet attrs) {
super(context, attrs);
// Creates a Rect and a Paint object, and sets the style and color of
// the Paint object.
mRect = new Rect();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(3.0f);
mPaint.setColor(0x800000FF);
}
/**
* This is called to draw the DividerEditText object
*
* @param canvas
* The canvas on which the background is drawn.
*/
@Override
protected void onDraw(Canvas canvas) {
// Gets the global Rect and Paint objects
Rect r = mRect;
Paint paint = mPaint;
Layout layout = getLayout();
if (!canvas.getClipBounds(r)) {
return;
}
float startX = r.left + MARGIN, stopX = r.right - MARGIN;
int count = layout.getLineCount();
int lineHeight = getLineHeight();
int height = getHeight() - getPaddingBottom() - getPaddingTop();
int n = height % lineHeight == 0 ? height / lineHeight : height / lineHeight + 1;
if (count < n) {
count = n;
}
for (int i = 1; i <= count; i++) {
int y = lineHeight * i;
canvas.drawLine(startX, y, stopX, y, paint);
}
// Finishes up by calling the parent method
super.onDraw(canvas);
}
}
首先我们可以想到PopupWindow、Dialog,直接浮于Activity之上,那我就来按照自己想法实现一下。我这里都是横向布局实现,纵向没有测试。
@SuppressLint("ViewConstructor")
public class PopupWindowNote extends PopupWindow {
private int width = 0;
private int height = 0;
private DividerEditText dividerEditText;
@SuppressWarnings("deprecation")
public PopupWindowNote(Context context, String content, final OnPopupWindowNoteClickListener onPopupWindowNoteClickListener) {
super(context);
LayoutInflater inflater = LayoutInflater.from(context);
View contentView = inflater.inflate(R.layout.dialog_note, null);
setContentView(contentView);
Button cancelBtn = (Button) contentView.findViewById(R.id.btn_cancel_popupwindow_note);
Button okBtn = (Button) contentView.findViewById(R.id.btn_ok_popupwindow_note);
dividerEditText = (DividerEditText) contentView.findViewById(R.id.det_content_popupwindow_note);
cancelBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onPopupWindowNoteClickListener.onPopupWindowNoteCancelBtnClick();
}
});
okBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onPopupWindowNoteClickListener.onPopupWindowNoteOkBtnClick();
}
});
dividerEditText.setText("" + content);
setWidth(ScreenUtil.getScreenWidth(context));
setHeight(ScreenUtil.getScreenHeight(context));
setAnimationStyle(R.style.AnimStylePushInAndPushOut);
setBackgroundDrawable(new ColorDrawable(0));
setFocusable(true);
setOutsideTouchable(true);
// 点击“返回Back”消失,并且不影响背景元素
setBackgroundDrawable(new BitmapDrawable());
}
public int getPopupWindowWidth() {
return width;
}
public void setPopupWindowWidth(int width) {
this.width = width;
setWidth(this.width);
this.update(this.width, this.height);
}
public int getPopupWindowHeight() {
return height;
}
public void setPopupWindowHeight(int height) {
this.height = height;
setHeight(this.height);
this.update(this.width, this.height);
}
public String getPopupWindowNoteString() {
return dividerEditText.getText().toString().trim();
}
// PopupWindowNote回调接口
public interface OnPopupWindowNoteClickListener {
public void onPopupWindowNoteOkBtnClick();
public void onPopupWindowNoteCancelBtnClick();
}
}
使用方法:
private PopupWindowNote popupWindowNote;
......
//前提需要你的Activity实现接口OnPopupWindowNoteClickListener
popupWindowNote = new PopupWindowNote(context, "我是测试哇哈哈",this);
......
//代码中弹出调用
popupWindowNote.showAtLocation(btnInfo, Gravity.CENTER, 0, 0);
......
//activity销毁注意调用一下
@Override
public void onDestroy() {
super.onDestroy();
if (popupWindowNote.isShowing()) {
popupWindowNote.dismiss();
}
}
看来使用PopupWindow实现文本输入,问题多多,为了功能的稳定决定放弃。
PopupWindow有的问题在这里统统解决了,看代码。
public class DialogNote {
private String note;
private Context context;
private DividerEditText dividerEditText;
public DialogNote(String note, Context context) {
super();
this.note = note;
this.context = context;
}
public void show(final DialogNoteClickListener dialogNoteClickListener) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
final AlertDialog alertDialog = builder.create();
alertDialog.show();
Window win = alertDialog.getWindow();
//设置对话框满屏
win.setLayout(ScreenUtil.getScreenWidth(context), ScreenUtil.getScreenHeight(context));
win.setWindowAnimations(R.style.AnimStylePushInAndPushOut);
LayoutInflater factory = LayoutInflater.from(context);
final View view = factory.inflate(R.layout.dialog_note, null);
win.setContentView(view);
//实现弹出软键盘
win.clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
Button cancelBtn = (Button) win.findViewById(R.id.btn_cancel_popupwindow_note);
Button okBtn = (Button) win.findViewById(R.id.btn_ok_popupwindow_note);
dividerEditText = (DividerEditText) win.findViewById(R.id.det_content_popupwindow_note);
cancelBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
dialogNoteClickListener.onDialogNoteCancelBtnClick();
alertDialog.dismiss();
}
});
okBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
dialogNoteClickListener.onDialogNoteOkBtnClick();
alertDialog.dismiss();
}
});
dividerEditText.setText(note);
}
public String getNote() {
note = dividerEditText.getText().toString().trim() + "\0";
return note;
}
public interface DialogNoteClickListener {
public void onDialogNoteOkBtnClick();
public void onDialogNoteCancelBtnClick();
}
}
private DialogNote dialogNote;
......
//初始化
dialogNote = new DialogNote("我是测试数据哇", context);
//调用弹出
dialogNote.show(xxxActivity.this);
.......
看看效果如何:
布局正常,不会崩溃,可正常调起系统的复制粘贴功能,还算比较满意。
通过AlertDialog搭建的对话框,你会发现不能正常弹出输入法,解决办法:
//实现弹出软键盘
win.clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);