6.8. 其它UI事件
6.8.其它UI事件
前面我们已经看过了通过实现一个OnClickListener提供onClick()从而捕获点击事件的方法。接下来思考下,输入框的最大字符限制是140,我们该怎样统计已输入字符的个数?这就需要用到另一个侦听器(Listener)。
Android为不同的事件(如触摸、点击等)提供了不同的侦听器。在这里,我们需要用到的是TextWatcher来监视文本框中文本的变化,步骤与OnClickListener大同小异。实际上,各种侦听器的用法都是很相似的。
从用户的角度来看,界面上多了一个TextView显示仍可输入的字符数。它的颜色会随着字数的减少而变化,从绿到黄,最后红色表示输入到达限制。
从Java的角度来看,我们需要实现一个TextWatcher来监视文本框的变化。它会在用户更改文本的时候触发,并根据字数的变化更新计数器。
例 6.6. res/layout/status2.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- Main Layout of Status Activity -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<!-- Title TextView-->
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content" android:gravity="center"
android:text="@string/titleStatus" android:textSize="30sp"
android:layout_margin="10dp" />
<!-- Text Counter TextView -->
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_gravity="right"
android:id="@+id/textCount" android:text="000"
android:layout_marginRight="10dp" />
<!-- Status EditText -->
<EditText android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_weight="1"
android:hint="@string/hintText" android:id="@+id/editText"
android:gravity="top|center_horizontal"></EditText>
<!-- Update Button -->
<Button android:layout_width="fill_parent"
android:layout_height="wrap_content" android:text="@string/buttonUpdate"
android:textSize="20sp" android:id="@+id/buttonUpdate"></Button>
</LinearLayout>
- 显示仍可输入字符数的TextView。其初始值为140,随着用户输入的增加而减少。
下面的StatusActivity实现了TextWatcher接口,新加入的方法列在后面。TextView初始为绿色,表示还可以继续输入;随着字数增长,它会变成黄色,表示字数接近上限;最后变成红色,表示已经达到了字数限制。
例 6.7. StatusActivity.java, final version
package com.marakana.yamba1;
import winterwell.jtwitter.Twitter;
import winterwell.jtwitter.TwitterException;
import android.app.Activity;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class StatusActivity extends Activity implements OnClickListener,
TextWatcher { //
private static final String TAG = "StatusActivity";
EditText editText;
Button updateButton;
Twitter twitter;
TextView textCount; //
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.status);
// Find views
editText = (EditText) findViewById(R.id.editText);
updateButton = (Button) findViewById(R.id.buttonUpdate);
updateButton.setOnClickListener(this);
textCount = (TextView) findViewById(R.id.textCount); //
textCount.setText(Integer.toString(140)); //
textCount.setTextColor(Color.GREEN); //
editText.addTextChangedListener(this); //
twitter = new Twitter("student", "password");
twitter.setAPIRootUrl("http://yamba.marakana.com/api");
}
// Called when button is clicked
public void onClick(View v) {
String status = editText.getText().toString();
new PostToTwitter().execute(status);
Log.d(TAG, "onClicked");
}
// Asynchronously posts to twitter
class PostToTwitter extends AsyncTask<String, Integer, String> {
// Called to initiate the background activity
@Override
protected String doInBackground(String...statuses) {
try {
Twitter.Status status = twitter.updateStatus(statuses[0]);
return status.text;
} catch (TwitterException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
return "Failed to post";
}
}
// Called when there's a status to be updated
@Override
protected void onProgressUpdate(Integer...values) {
super.onProgressUpdate(values);
// Not used in this case
}
// Called once the background activity has completed
@Override
protected void onPostExecute(String result) {
Toast.makeText(StatusActivity.this, result, Toast.LENGTH_LONG).show();
}
}
// TextWatcher methods
public void afterTextChanged(Editable statusText) { //
int count = 140 - statusText.length(); //
textCount.setText(Integer.toString(count));
textCount.setTextColor(Color.GREEN); //
if (count < 10)
textCount.setTextColor(Color.YELLOW);
if (count < 0)
textCount.setTextColor(Color.RED);
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) { // {#10}
}
public void onTextChanged(CharSequence s, int start, int before, int count) { // {#11}
}
}
- 使StatusActivity实现TextWatcher接口,并在后面提供这个接口的实现。
- textCount是我们新加入的TextView。
- 找到textCount的引用。
- 设置初始值为140,表示最大字符数限制。留意TextView的值只能是字符串,因此执行类型转换。
- textCount会随着字符数的变化而改变颜色,在这里初始化为绿色。留意,颜色都是以常量的形式定义在Android的框架中,而不是Java类库的一部分。我们用的是android.graphics.Color,而不是java.awt.Color。Color.Green是这个对象中定义的一个常量。
- 将TextWatcher绑定到文本框editText,editText在内容发生变化时,就会调用到TextWatcher的实例。
- afterTextChanged()是TextWatcher接口定义的一个方法。它在自己所监视的文本框的内容发生变化时触发,以当前的文本为参数。在这里,只要用户修改了自己的输入,它就会被触发一次。
- 做点数学,计算出当前可输入的字符数。
- 然后根据可输入的字符数,设置textCount的颜色。如果字符数大于10,就是绿色;大于零小于十,黄色;等于零,红色。
- 在文本修改之前触发。我们并不需要这个方法,但它作为TextWatcher的一部分不可以省略,因此留空。
- 同上,我们不需要这个方法,因此留空。
图6.12. StatusActivity, 2