6.8. 其它UI事件

优质
小牛编辑
128浏览
2023-12-01

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>

  1. 显示仍可输入字符数的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}

}

}

  1. 使StatusActivity实现TextWatcher接口,并在后面提供这个接口的实现。
  2. textCount是我们新加入的TextView。
  3. 找到textCount的引用。
  4. 设置初始值为140,表示最大字符数限制。留意TextView的值只能是字符串,因此执行类型转换。
  5. textCount会随着字符数的变化而改变颜色,在这里初始化为绿色。留意,颜色都是以常量的形式定义在Android的框架中,而不是Java类库的一部分。我们用的是android.graphics.Color,而不是java.awt.Color。Color.Green是这个对象中定义的一个常量。
  6. 将TextWatcher绑定到文本框editText,editText在内容发生变化时,就会调用到TextWatcher的实例。
  7. afterTextChanged()是TextWatcher接口定义的一个方法。它在自己所监视的文本框的内容发生变化时触发,以当前的文本为参数。在这里,只要用户修改了自己的输入,它就会被触发一次。
  8. 做点数学,计算出当前可输入的字符数。
  9. 然后根据可输入的字符数,设置textCount的颜色。如果字符数大于10,就是绿色;大于零小于十,黄色;等于零,红色。
  10. 在文本修改之前触发。我们并不需要这个方法,但它作为TextWatcher的一部分不可以省略,因此留空。
  11. 同上,我们不需要这个方法,因此留空。

图6.12. StatusActivity, 2