最近在用原生的控件和佈局繪製一些界面並使用,雖然這些都是Android基本知識,但是有的時候真的感覺力不從心,感覺有必要對Android常用的控件和佈局做一個系統的瞭解。後續一個月甚至更多的時間都會圍繞這個主題展開,畢竟這裏面還是有不少高級控件的,我也會盡量結合應用深入的進行了解。
上一篇:TextView 下一篇:AutoCompleteTextView與MultiAutoCompleteTextView
在上一篇中,我們對TextView及其屬性進行了比較完整的學習,當然還有很多沒有觸及到的知識點,今天我們的主題是EditText,它是 TextView的直接子類,下面我們就結合官方的文檔描述展開學習:
* A user interface element for entering and modifying text. * When you define an edit text widget, you must specify the * {@link android.R.styleable#TextView_inputType} * attribute. For example, for plain text input set inputType to "text": * <p> * <pre> * <EditText * android:id="@+id/plain_text_input" * android:layout_height="wrap_content" * android:layout_width="match_parent" * android:inputType="text"/></pre>
一個用戶可以編輯和修改文本的接口,當你定義一個EditText控件時,一定要給定文本輸入類型屬性。下面還給了一個例子
上面的文檔對EditText做了一個總體的介紹,這個控件支持用戶編輯和修改文本,但是一定要設置inputType屬性,這個屬性真的很重要,平時在使用的過程中會經常用到。那麼我們首先看一下一個TextView的模樣:
在使用EditText的時候,我們通常都是提供一個給用戶輸入信息的接口,比如別人註冊一個信息,需要輸入年齡,性別,電話號碼,郵箱以及密碼等等各種各樣的信息。那我們就有一個疑問了,每一條信息的數據樣式都是千差萬別的,比如郵箱是有特定格式的,電話號碼只能是數字且長度固定,難道這些都需要我們自己等用戶把所有信息輸入完成之後自己再一個一個校驗嗎,顯然不是的,這裏就需要用到它(準確說是TextView的)的一個屬性android:inputType。關於text的type都是統一定義在EditorInfo,我們在EditText的setTextType接口中找到答案:
* Set the type of the content with a constant as defined for {@link EditorInfo#inputType}. This * will take care of changing the key listener, by calling {@link #setKeyListener(KeyListener)}, * to match the given content type. If the given content type is {@link EditorInfo#TYPE_NULL} * then a soft keyboard will not be displayed for this text view.
當然我們也可以通過對控件添加鍵盤監聽來實現。因爲考慮到inputType類型較多,我們直接根據Android的Design界面推薦的來學習。
下面我們就三個一起作爲一組來學習
(1)第一組:
- Plain Text:普通文本
- Password:密碼
- Password(Numeric):數字密碼
在開始之前,爲了更好的演示,我可能會使用電腦鍵盤配合軟鍵盤的方式進行,如果你的模擬器軟鍵盤沒有開啓,請參照如下操作打開,電腦鍵盤類似:
好了,環境準備好之後,我們來看一下運行的效果:
(2)第二組:
- E-mail:電子郵件
- Phone:電話
- Postal-Address:郵箱地址
運行的結果如下:
(3)第三組:
- MultilineText:多行文本
- Time:時間
- Date:日期
運行結果如下(這裏爲了比較第一個類型,特地加了一個EditText):
(4)第四組:
- Number
- Number(Singed)
- Number(Decimal)
運行結果:
上面列舉了EditText的inputType的幾個屬性,主要是依據XML佈局Design界面中推薦的幾個,也是平時使用較多的幾個,其實,該參數還可以通過EditText的setInputType()接口來實現,比如:
text.setInputType(EditorInfo.TYPE_TEXT_VARIATION_POSTAL_ADDRESS);
那這個設置的參數動作究竟做了哪些邏輯處理了:
* Set the type of the content with a constant as defined for {@link EditorInfo#inputType}. This * will take care of changing the key listener, by calling {@link #setKeyListener(KeyListener)}, * to match the given content type. If the given content type is {@link EditorInfo#TYPE_NULL} * then a soft keyboard will not be displayed for this text view.
通過一個定義在EditorInfo中的常量來設置EditText可以輸入的內容類型,實現主要是通過改變KeyListener監聽實現。
下面會介紹EditText的監聽內容。關於inputType的類型還有很多其他類型,具體請參考EditorInfo類
EditText的監聽部分,我們主要介紹兩個,一個是焦點狀態改變監聽View.OnFocusChangeListener,另一個就是View.OnKeyListener,下面我們就來簡單學習一下
- View.OnFocusChangeListener
- View.OnKeyListener
(1)View.OnFocusChangeListener,使用與測試結果如下:
text=findViewById(R.id.editText);
text.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
text.setText("是否有焦點:"+hasFocus);
}
});
<LinearLayout
android:gravity="center"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_weight="2"
android:layout_height="0dp">
<EditText
android:id="@+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="測試View" />
<EditText
android:id="@+id/editText2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="協助View" />
</LinearLayout>
(2)View.OnKeyListener,使用與測試結果如下:
text=findViewById(R.id.editText);
text1=findViewById(R.id.editText2);
text.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
text1.setText("keyCode:"+keyCode+"v=text:"+(v==text));
return false;
}
});
關於回調接口的介紹以及回調接口中的參數介紹如下:
* Called when a hardware key is dispatched to a view. This allows listeners to * get a chance to respond before the target view. * <p>Key presses in software keyboards will generally NOT trigger this method, * although some may elect to do so in some situations. Do not assume a * software input method has to be key-based; even if it is, it may use key presses * in a different way than you expect, so there is no way to reliably catch soft * input key presses. * * @param v The view the key has been dispatched to. * @param keyCode The code for the physical key that was pressed * @param event The KeyEvent object containing full information about * the event. * @return True if the listener has consumed the event, false otherwise.
當硬件鍵盤key被點擊的事件傳遞給一個View的時候,這個回調會調用,這樣我們就可以在最終的View處理該事件之前作出響應。
通常軟鍵盤的點擊不會觸發該方法,儘管有些時候會(比如點擊數字)。軟件的輸入方式不一定是鍵盤點擊的方式,即便如此,使用鍵盤點擊作爲輸入也不一定按照你的預期進行,鋪貨軟鍵盤的點擊輸入是不可靠的。
- 最終處理該Event的View
- 按下的物理鍵盤按鈕對應於KeyEvent中的編碼
- 包含此點擊事件信息的KeyEvent
如果返回true,我們就拿不到這個點擊的數據了,所以通常我們都保持默認的返回false。
考慮到上述的描述,我們先使用電腦鍵盤輸入演示,然後在使用軟鍵盤演示看一下
電腦鍵盤輸入:
軟鍵盤輸入:
這個結果驗證上面的描述。okay,下面我們就來結合這兩個監聽事件實現一個平時註冊界面常見的場景:
- 監聽enter鍵點擊實現切換焦距
- 對輸入的內容進行校驗(這裏比較簡單,可以做成實時監聽的方案)
運行的效果如下:
具體的實現代碼如下:
package aoto.com.commonwidgetandlayout.basic_widget.editText;
import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.method.KeyListener;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import aoto.com.commonwidgetandlayout.R;
/**
* @author why
* @date 2019-6-3 19:14:44
*/
public class EditTextActivity extends AppCompatActivity {
EditText userNameView;
EditText userPsdView;
TextView userNameTip;
TextView userPsdTip;
boolean userNameTrigger = false;
boolean userPsdTrigger = false;
boolean userNameLegal=false;
boolean userPsdLegal=false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_text);
userNameView = findViewById(R.id.editText);
userPsdView = findViewById(R.id.editText1);
userNameTip = findViewById(R.id.userName_edit_tip);
userPsdTip = findViewById(R.id.userPsd_edit_tip);
userNameView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus && userNameTrigger) {
userNameLegal=checkString(userNameView.getText().toString());
if (userNameLegal) {
userNameTip.setText("用戶名合法");
userNameTip.setTextColor(Color.GREEN);
userNameTip.setVisibility(View.VISIBLE);
} else {
userNameTip.setTextColor(Color.RED);
userNameTip.setText("密碼只能由文本字符,數字組成");
userNameTip.setVisibility(View.VISIBLE);
}
}
}
});
userNameView.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
userNameTrigger = true;
if (keyCode == KeyEvent.KEYCODE_ENTER) {
userPsdView.requestFocus();
}
return false;
}
});
userPsdView.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_ENTER && userPsdTrigger == true) {
userPsdLegal=checkString(userPsdView.getText().toString());
if (userPsdLegal) {
userPsdTip.setText("密碼合法");
userPsdTip.setTextColor(Color.GREEN);
userPsdTip.setVisibility(View.VISIBLE);
if(userNameLegal&&userPsdLegal){
Toast.makeText(EditTextActivity.this, "註冊成功", Toast.LENGTH_SHORT).show();
}
} else {
userPsdTip.setTextColor(Color.RED);
userPsdTip.setText("密碼只能由文本字符,數字組成");
userPsdTip.setVisibility(View.VISIBLE);
}
} else {
userPsdTrigger = true;
}
return false;
}
});
}
private boolean checkString(String string) {
for (char c : string.toCharArray()) {
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
return false;
}
}
return true;
}
}
佈局文件也比較簡單:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="3"
tools:context="aoto.com.commonwidgetandlayout.basic_widget.editText.EditTextActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:weightSum="10">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="請輸入用戶名:"
android:textAlignment="viewEnd"
android:textColor="#000000"
android:textSize="20sp" />
<EditText
android:id="@+id/editText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:gravity="center"
android:hint="請輸入用戶名"
android:inputType="text"
android:textSize="20sp" />
<TextView
android:id="@+id/userName_edit_tip"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="4"
android:textAlignment="textStart"
android:textStyle="italic" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:weightSum="10">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="請輸入密碼:"
android:textAlignment="viewEnd"
android:textColor="#000000"
android:textSize="20sp" />
<EditText
android:id="@+id/editText1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:gravity="center"
android:hint="請輸入密碼"
android:inputType="textPassword"
android:textSize="20sp" />
<TextView
android:id="@+id/userPsd_edit_tip"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="4"
android:textAlignment="textStart"
android:textStyle="italic" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
到這裏,關於EditText以及其使用就介紹的差不多了,下一篇會介紹兩個EditText的子類,如果喜歡,可以掃碼關注。
注:歡迎掃碼關注