第三堂(1)为ListView元件建立自定画面

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

ListView是Android应用程式很常使用的画面元件,它可以显示多笔资料项目让使用者浏览、选择与执行后续的操作。目前完成的记事应用程式,只有把简单的文字资料设定给ListView元件使用,其实这个元件有非常多不同的用途,它可以显示比较复杂的资料项目,让使用者勾选和执行后续的功能。 这一章会加强ListView元件的使用,为它设计专用的画面,让一个项目可以显示比较多的资料: [![AndroidTutorial5_03_01_01](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_03_01_01-190x300.png)](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_03_01_01.png) 为了让记事资料可以清楚的分类,所以在新增与修改记事加入设定颜色的功能: [![AndroidTutorial5_03_01_02](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_03_01_02-190x300.png)](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_03_01_02.png) [![AndroidTutorial5_03_01_03](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_03_01_03-190x300.png)](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_03_01_03.png) 在浏览记事资料的主画面,提供使用者勾选项目的功能,在未选择与已选择项目的状态,需要显示不同的功能表项目: [![AndroidTutorial5_03_01_04](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_03_01_04-190x300.png)](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_03_01_04.png) [![AndroidTutorial5_03_01_05](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_03_01_05-190x300.png)](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_03_01_05.png) 如果使用者选择记事项目,为应用程式加入删除记事的功能: [![AndroidTutorial5_03_01_06](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_03_01_06-182x300.png)](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_03_01_06.png) ## 9-1 记事资料的封装 不论是开发一般Java或Android应用程式,应用程式的功能越写越多,程式码也会更复杂,一般的物件封装作法可以让程式码比较简洁一些。这个应用程式需要管理所有的记事资料,所以应该为应用程式新增一个封装记事资料的类别。因为希望可以为每一个记事资料加入颜色设定的功能,所以先建立一个封装颜色资料的类别。在“net.macdidi.myandroidtutorial”套件上按鼠标右键,选择“New -> Java Class”,在Create New Class对话框的Name输入“Colors”,Kind选择“Enum”后选择“OK”。参考下面的内容完成这个程式码: ~~~ package net.macdidi.myandroidtutorial; import android.graphics.Color; public enum Colors { LIGHTGREY("#D3D3D3"), BLUE("#33B5E5"), PURPLE("#AA66CC"), GREEN("#99CC00"), ORANGE("#FFBB33"), RED("#FF4444"); private String code; private Colors(String code) { this.code = code; } public String getCode() { return code; } public int parseColor() { return Color.parseColor(code); } } ~~~ 在“net.macdidi.myandroidtutorial”套件上按鼠标右键,选择“New -> Java Class”,在Create New Class对话框的Name输入“Item”后选择“OK”。参考下面的内容完成这个程式码: ~~~ package net.macdidi.myandroidtutorial; import java.util.Date; import java.util.Locale; public class Item implements java.io.Serializable { // 编号、日期时间、颜色、标题、内容、档案名称、经纬度、修改、已选择 private long id; private long datetime; private Colors color; private String title; private String content; private String fileName; private double latitude; private double longitude; private long lastModify; private boolean selected; public Item() { title = ""; content = ""; color = Colors.LIGHTGREY; } public Item(long id, long datetime, Colors color, String title, String content, String fileName, double latitude, double longitude, long lastModify) { this.id = id; this.datetime = datetime; this.color = color; this.title = title; this.content = content; this.fileName = fileName; this.latitude = latitude; this.longitude = longitude; this.lastModify = lastModify; } public long getId() { return id; } public void setId(long id) { this.id = id; } public long getDatetime() { return datetime; } // 装置区域的日期时间 public String getLocaleDatetime() { return String.format(Locale.getDefault(), "%tF %<tR", new Date(datetime)); } // 装置区域的日期 public String getLocaleDate() { return String.format(Locale.getDefault(), "%tF", new Date(datetime)); } // 装置区域的时间 public String getLocaleTime() { return String.format(Locale.getDefault(), "%tR", new Date(datetime)); } public void setDatetime(long datetime) { this.datetime = datetime; } public Colors getColor() { return color; } public void setColor(Colors color) { this.color = color; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public double getLatitude() { return latitude; } public void setLatitude(double latitude) { this.latitude = latitude; } public double getLongitude() { return longitude; } public void setLongitude(double longitude) { this.longitude = longitude; } public long getLastModify() { return lastModify; } public void setLastModify(long lastModify) { this.lastModify = lastModify; } public boolean isSelected() { return selected; } public void setSelected(boolean selected) { this.selected = selected; } } ~~~ 为了让记事资料项目可以使用不同的颜色分类,所以新增一个绘图资源。在“res/drawable”目录上按鼠标右键,选择“New -> Drawable resource file”。在“File name”输入“item_drawable”后选择“OK”。参考下面的内容完成这个绘图资源: ~~~ <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <corners android:topLeftRadius="20sp" android:topRightRadius="20sp" android:bottomLeftRadius="20sp" android:bottomRightRadius="20sp" /> <solid android:color="#AAAAAA"/> </shape> ~~~ 为了让ListView元件的每一个项目可以显示比较多的资料,你可以为项目建立一个画面配置档。这个画面配置档需要使用一个额外的图示(selected_icon.png),用来显示使用者已经选择一个项目,你可以在GitHub这一章的范例程式专案找到这个图档,把它复制到“res/drawable”目录。现在准备新增一个给ListView元件项目使用的画面资源,在“res/layout”目录上按鼠标右键,选择“New -> Layout resource file”。在“File name”输入“single_item”后选择“OK”。参考下面的内容完成这个画面资源: ~~~ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <!-- 颜色分类 --> <RelativeLayout android:id="@+id/type_color" android:layout_width="64dp" android:layout_height="64dp" android:layout_margin="3sp" android:background="@drawable/item_drawable" > <!-- 勾选 --> <ImageView android:id="@+id/selected_item" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true" android:src="@drawable/selected_icon" android:visibility="invisible" /> </RelativeLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="3sp" android:gravity="center_vertical" android:orientation="vertical" > <!-- 标题 --> <TextView android:id="@+id/title_text" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:gravity="center_vertical" /> <!-- 日期时间 --> <TextView android:id="@+id/date_text" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:gravity="center_vertical" /> </LinearLayout> </LinearLayout> ~~~ 需要在ListView元件中显示比较复杂的画面,就不能使用一般的Adapter物件,你可以依照自己的需求,撰写一个自定的Adapter类别给ListView元件使用。在“net.macdidi.myandroidtutorial”套件上按鼠标右键,选择“New -> Java Class”,在Create New Class对话框的Name输入“ItemAdapter”后选择“OK”。参考下面的内容完成这个程式码: ~~~ package net.macdidi.myandroidtutorial; import java.util.List; import android.content.Context; import android.graphics.drawable.GradientDrawable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; public class ItemAdapter extends ArrayAdapter { // 画面资源编号 private int resource; // 包装的记事资料 private List items; public ItemAdapter(Context context, int resource, List items) { super(context, resource, items); this.resource = resource; this.items = items; } @Override public View getView(int position, View convertView, ViewGroup parent) { LinearLayout itemView; // 读取目前位置的记事物件 final Item item = getItem(position); if (convertView == null) { // 建立项目画面元件 itemView = new LinearLayout(getContext()); String inflater = Context.LAYOUT_INFLATER_SERVICE; LayoutInflater li = (LayoutInflater) getContext().getSystemService(inflater); li.inflate(resource, itemView, true); } else { itemView = (LinearLayout) convertView; } // 读取记事颜色、已选择、标题与日期时间元件 RelativeLayout typeColor = (RelativeLayout) itemView.findViewById(R.id.type_color); ImageView selectedItem = (ImageView) itemView.findViewById(R.id.selected_item); TextView titleView = (TextView) itemView.findViewById(R.id.title_text); TextView dateView = (TextView) itemView.findViewById(R.id.date_text); // 设定记事颜色 GradientDrawable background = (GradientDrawable)typeColor.getBackground(); background.setColor(item.getColor().parseColor()); // 设定标题与日期时间 titleView.setText(item.getTitle()); dateView.setText(item.getLocaleDatetime()); // 设定是否已选择 selectedItem.setVisibility(item.isSelected() ? View.VISIBLE : View.INVISIBLE); return itemView; } // 设定指定编号的记事资料 public void set(int index, Item item) { if (index >= 0 && index < items.size()) { items.set(index, item); notifyDataSetChanged(); } } // 读取指定编号的记事资料 public Item get(int index) { return items.get(index); } } ~~~ 完成这些程式码与画面配置档以后,就完成基本的准备工作了。 ## 9-2 使用自定画面的ListView元件 为了让ListView元件使用已经准备好的程式码与资源,之前已经写好的主画面元件,就要执行比较大幅度的修改。开启“net.macdidi.myandroidtutorial”套件下的“MainActivity.java”,修改字段变量的宣告: ~~~ private ListView item_list; private TextView show_app_name; // 删除原来的宣告 //private ArrayList data = new ArrayList<>(); //private ArrayAdapter adapter; // ListView使用的自定Adapter物件 private ItemAdapter itemAdapter; // 储存所有记事本的List物件 private List items; // 选单项目物件 private MenuItem add_item, search_item, revert_item, share_item, delete_item; // 已选择项目数量 private int selectedCount = 0; ~~~ 同样在“MainActivity.java”,参考下列的说明,修改“onCreate”方法的程式码: ~~~ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); processViews(); processControllers(); // 删除原来的程式码 //data.add("关于Android Tutorial的事情"); //data.add("一只非常可爱的小狗狗!"); //data.add("一首非常好听的音乐!"); //int layoutId = android.R.layout.simple_list_item_1; //adapter = new ArrayAdapter(this, layoutId, data); //item_list.setAdapter(adapter); // 加入范例资料 items = new ArrayList(); items.add(new Item(1, new Date().getTime(), Colors.RED, "关于Android Tutorial的事情.", "Hello content", "", 0, 0, 0)); items.add(new Item(2, new Date().getTime(), Colors.BLUE, "一只非常可爱的小狗狗!", "她的名字叫“大热狗”,又叫\n作“奶嘴”,是一只非常可爱\n的小狗。", "", 0, 0, 0)); items.add(new Item(3, new Date().getTime(), Colors.GREEN, "一首非常好听的音乐!", "Hello content", "", 0, 0, 0)); // 建立自定Adapter物件 itemAdapter = new ItemAdapter(this, R.layout.single_item, items); item_list.setAdapter(itemAdapter); } ~~~ 执行上面的修改以后,会发现这个程式码出现一些错误,这些错误会在“onActivityResult”与“processControllers”这两个方法里面,你可以参考下列的作法,先把这两的方法的所有程式码加上注解,后面再慢慢修改它们: ~~~ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { /* ... */ } private void processControllers() { /* ... */ } ~~~ 使用上面介绍的方法处理程式码以后,错误的情况就会消失了,先执行这个应用程式,看看是否可以正常的显示应用程式画面。 ## 9-3 新增记事的资料传送与接收 改用目前的方式处理记事资料以后,新增记事的作法就要执行一些必要的修改。开启“net.macdidi.myandroidtutorial”套件下的“ItemActivity.java”,加入这些新的字段变量宣告: ~~~ // 启动功能用的请求代码 private static final int START_CAMERA = 0; private static final int START_RECORD = 1; private static final int START_LOCATION = 2; private static final int START_ALARM = 3; private static final int START_COLOR = 4; // 记事物件 private Item item; ~~~ 同样在“ItemActivity.java”,参考下列的说明,修改“onCreate”方法的程式码: ~~~ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_item); processViews(); // 取得Intent物件 Intent intent = getIntent(); // 读取Action名称 String action = intent.getAction(); // 如果是修改记事 if (action.equals("net.macdidi.myandroidtutorial.EDIT_ITEM")) { // 接收与设定记事标题 String titleText = intent.getStringExtra("titleText"); title_text.setText(titleText); } // 新增记事 else { item = new Item(); } } ~~~ 同样在“ItemActivity.java”,参考下列的说明,修改“onSubmit”方法的程式码,调整确认新增记事以后要执行的工作: ~~~ // 点击确定与取消按钮都会呼叫这个方法 public void onSubmit(View view) { // 确定按钮 if (view.getId() == R.id.ok_teim) { // 读取使用者输入的标题与内容 String titleText = title_text.getText().toString(); String contentText = content_text.getText().toString(); // 设定记事物件的标题与内容 item.setTitle(titleText); item.setContent(contentText); // 如果是修改记事 if (getIntent().getAction().equals( "net.macdidi.myandroidtutorial.EDIT_ITEM")) { item.setLastModify(new Date().getTime()); } // 新增记事 else { item.setDatetime(new Date().getTime()); } Intent result = getIntent(); // 设定回传的记事物件 result.putExtra("net.macdidi.myandroidtutorial.Item", item); setResult(Activity.RESULT_OK, result); } // 结束 finish(); } ~~~ 回到“net.macdidi.myandroidtutorial”套件下的“MainActivity.java”,找到“onActivityResult”方法,移除之前加入的注解,参考下列的程式码修改新增记事后需要处理的工作。因为修改记事的部份还没有完成,所以先把它们设定为注解。 ~~~ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // 如果被启动的Activity元件传回确定的结果 if (resultCode == Activity.RESULT_OK) { // 读取记事物件 Item item = (Item) data.getExtras().getSerializable( "net.macdidi.myandroidtutorial.Item"); // 如果是新增记事 if (requestCode == 0) { // 设定记事物件的编号与日期时间 item.setId(items.size() + 1); item.setDatetime(new Date().getTime()); // 加入新增的记事物件 items.add(item); // 通知资料改变 itemAdapter.notifyDataSetChanged(); } /* // 如果是修改记事 else if (requestCode == 1) { ... } */ } } ~~~ 完成上面的工作以后,执行这个应用程式,测试新增记式资料的功能是否正确。 ## 9-4 修改记事的资料传送与接收 完成新增记事功能以后,接下来处理工作比较多一些的修改记事功能。开启“net.macdidi.myandroidtutorial”套件下的“MainActivity.java”,找到“processControllers”方法,移除之前加入的注解。在这个方法中找到处理ListView项目长按事件的程式码,先把它们设定为注解: ~~~ /* // 建立选单项目长按监听物件 OnItemLongClickListener itemLongListener = new OnItemLongClickListener() { ... } }; // 注册选单项目长按监听物件 item_list.setOnItemLongClickListener(itemLongListener); */ ~~~ 接下来参考下列的程式码,修改处理ListView项目点击事件的程式码: ~~~ // 建立选单项目点击监听物件 AdapterView.OnItemClickListener itemListener = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { // 读取选择的记事物件 Item item = itemAdapter.getItem(position); Intent intent = new Intent( "net.macdidi.myandroidtutorial.EDIT_ITEM"); // 设定记事编号与记事物件 intent.putExtra("position", position); intent.putExtra("net.macdidi.myandroidtutorial.Item", item); startActivityForResult(intent, 1); } }; // 注册选单项目点击监听物件 item_list.setOnItemClickListener(itemListener); ~~~ 你可以注意到在点击一个记事项目以后,传送的资料已经修改为Item物件,所以修改记事元件也要执行对应的调整。开启“net.macdidi.myandroidtutorial”套件下的“ItemActivity.java”,修改“onCreate”方法里面的程式码: ~~~ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_item); processViews(); // 取得Intent物件 Intent intent = getIntent(); // 读取Action名称 String action = intent.getAction(); // 如果是修改记事 if (action.equals("net.macdidi.myandroidtutorial.EDIT_ITEM")) { // 接收记事物件与设定标题、内容 item = (Item) intent.getExtras().getSerializable( "net.macdidi.myandroidtutorial.Item"); title_text.setText(item.getTitle()); content_text.setText(item.getContent()); } // 新增记事 else { item = new Item(); } } ~~~ 修改记事元件在使用者确认内容以后,回到主画面元件处理修改后的工作。开启“net.macdidi.myandroidtutorial”套件下的“MainActivity.java”,修改“onActivityResult”方法里面的程式码: ~~~ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // 如果被启动的Activity元件传回确定的结果 if (resultCode == Activity.RESULT_OK) { // 读取记事物件 Item item = (Item) data.getExtras().getSerializable( "net.macdidi.myandroidtutorial.Item"); // 如果是新增记事 if (requestCode == 0) { ... } // 如果是修改记事 else if (requestCode == 1) { // 读取记事编号 int position = data.getIntExtra("position", -1); if (position != -1) { // 设定修改的记事物件 items.set(position, item); itemAdapter.notifyDataSetChanged(); } } } } ~~~ 完成修改记事功能的调整工作,执行应用程式,点选一笔记事项目,修改内容并确定以后,看看功能是否正确。 ## 9-5 设定记事颜色 像记事这类应用程式,使用一段时间以后,通常会储存很多资料,为了让使用者可以清楚的分类与查询这些记事资料,所以为应用程式加入颜色分类的功能。使用者在新增或修改记事资料的时候,可以依照自己的需求为它设定一个颜色,为设定颜色的功能设计一个Activity元件,元件的名称是“ColorActivity.java”,画面配置档的名称是“activity_color.xml”。在最顶端的“app”目录按鼠标左键,选择“New -> Activity -> Blank Activity”,元件与画面配置档名称依照上面的规划。建立元件以后,开启应用程式设定档“AndroidManifest.xml”,参考下列的内容,加入对话框样式的设定: ~~~ <activity android:name="net.macdidi.myandroidtutorial.ColorActivity" android:theme="@android:style/Theme.Dialog" android:label="@string/title_activity_color" /> ~~~ 选择颜色功能的画面设计比较简单一些,开启在“res/layout”目录下的“activity_color.xml”,把它修改为下面的内容: ~~~ <HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="6sp" android:spacing="3sp" tools:context="net.macdidi.myandroidtutorial.ColorActivity"> <LinearLayout android:id="@+id/color_gallery" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" /> </HorizontalScrollView> ~~~ 开启在“net.macdidi.myandroidtutorial”套件下的“ColorActivity.java”,把它修改为下面的内容: ~~~ package net.macdidi.myandroidtutorial; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.LinearLayout; public class ColorActivity extends Activity { private LinearLayout color_gallery; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_color); processViews(); ColorListener listener = new ColorListener(); for (Colors c : Colors.values()) { Button button = new Button(this); button.setId(c.parseColor()); LinearLayout.LayoutParams layout = new LinearLayout.LayoutParams(128, 128); layout.setMargins(6, 6, 6, 6); button.setLayoutParams(layout); button.setBackgroundColor(c.parseColor()); button.setOnClickListener(listener); color_gallery.addView(button); } } private void processViews() { color_gallery = (LinearLayout) findViewById(R.id.color_gallery); } private class ColorListener implements OnClickListener { @Override public void onClick(View view) { Intent result = getIntent(); result.putExtra("colorId", view.getId()); setResult(Activity.RESULT_OK, result); finish(); } } } ~~~ 完成准备工作以后,就可以回到记事元件加入需要的程式码。开启在“net.macdidi.myandroidtutorial”套件下的“ItemActivity.java”,参考下列的说明加入启动元件的程式码: ~~~ public void clickFunction(View view) { int id = view.getId(); switch (id) { case R.id.take_picture: break; case R.id.record_sound: break; case R.id.set_location: break; case R.id.set_alarm: break; case R.id.select_color: // 启动设定颜色的Activity元件 startActivityForResult( new Intent(this, ColorActivity.class), START_COLOR); break; } } ~~~ 同样在ItemActivity.java,参考下列的程式码,执行选择颜色后的设定工作: ~~~ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK) { switch (requestCode) { case START_CAMERA: break; case START_RECORD: break; case START_LOCATION: break; case START_ALARM: break; // 设定颜色 case START_COLOR: int colorId = data.getIntExtra( "colorId", Colors.LIGHTGREY.parseColor()); item.setColor(getColors(colorId)); break; } } } private Colors getColors(int color) { Colors result = Colors.LIGHTGREY; if (color == Colors.BLUE.parseColor()) { result = Colors.BLUE; } else if (color == Colors.PURPLE.parseColor()) { result = Colors.PURPLE; } else if (color == Colors.GREEN.parseColor()) { result = Colors.GREEN; } else if (color == Colors.ORANGE.parseColor()) { result = Colors.ORANGE; } else if (color == Colors.RED.parseColor()) { result = Colors.RED; } return result; } ~~~ 执行应用程式,在新增或修改记事资料的时候,执行设定颜色的测试。 ## 9-6 选择记事资料与主功能表 这一章最后的工作是完成让使用者勾选记事资料、控制主功能表的显示与删除记事的功能。开启在“net.macdidi.myandroidtutorial”套件下的“MainActivity.java”,找到“processControllers”方法,修改记事项目长按事件的程式码,原来的点击事件也要执行相关的修改。因为在使用者勾选事件项目以后,主功能表就要根据选择的情况调整,所以也增加控制功能表显示的方法processMenu: ~~~ private void processControllers() { // 建立选单项目点击监听物件 AdapterView.OnItemClickListener itemListener = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { // 读取选择的记事物件 Item item = itemAdapter.getItem(position); // 如果已经有勾选的项目 if (selectedCount > 0) { // 处理是否显示已选择项目 processMenu(item); // 重新设定记事项目 itemAdapter.set(position, item); } else { Intent intent = new Intent( "net.macdidi.myandroidtutorial.EDIT_ITEM"); // 设定记事编号与记事物件 intent.putExtra("position", position); intent.putExtra("net.macdidi.myandroidtutorial.Item", item); startActivityForResult(intent, 1); } } }; // 注册选单项目点击监听物件 item_list.setOnItemClickListener(itemListener); // 建立记事项目长按监听物件 AdapterView.OnItemLongClickListener itemLongListener = new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { // 读取选择的记事物件 Item item = itemAdapter.getItem(position); // 处理是否显示已选择项目 processMenu(item); // 重新设定记事项目 itemAdapter.set(position, item); return true; } }; // 注册记事项目长按监听物件 item_list.setOnItemLongClickListener(itemLongListener); ... } // 处理是否显示已选择项目 private void processMenu(Item item) { // 如果需要设定记事项目 if (item != null) { // 设定已勾选的状态 item.setSelected(!item.isSelected()); // 计算已勾选数量 if (item.isSelected()) { selectedCount++; } else { selectedCount--; } } // 根据选择的状况,设定是否显示选单项目 add_item.setVisible(selectedCount == 0); search_item.setVisible(selectedCount == 0); revert_item.setVisible(selectedCount > 0); share_item.setVisible(selectedCount > 0); delete_item.setVisible(selectedCount > 0); } 同样在“MainActivity.java”,找到“onCreateOptionsMenu”方法,为了控制主功能表的显示,参考下列的程式码执行必要的修改: @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater menuInflater = getMenuInflater(); menuInflater.inflate(R.menu.menu_main, menu); // 取得选单项目物件 add_item = menu.findItem(R.id.add_item); search_item = menu.findItem(R.id.search_item); revert_item = menu.findItem(R.id.revert_item); share_item = menu.findItem(R.id.share_item); delete_item = menu.findItem(R.id.delete_item); // 设定选单项目 processMenu(null); return true; } ~~~ 同样在“MainActivity.java”,找到“clickMenuItem”方法,加入取消勾选与删除记事资料的程式码: ~~~ public void clickMenuItem(MenuItem item) { // 使用参数取得使用者选择的选单项目元件编号 int itemId = item.getItemId(); // 判断该执行什么工作,目前还没有加入需要执行的工作 switch (itemId) { case R.id.search_item: break; // 使用者选择新增选单项目 case R.id.add_item: // 使用Action名称建立启动另一个Activity元件需要的Intent物件 Intent intent = new Intent("net.macdidi.myandroidtutorial.ADD_ITEM"); // 呼叫“startActivityForResult”,,第二个参数“0”表示执行新增 startActivityForResult(intent, 0); break; // 取消所有已勾选的项目 case R.id.revert_item: for (int i = 0; i < itemAdapter.getCount(); i++) { Item ri = itemAdapter.getItem(i); if (ri.isSelected()) { ri.setSelected(false); itemAdapter.set(i, ri); } } selectedCount = 0; processMenu(null); break; // 删除 case R.id.delete_item: // 没有选择 if (selectedCount == 0) { break; } // 建立与显示询问是否删除的对话框 AlertDialog.Builder d = new AlertDialog.Builder(this); String message = getString(R.string.delete_item); d.setTitle(R.string.delete) .setMessage(String.format(message, selectedCount)); d.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 删除所有已勾选的项目 int index = itemAdapter.getCount() - 1; while (index > -1) { Item item = itemAdapter.get(index); if (item.isSelected()) { itemAdapter.remove(item); } index--; } // 通知资料改变 itemAdapter.notifyDataSetChanged(); selectedCount = 0; processMenu(null); } }); d.setNegativeButton(android.R.string.no, null); d.show(); break; case R.id.googleplus_item: break; case R.id.facebook_item: break; } } ~~~ 完成这一章所有的工作了,执行应用程式,看看加入的功能是不是都可以正常的运作。
';