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;
}
}
~~~
完成这一章所有的工作了,执行应用程式,看看加入的功能是不是都可以正常的运作。
- 第一堂
- 第一堂(1)西游记里的那只猴子
- 第一堂(2)准备 Android Studio 开发环境
- 第一堂(3)开始设计 Android 应用程式
- 第一堂(4)开发 Android 应用程式的准备工作
- 第二堂
- 第二堂(1)规划与建立应用程式需要的资源
- 第二堂(2)设计应用程式使用者界面
- 第二堂(3)应用程式与使用者的互动
- 第二堂(4)建立与使用 Activity 元件
- 第三堂
- 第三堂(1)为ListView元件建立自定画面
- 第三堂(2)储存与读取应用程式资讯
- 第三堂(3)Android 内建的 SQLite 数据库
- 第四堂
- 第四堂(1)使用照相机与麦克风
- 第四堂(2)设计地图应用程式 - Google Maps Android API v2
- 第四堂(3)读取装置目前的位置 - Google Services Location
- 第五堂
- 第五堂(1)建立广播接收元件 - BroadcastReceiver
- 第五堂(2)系统通知服务 - Notification
- 第五堂(3)设计小工具元件 - AppWidget
- 第六堂
- 第六堂(1)Material Design - Theme与Transition
- 第六堂(2)Material Design - RecylerView
- 第六堂(3)Material Design - Shared Element与自定动画效果