Android實現自帶橫線的EditText

yangxi_001發表於2014-07-24

(一)問題

怎樣實現帶有橫欄的EditText(像記事本的編輯介面那樣)?

(二)初步思路

1.通過修改EditText背景來實現(系統背景是一個框形圖片,內部透明,替換為一個帶有橫欄的圖片即可)

2.通過重繪EditText來實現(自定義元件,自己畫線)

3.用ListView實現(ListView本身就會顯示橫線)

(三)深入分析

1.EditText顯示多行文字時會自動拉伸背景,若要保證邊框不會失真,需要用9patch圖片來做背景,或許能夠實現

2.毫無疑問,自定義EditText一定可以實現橫線的顯示(沒有槍炮就自己造...),但是自定義元件比較麻煩(需要重寫很多東西),能用其他方法解決當然更好

3.ListView用來顯示多行文字可能比較好(將Text分割為等長String存入Array,作為ListView的Adapter),但是若要編輯文字則明顯不合適

(四)初步實踐

1.通過多次測試發現改變EditText的背景圖能夠顯示橫欄,但僅限於SingLine的文字,因為輸入多行文字時背景圖會向下拉伸(橫線沒了...)。所以測試結果是:用自定義背景圖只能顯示帶下劃線的單行文字,方案一失敗!但是在此過程中學到了9patch圖片的用處,算是一點小收穫。

2.通過重寫EditText的onDraw方法來繪製需要的橫線,如何確定橫線的位置成為核心問題(本質是獲取一組起點座標和一組對應的終點座標),此方法在下面展開詳述

3.ListView的缺點在上面已經說過了,但是經過對方案一的嘗試,我們很容易發現方案一和方案三恰好互補(把方案一得到的EditText作為ListView的Item),此時應該為EditText自定義selector,設定focus時不發光即可。測試結果是:單行EditText負責按行顯示文字,ListView負責畫線,方案一組合方案三可行。

(五)自定義EditText實現橫欄的顯示

[自定義myEditText類]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package com.ayqy.app_test;
 
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.widget.EditText;
 
public class myEditText extends EditText{
     
    private int lineColor;//橫線顏色
    private float lineWidth;//橫線寬度
 
    public myEditText(Context context) {
        super(context);
         
        //設定預設顏色和橫線寬度
        lineColor = Color.BLUE;//預設藍色線
        lineWidth = 2f;//寬度為2
    }
     
    public myEditText(Context context,int color,float width) {
        super(context);
         
        //設定顏色和橫線寬度
        this.lineColor = color;
        this.lineWidth = width;
    }
 
    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        super.onDraw(canvas);
         
        //建立畫筆
        Paint mPaint = new Paint();
        mPaint.setStrokeWidth(lineWidth);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(lineColor);
         
        //獲取引數
        int w = this.getWidth();//獲取控制元件寬度
        int h = this.getHeight();//獲取控制元件高度
        int padB = this.getPaddingBottom();//獲取底部留白
        int padL = this.getPaddingLeft();//獲取左邊留白
        int padR = this.getPaddingRight();//獲取右邊留白
        float size = this.getTextSize() * 7 / 6;//獲取橫欄間距(TextSize的預設值為18)
        /*設定size的值是一個核心問題,size的值要適應不同的字型大小(不同大小字型的行距也不同)
         *經過多次嘗試發現以字型大小的7/6倍作為橫欄間距最合適
         * */
        int lines = (int)(h / size);//獲取行數
         
        //從下向上畫線
        for(int i = 0;i < lines;i++)
            canvas.drawLine(padL//startX
                    , this.getHeight() - padB - size * i//startY
                    , this.getWidth() - padR//endX
                    , this.getHeight() - padB - size * i//endY
                    , mPaint);
    }
     
    public int getLineColor() {
        return lineColor;
    }
 
    public void setLineColor(int color) {
        this.lineColor = color;
    }
 
    public float getLineWidth() {
        return lineWidth;
    }
 
    public void setLineWidth(float width) {
        this.lineWidth = width;
    }
 
}

[佈局檔案]

1
2
3
4
5
6
7
8
9
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >
 
</LinearLayout>

[測試類]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.ayqy.app_test;
 
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.widget.LinearLayout;
 
public class MainActivity extends Activity {
     
    LinearLayout root;//宣告根佈局
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
         
        root = (LinearLayout) findViewById(R.id.root);//獲取根佈局
        //建立自定義EditText控制元件物件
        myEditText txt = new myEditText(this);
        //設定多行文字
        txt.setText("這是一個很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長的測試內容");
        //用來測試是否能夠適應不同大小的字型
        //txt.setTextSize(48);
        //txt.setTextSize(24);
        root.addView(txt);//新增控制元件
    }
 
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
 
}

[P.S.以上原始碼本機測試無誤,若在測試中發現任何問題請在下方留言]

(六)測試結果圖片

(七)總結

嘗試是解決問題的最好方法,即便最終問題得不到解決,其間的思考也是一種鍛鍊

(八)BUG修正

此版本存在BUG,詳情及修正方法見 http://www.cnblogs.com/ayqy/p/3600289.html

相關文章