第二堂(3)应用程式与使用者的互动

最后更新于:2022-04-01 00:52:50

Android API提供应用程式使用者互动的设计架构,你可以根据使用者在应用程式的操作,设计与提供应用程式与使用者的互动功能。例如使用者点击画面元件、按下实体按键,还有在触控萤幕上点击或滑动,这些操作行为通常会称为“事件”。应用程式可以依照需求加入事件的控制,当某一种事件发生的时候,也就是使用者执行某种操作,可以执行你为这些事件设计好的程式码。 Android系统的使用者操作事件控制,都是一些已经设计好的作法,根据使用者操作事件和画面元件的种类,通常是撰写实作一个接口(interface)的类别,根据这个接口的规定实作需要的方法,在方法里面设计需要执行的工作。 ## 7-1 画面元件的onClick设定 想要让应用程式提供的画面元件,可以让使用者点击以后执行一个指定的工作,最简单的作法就是在画面元件加入“android:onClick”设定,例如最常用的按钮元件(Button)。如果需要的话,也可以为文字符件(TextView)执行onClick设定。开启“res/layout/activity_main.xml”档案,参考下面的内容加入需要的设定: ~~~ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> ... <!-- 加入“android:clickable="true"”的设定,TextView元件才可以点击 --> <!-- 加入“android:onClick="方法名称"”的设定 --> <TextView ... android:clickable="true" android:onClick="aboutApp" /> </LinearLayout> ~~~ TextView是用来显示文字的元件,所以要特别加入让它可以点击的设定,如果是按钮元件的话就不用特别设定。如果希望使用者点击TextView元件以后,在画面显示应用程式名称的讯息框,就要加入需要的程式码。开启专案的“MainActivity.java”,参考下面的内容加入需要的程式码: ~~~ package net.macdidi.myandroidtutorial; ... // 加入讯息框的API import android.widget.Toast; public class MainActivity extends Activity { ... // 方法名称与onClick的设定一样,参数的型态是android.view.View public void aboutApp(View view) { // 显示讯息框,指定三个参数 // Context:通常指定为“this” // String或int:设定显示在讯息框里面的讯息或文字资源 // int:设定讯息框停留在画面的时间 Toast.makeText(this, R.string.app_name, Toast.LENGTH_LONG).show(); } } ~~~ 执行这个应用程式,在应用程式画面点击最下面的TextView元件,检查有没有显示讯息框。 ## 7-2 选单事件控制 如果应用程式提供的功能比较多一些,为了让画面可以比较简洁,通常会把功能设计为选单,选单资源的部份已经在“第二堂(1)规划与建立应用程式需要的资源”建立好了。需要让使用者选择选单项目后执行一些特定的工作,最简单的作法是为选单项目加入“onClick”的设定。开启“res/menu/main_menu.xml”档案,参考下面的内容加入需要的设定: ~~~ <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" > <!-- 为选单项目加入“android:onClick”设定 --> <item android:id="@+id/search_item" android:showAsAction="always" android:icon="@android:drawable/ic_menu_search" android:onClick="clickMenuItem" /> <item android:id="@+id/add_item" android:showAsAction="always" android:icon="@android:drawable/ic_menu_add" android:onClick="clickMenuItem" /> <item android:id="@+id/revert_item" android:showAsAction="always" android:icon="@android:drawable/ic_menu_revert" android:onClick="clickMenuItem" /> <item android:id="@+id/delete_item" android:showAsAction="always" android:icon="@android:drawable/ic_menu_delete" android:onClick="clickMenuItem" /> <!-- 这是外层的选单项目,所以不用设定 --> <item android:id="@+id/share_item" android:showAsAction="always" android:icon="@android:drawable/ic_menu_share" android:onClick="clickMenuItem" > <menu> <item android:id="@+id/googleplus_item" android:title="Google+" android:onClick="clickMenuItem" /> <item android:id="@+id/facebook_item" android:title="Facebook" android:onClick="clickMenuItem" /> </menu> </item> </menu> ~~~ 这里执行的设定跟之前的说明不太一样,所有选单项目设定的方法名称都是“clickMenuItem”。你也可以为每一个选单项目设定不同的方法名称,可是这样做的话,Activity元件里面就要宣告很多方法,所以使用这样的作法。开启“MainActivity.java”档案,参考下面的内容加入需要的程式码: ~~~ package net.macdidi.myandroidtutorial; ... import android.app.AlertDialog; import android.view.Menu; import android.view.MenuItem; public class MainActivity extends ActionBarActivity { ... // 加载选单资源 @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater menuInflater = getMenuInflater(); menuInflater.inflate(R.menu.main_menu, menu); return true; } // 使用者选择所有的选单项目都会呼叫这个方法 public void clickMenuItem(MenuItem item) { // 使用参数取得使用者选择的选单项目元件编号 int itemId = item.getItemId(); // 判断该执行什么工作,目前还没有加入需要执行的工作 switch (itemId) { case R.id.search_item: break; case R.id.add_item: break; case R.id.revert_item: break; case R.id.delete_item: break; case R.id.googleplus_item: break; case R.id.facebook_item: break; } // 测试用的程式码,完成测试后记得移除 AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this); dialog.setTitle("MenuItem Test") .setMessage(item.getTitle()) .setIcon(item.getIcon()) .show(); } } ~~~ 执行这个应用程式,选择画面上方的选单项目,检查有没有显示对话框。 ## 7-3 监听与事件介绍 “android.view”和“android.widget”套件宣告了许多“Listener”接口,这些接口通常会叫作“监听接口”。每一个监听接口可以控制使用者在应用程式中执行的一种操作,这些接口的名称都很规则,都是使用“On种类Listener”的格式命名。例如下列宣告在“android.view.View”类别中的基本监听接口: * View.OnClickListener:执行点击事件。 * View.OnLongClickListener:执行长按事件。 * View.OnKeyListener:执行实体按键操作事件。 * View.OnTouchListener:执行触控萤幕操作事件。 采用这种方式为某个画面元件加入事件控制,因为需要在程式码使用画面元件,所以一定要为元件取一个名称,设定元件名称使用“android:id="@+id/名称"”的格式: ~~~ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> ... <!-- 加入“android:id="@+id/名称"”的设定 --> <TextView android:id="@+id/show_app_name" ... /> </LinearLayout> ~~~ 为需要执行事件控制的元件设定好名称(id)以后,让使用者在点击这个元件以后,使用对话框显示比较详细的应用程式资讯,所以先在文字资源档(res/values/strings.xml)加入需要的资源: ~~~ <resources> ... <string name="about">这是Android Tutorial应用程式</string> </resources> ~~~ 开启专案的“MainActivity.java”,参考下面的内容加入需要的程式码: ~~~ package net.macdidi.myandroidtutorial; ... public class MainActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { ... // 读取在画面配置档已经设定好名称的元件 TextView show_app_name = (TextView) findViewById(R.id.show_app_name); // 建立点击监听物件 View.OnClickListener listener = new View.OnClickListener() { @Override public void onClick(View view) { AlertDialog.Builder d = new AlertDialog.Builder(MainActivity.this); d.setTitle(R.string.app_name) .setMessage(R.string.about) .show(); } }; // 注册点击监听物件 show_app_name.setOnClickListener(listener); } ... } ~~~ 执行这个应用程式,在应用程式画面点击最下面的TextView元件,检查有没有显示对话框。因为你在这个TextView元件执行OnClickListener事件的注册,它的“android:onClick”设定就被覆蓋了,所以点击以后只会显示对话框。 一般的应用程式也很常使用长按事件,开启专案的“MainActivity.java”,参考下面的内容,把原来的点击事件改为长按事件: ~~~ package net.macdidi.myandroidtutorial;   ...   public class MainActivity extends ActionBarActivity {       @Override     protected void onCreate(Bundle savedInstanceState) {         ...         // 读取在画面配置档已经设定好名称的元件         TextView show_app_name = (TextView) findViewById(R.id.show_app_name);           // 建立长按监听物件         View.OnLongClickListener listener = new View.OnLongClickListener() {               @Override             public boolean onLongClick(View view) {                 AlertDialog.Builder dialog =                     new AlertDialog.Builder(MainActivity.this);                 dialog.setTitle(R.string.app_name)                       .setMessage(R.string.about)                       .show();                 return false;             }           };           // 注册长按监听物件         show_app_name.setOnLongClickListener(listener);     }     ... } ~~~ 执行这个应用程式,在应用程式画面点击最下面的TextView元件,会显示原来设定的讯息框,长按TextView元件会显示对话框。经由这两个练习,就可以了解Android事件的设计方式,在大部份的情况下,监听接口都会以“On”开头,宣告与建立好监听物件以后,呼叫元件的“set监听接口”方法执行注册的工作。 ## 7-4 ListView元件的事件控制 ListView元件在应用程式中的应用非常多,从应用程式的功能表、浏览大量的资料或是让使用者执行资料的选择,应用程式需要类似列表资料的需求,都可以使用它来完成。它可以简单的列出一些文字的项目在画面上,让使用者浏览与选择。也可以自己设计需要的项目画面,加入图示、CheckBox或其它需要的画面元件,它呈现的画面与可以提供的操作功能都非常灵活。 这个记事本的主画面使用ListView元件显示所有的记事资料,选择一个项目以后可以显示详细的内容与执行后续的工作,所以需要为ListView设定选择项目的事件控制。开启专案的“MainActivity.java”,参考下面的内容加入需要的程式码: ~~~ package net.macdidi.myandroidtutorial; ... import android.widget.ArrayAdapter; import android.widget.ListView; public class MainActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 增加“final”关键字,让巢状类别中的程式码使用 final String[] data = { "关于Android Tutorial的事情", "一只非常可爱的小狗狗!", "一首非常好听的音乐!"}; int layoutId = android.R.layout.simple_list_item_1; ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, layoutId, data); ListView item_list = (ListView)findViewById(R.id.item_list); item_list.setAdapter(adapter); // 建立选单项目点击监听物件 AdapterView.OnItemClickListener itemListener = new AdapterView.OnItemClickListener() { // 第一个参数是使用者操作的ListView物件 // 第二个参数是使用者选择的项目 // 第三个参数是使用者选择的项目编号,第一个是0 // 第四个参数在这里没有用途 @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Toast.makeText(MainActivity.this, data[position], Toast.LENGTH_LONG).show(); } }; // 注册选单项目点击监听物件 item_list.setOnItemClickListener(itemListener); ... } ... } ~~~ 执行这个应用程式,在应用程式画面点击ListView的选单项目,看看有没有显示选单项目的内容讯息框。ListView元件也提供项目长按事件,你可以依照应用程式的需求,使用点击与长按事件提供使用者的操作。开启专案的“MainActivity.java”,参考下面的内容加入需要的程式码: ~~~ package net.macdidi.myandroidtutorial; ... import android.widget.ArrayAdapter; import android.widget.ListView; public class MainActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 增加“final”关键字,让巢状类别中的程式码使用 final String[] data = { "关于Android Tutorial的事情", "一只非常可爱的小狗狗!", "一首非常好听的音乐!"}; int layoutId = android.R.layout.simple_list_item_1; ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, layoutId, data); ListView item_list = (ListView)findViewById(R.id.item_list); item_list.setAdapter(adapter); ... // 建立选单项目长按监听物件 AdapterView.OnItemLongClickListener itemLongListener = new AdapterView.OnItemLongClickListener() { // 第一个参数是使用者操作的ListView物件 // 第二个参数是使用者选择的项目 // 第三个参数是使用者选择的项目编号,第一个是0 // 第四个参数在这里没有用途 @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { Toast.makeText(MainActivity.this, "Long: " + data[position], Toast.LENGTH_LONG).show(); return false; } }; // 注册选单项目长按监听物件 item_list.setOnItemLongClickListener(itemLongListener); ... } ... } ~~~ 执行这个应用程式,在应用程式画面长按ListView的选单项目,看看有没有显示选单项目的内容讯息框。 ## 7-5 重新规划Activity元件的程式码 如果Activity元件需要的画面元件比较多一些,使用者操作的功能也比较复杂,你应该可以想像得到,这个Activity元件类别的onCreate方法,会有一大堆呼叫findViewById方法取得画面元件物件的叙述,还有宣告与建立监听物件与执行注册的叙述。这些需要的叙述通通写在onCreate方法中,以程式设计的概念来说,一个方法的宣告有上百行的程式叙述,应该不是一种很好的写法,对开发人员来说,以后的维护与修改都会是一件不容易的工作。 为了让所有Activity元件的程式码,都可以使用一种比较固定而且容易的设计方式来完成需要的工作,建议你可以在开发每一个Activity元件类别的时候,使用像这个样版的模式来开发Activity元件: ~~~ public class SampleActivity extends Activity { // 宣告所有需要的画面元件物件字段变量 private ...; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(...); // 呼叫自己额外宣告的方法,执行所有取得画面元件物件的工作 processViews(); // 呼叫自己额外宣告的方法,执行所有注册的工作 processControllers(); } private void processViews() { // 在这个方法中,取得画面元件物件后指定给字段变量 ... = (...) findViewById(R.id.xxx); } private void processControllers() { // 在这个方法中,宣告或建立需要的监听物件 // 并执行所有需要的注册工作 ... } ... } ~~~ 熟悉这样的写法以后,原来需要执行的工作会在不同的方法中执行。你会先加入画面元件字段变量的宣告,然后在processViews方法中取得与设定画面元件物件,如果需要执行注册监听物件的工作,在processControllers方法中加入需要的程式码。这样把程式码依照工作简单的分开在不同方法中执行,对以后的维护与修改都会有一个比较固定的作法,而且比较不容易出错。所以就算是一个很简单的Activity元件,都建议你使用这样的写法。 开启专案的“MainActivity.java”,不改变原来撰写好的功能,把它改为下面的内容: ~~~ package net.macdidi.myandroidtutorial; import android.app.AlertDialog; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends ActionBarActivity { private ListView item_list; private TextView show_app_name; private static final String[] data = { "关于Android Tutorial的事情", "一只非常可爱的小狗狗!", "一首非常好听的音乐!"}; private ArrayAdapter<String> adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); processViews(); processControllers(); int layoutId = android.R.layout.simple_list_item_1; adapter = new ArrayAdapter<String>(this, layoutId, data); item_list.setAdapter(adapter); } private void processViews() { item_list = (ListView)findViewById(R.id.item_list); show_app_name = (TextView) findViewById(R.id.show_app_name); } private void processControllers() { // 建立选单项目点击监听物件 AdapterView.OnItemClickListener itemListener = new AdapterView.OnItemClickListener() { // 第一个参数是使用者操作的ListView物件 // 第二个参数是使用者选择的项目 // 第三个参数是使用者选择的项目编号,第一个是0 // 第四个参数在这里没有用途 @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Toast.makeText(MainActivity.this, data[position], Toast.LENGTH_LONG).show(); } }; // 注册选单项目点击监听物件 item_list.setOnItemClickListener(itemListener); // 建立选单项目长按监听物件 AdapterView.OnItemLongClickListener itemLongListener = new AdapterView.OnItemLongClickListener() { // 第一个参数是使用者操作的ListView物件 // 第二个参数是使用者选择的项目 // 第三个参数是使用者选择的项目编号,第一个是0 // 第四个参数在这里没有用途 @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { Toast.makeText(MainActivity.this, "Long: " + data[position], Toast.LENGTH_LONG).show(); return false; } }; // 注册选单项目长按监听物件 item_list.setOnItemLongClickListener(itemLongListener); // 建立长按监听物件 View.OnLongClickListener listener = new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this); dialog.setTitle(R.string.app_name) .setMessage(R.string.about) .show(); return false; } }; // 注册长按监听物件 show_app_name.setOnLongClickListener(listener); } // 加载选单资源 @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater menuInflater = getMenuInflater(); menuInflater.inflate(R.menu.menu_main, menu); return true; } // 使用者选择所有的选单项目都会呼叫这个方法 public void clickMenuItem(MenuItem item) { // 使用参数取得使用者选择的选单项目元件编号 int itemId = item.getItemId(); // 判断该执行什么工作,目前还没有加入需要执行的工作 switch (itemId) { case R.id.search_item: break; case R.id.add_item: break; case R.id.revert_item: break; case R.id.delete_item: break; case R.id.googleplus_item: break; case R.id.facebook_item: break; } // 测试用的程式码,完成测试后记得移除 AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this); dialog.setTitle("MenuItem Test") .setMessage(item.getTitle()) .setIcon(item.getIcon()) .show(); } // 方法名称与onClick的设定一样,参数的型态是android.view.View public void aboutApp(View view) { // 显示讯息框 // Context:通常指定为“this”;如果在巢状类别中使用,要加上这个Activity元件类别的名称,例如“元件类别名称.this” // String或int:设定显示在讯息框里面的讯息或文字资源 // int:设定讯息框停留在画面的时间,使用宣告在Toast类别中的变量,可以设定为“LENGTH_LONG”和“LENGTH_SHORT” Toast.makeText(this, R.string.app_name, Toast.LENGTH_LONG).show(); } } ~~~ 执行这个应用程式,确认所有功能都还是可以正确的运作。
';