写一个弹出样式的多行文本输入界面,如何选择呢?

一、打造一个带横格子的输入控件

多行文本样式的输入界面,我们首先联想到的是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);
        }
    }
对应的布局如下:

<view xmlns:android="http://schemas.android.com/apk/res/android"
    class="com.example.android.notepad.NoteEditor$LinedEditText"
    android:id="@+id/note"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent"
    android:padding="5dp"
    android:scrollbars="vertical"
    android:fadingEdge="vertical"
    android:gravity="top"
    android:textSize="22sp"
    android:capitalize="sentences"
/>

原生这个代码实现,优化的不是特别好,我们继续考虑一下边界问题,优化一下:

/**
 * @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之上,那我就来按照自己想法实现一下。我这里都是横向布局实现,纵向没有测试。

1.使用PopupWindow

@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();
		
	}
}

内部实现了一个回调函数,用于监听PopupWindow上的按钮点击事件,getPopupWindowNoteString()用于获取editText上用户输入的文本内容,供Activity使用。设置editText上的内容可以通过构造函数传入。

使用方法:

private PopupWindowNote popupWindowNote;
......
//前提需要你的Activity实现接口OnPopupWindowNoteClickListener
popupWindowNote = new PopupWindowNote(context, "我是测试哇哈哈",this);
......
//代码中弹出调用
popupWindowNote.showAtLocation(btnInfo, Gravity.CENTER, 0, 0);
......
//activity销毁注意调用一下
@Override
public void onDestroy() {
<span style="white-space:pre">	</span>super.onDestroy();
	if (popupWindowNote.isShowing()) {
		popupWindowNote.dismiss();
	}
}

本来以为大工搞成运行一下看看效果吧。布局有问题,按钮没有显示全,怎么才能显示全呢,只能通过margin属性控制了。这都不是大问题,输入文字试试,当多行文字输入后滚动向下,直接崩溃了。而且无法调起来文本自带的文本复制功能,这也是为什么我放弃了使用PopupWindow实现这个功能了。


看来使用PopupWindow实现文本输入,问题多多,为了功能的稳定决定放弃。

2.使用Dialog方式

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();
		
	}
	
}

和popup类似,实现了相关借口,使用方法类同。

private DialogNote dialogNote;
......
//初始化
dialogNote = new DialogNote("我是测试数据哇", context);
//调用弹出
dialogNote.show(xxxActivity.this);
.......
看看效果如何:



布局正常,不会崩溃,可正常调起系统的复制粘贴功能,还算比较满意。

通过AlertDialog搭建的对话框,你会发现不能正常弹出输入法,解决办法:

//实现弹出软键盘
win.clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);

直接继承Dialog创建对话框,听说是没有问题的,这个没有测试。

3.使用到的布局

<?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:background="@color/white"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="@dimen/offset_6dp"
        android:layout_marginRight="@dimen/offset_6dp"
        android:layout_marginTop="@dimen/offset_6dp" >

        <Button
            android:id="@+id/btn_cancel_popupwindow_note"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:text="cancel"
            android:textColor="@android:color/black"
            android:textSize="@dimen/textsize_level_10" />

        <Button
            android:id="@+id/btn_ok_popupwindow_note"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:text="ok"
            android:textColor="@color/black"
            android:textSize="@dimen/textsize_level_10" />
    </RelativeLayout>

        <com.xxx.widget.DividerEditText
            android:id="@+id/det_content_popupwindow_note"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/offset_6dp"
            android:layout_marginRight="@dimen/offset_6dp"
            android:background="@null"
            android:gravity="top"
            android:lines="10"
            android:imeOptions="flagNoExtractUi"
            android:scrollbars="none"
            android:textColor="@color/black"
            android:textSize="@dimen/textsize_level_10" >
        </com.xxx.widget.DividerEditText>

</LinearLayout>


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TYYJ-洪伟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值