Android learning Demo (11): a custom EditText display line

Source: Internet
Author: User

When processing an EditText file today, I want to take EditText as a copy of the paper on a homework book. Each row can be separated by lines. The specific effect is as follows:


1) First Thought

The idea at the beginning is very simple. Just find the height of each line and draw lines one line at a time. The Code is as follows:

    viewHeight = getMeasuredHeight();    viewWidth = getMeasuredWidth();    lineHeight = getLineHeight();    int maxLines = viewHeight / lineHeight + 1;    int i = 0;    int currentLineHeight = 0;while(i < maxLines){currentLineHeight += lineHeight;canvas.drawLine(0, currentLineHeight, viewWidth, currentLineHeight, mPaint);i++;}
However, the height is obviously not enough, as shown in the following figure:


It seems to be a matter of height, so add a bit of height to each line. Try again:

lineHeight = getLineHeight() + 5;
Let's take a look at the effect,

The first few lines seem to have a good effect, but they are crowded together. I guess the reason is that the value returned by getLineHeight is not standard, but it varies with the content. Let's take a look at its function description as follows:

    /**     * @return the height of one standard line in pixels.  Note that markup     * within the text can cause individual lines to be taller or shorter     * than this height, and the layout may contain additional first-     * or last-line padding.     */    public int getLineHeight() {        return FastMath.round(mTextPaint.getFontMetricsInt(null) * mSpacingMult + mSpacingAdd);    }
Indeed, the getLineHeight is used to indicate that the height of each row is not feasible.

In the sample provided by android, there is a small demo of NotePad, which adds an underline to each line in EditText. The Code is as follows:

    public static class LinedEditText extends EditText {       ...             @Override        protected void onDraw(Canvas canvas) {            int count = getLineCount();            Rect r = mRect;            Paint paint = mPaint;            for (int i = 0; i < count; i++) {                int baseline = getLineBounds(i, r);                canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint);            }            super.onDraw(canvas);        }    }
Okay, let's use it.


Good! However, if a problem is found, it will not be underlined if there is no character at the end, because it is based on the getLineCount function, which is defined as follows:

    /**     * Return the number of lines of text, or 0 if the internal Layout has not     * been built.     */    public int getLineCount() {        return mLayout != null ? mLayout.getLineCount() : 0;    }
That is to say, the returned value is related to the content, while the value of getLineBounds is based on getLineCount, which is defined as follows (see the first comment ):

    /**     * Return the baseline for the specified line (0...getLineCount() - 1)     * If bounds is not null, return the top, left, right, bottom extents     * of the specified line in it. If the internal Layout has not been built,     * return 0 and set bounds to (0, 0, 0, 0)     * @param line which line to examine (0..getLineCount() - 1)     * @param bounds Optional. If not null, it returns the extent of the line     * @return the Y-coordinate of the baseline     */    public int getLineBounds(int line, Rect bounds)
Therefore, only the rows with content can be underlined, but our goal is to draw a line even if there is no content. How can this problem be solved?

My idea is as simple as it is. The lines displayed on the screen are actually limited, so I will divide them into two parts. The first part has content. I will use the above NotePad method to draw the picture, if the number of lines has filled this area (in fact, it reaches the predefined maximum number), you do not have to draw it yourself. Otherwise, if there are still a few differences, then, based on the average height already drawn above, draw the remaining lines, because when the input content, EditText is actually refreshing, so naturally, the lines of the newly added content are also drawn using the NotePad method above, so the drawn lines are also in line with the requirements. The complete code for the custom EditText is as follows:

package com.lms.todo.views;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.util.AttributeSet;import android.widget.EditText;/** * @author Linmiansheng */public class CustomEditText extends EditText {//private static final String TAG = "com.lms.todo.views.CustomEditText";private Rect mRect;    private Paint mPaint;        private final int padding = 10;        private int lineHeight;    private int viewHeight,viewWidth;    public CustomEditText(Context context) {        this(context, null);    }    public CustomEditText(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public CustomEditText(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        init(context, attrs);    }    private void init(Context context, AttributeSet attrs) {        mRect = new Rect();        mPaint = new Paint();        mPaint.setStyle(Paint.Style.STROKE);        mPaint.setColor(Color.BLACK);        mPaint.setAntiAlias(true);                setFocusable(true);        setFocusableInTouchMode(true);            }    @Override    protected void onDraw(Canvas canvas) {    int count = getLineCount();        Rect r = mRect;                 Paint paint = mPaint;        int lineHeight = 0;        int i = 0;        while (i < count) {lineHeight = getLineBounds(i, r);canvas.drawLine(r.left, lineHeight + padding, r.right, lineHeight + padding,paint);i++;}int maxLines = 15;int avgHeight = lineHeight / count;int currentLineHeight = lineHeight;while(i < maxLines){currentLineHeight = currentLineHeight + avgHeight + padding;canvas.drawLine(r.left, currentLineHeight, r.right, currentLineHeight, paint);i++;}        super.onDraw(canvas);          }}

However, it should be noted that the padding setting, that is, the height of each row, is actually related to the font size we set during application. Therefore, if it is a real application, you may need to tune it.

The usage in xml layout is as follows:

    <com.lms.todo.views.CustomEditText        android:id="@+id/etContent"        android:layout_width="match_parent"        android:layout_height="0dp"        android:layout_marginLeft="5dp"        android:layout_marginRight="5dp"        android:layout_weight="8"        android:background="#00000000"        android:gravity="top"        android:inputType="textMultiLine"        android:padding="5dip"        android:textSize="20sp" />

End.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.