Android 实现订餐加减

2019-03-06

目录:

  1. 功能需求–分析
  2. 具体实现–动手
  3. 源码分析–本源
  4. 自定义造轮子–创新
  5. 总结

1. 功能需求–分析


文字描述:餐食预订,获取餐食数据,显示食物名称、类别、价格,默认是➕订餐,+1 后显示➖,并且显示当前的份额,最大份额是max(在响应点击事件时访问一次server,若max == 0 , 设置不可点击刷新列表) ,+到 max 后提示食物只有max 份,不能满足需求;点击➖ ,份额-1,至0后➖不显示,份额也不显示。

具体展示:
功能需求

思考实现方式:
方法一:ListView 显示列表,Item 内部的加减点击事件在Adapter实现。
方法二:在 Adapter 实现 ListItemClickHelp 接口,在 Activity 继承 ListItemClickHelp 接口,重写点击事件。
现在用方法一实现。

2. 具体实现–动手


2.1 核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
private class FoodAdapter extends BaseAdapter {
private List<CanBuyServiceDetail> mDetails;
private LayoutInflater mInflater;
private Context mctx;
private ListItemClickHelp listItemClickHelp;
private int number = 0;


private FoodAdapter(Context ctx, List<CanBuyServiceDetail> mDetails,ListItemClickHelp listItemClickHelp) {
this.mDetails = mDetails;
this.mInflater = LayoutInflater.from(ctx);
this.mctx = ctx;
this.listItemClickHelp = listItemClickHelp;
}

@Override
public int getCount() {
// TODO Auto-generated method stub
return mDetails.size();
}

@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return mDetails.get(position);
}

@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(final int position, View convertView, final ViewGroup parent) {
final FoodAdapter.ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.addservice_add_item1,
null);
holder = new FoodAdapter.ViewHolder();
holder.tv_name = (TextView) convertView
.findViewById(R.id.tv_name);
holder.tv_price = (TextView) convertView
.findViewById(R.id.tv_price);

holder.btn_add_food = (Button) convertView.findViewById(R.id.btn_add_food);
holder.btn_reduce_food = (Button) convertView.findViewById(R.id.btn_reduce_food);

holder.tv_number_food = (TextView) convertView.findViewById(R.id.tv_number_food);

/* 得到各个控件的对象 */
convertView.setTag(holder);
} else {
holder = (FoodAdapter.ViewHolder) convertView.getTag();// 取出ViewHolder对象
}
final CanBuyServiceDetail canBuyServiceDetail = mDetails
.get(position);
holder.tv_name.setText(canBuyServiceDetail.getName());
holder.tv_price.setText("¥" + canBuyServiceDetail.getPrice());

final int add = holder.btn_add_food.getId();
final int reduce = holder.btn_reduce_food.getId();

final Integer[] amountArray;
if (canBuyServiceDetail.getAlreadyBuyAmount() == 0) {
// 如果没有购买
amountArray = new Integer[Integer.parseInt(canBuyServiceDetail
.getMaxamount()) + 1];
for (int i = 0; i <= Integer.parseInt(canBuyServiceDetail
.getMaxamount()); i++) {
amountArray[i] = i;
}

} else {
// 如果已购买
amountArray = new Integer[Integer.parseInt(canBuyServiceDetail
.getMaxamount())
- canBuyServiceDetail.getAlreadyBuyAmount() + 1];
for (int i = canBuyServiceDetail.getAlreadyBuyAmount(), j = 0; i <= Integer
.parseInt(canBuyServiceDetail.getMaxamount()); i++, j++) {
amountArray[j] = i;
}
}

// 设置点击事件
holder.btn_add_food.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

if (canBuyServiceDetail.getSelectedAmount()==0){
number = canBuyServiceDetail.getSelectedAmount();
listItemClickHelp.onClick(view, parent, position, add);
holder.tv_number_food.setVisibility(View.VISIBLE);
holder.btn_reduce_food.setVisibility(View.VISIBLE);
number ++;
holder.tv_number_food.setText(" " + number);
canBuyServiceDetail
.setSelectedAmount(number);
}
else{
if (canBuyServiceDetail.getMaxamount().equals(""+number)){
Toast.makeText(mctx,"尊敬的顾客,您已达到餐食的最大份数!",Toast.LENGTH_SHORT).show();
}else {
number = canBuyServiceDetail.getSelectedAmount() + 1 ;
listItemClickHelp.onClick(view, parent, position, add);
holder.tv_number_food.setVisibility(View.VISIBLE);
holder.btn_reduce_food.setVisibility(View.VISIBLE);
holder.tv_number_food.setText(" " + number);
canBuyServiceDetail
.setSelectedAmount(number);
}
}


}
});
if (canBuyServiceDetail.getSelectedAmount() == 0){
holder.tv_number_food.setVisibility(View.INVISIBLE);
holder.btn_reduce_food.setVisibility(View.INVISIBLE);
}
holder.btn_reduce_food.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (canBuyServiceDetail.getSelectedAmount() == 0){
holder.tv_number_food.setVisibility(View.INVISIBLE);
holder.btn_reduce_food.setVisibility(View.INVISIBLE);
}else {
number = canBuyServiceDetail.getSelectedAmount() -1;
holder.tv_number_food.setText(" " + number);
canBuyServiceDetail
.setSelectedAmount(number);
}


}
});


return convertView;
}

private class ViewHolder {
private TextView tv_name;
private TextView tv_price;
private Button btn_add_food;
private Button btn_reduce_food;
private TextView tv_number_food;
}

2.2 布局实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp"
android:padding="10dp">

<LinearLayout
android:id="@+id/ll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="1">

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:orientation="vertical"
android:layout_weight="0.8">

<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:text="水果餐-晚餐"
android:textSize="20sp" />

<TextView
android:id="@+id/tv_price"
android:layout_width="wrap_content"
android:layout_height="42dp"
android:layout_marginTop="5dp"
android:text="¥65"
android:textSize="20sp" />
</LinearLayout>

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.2">

<Button
android:id="@+id/btn_reduce_food"
android:layout_width="26dp"
android:layout_height="26dp"
android:background="@drawable/less"
android:gravity="center_vertical"
android:visibility="invisible"/>

<TextView
android:id="@+id/tv_number_food"
android:layout_width="40dp"
android:layout_height="match_parent"
android:gravity="center_vertical|center"
android:text="10"
android:textSize="20sp"
android:visibility="invisible"/>

<Button
android:id="@+id/btn_add_food"
android:layout_width="26dp"
android:layout_height="26dp"
android:background="@drawable/add_sevice"
android:gravity="center_vertical" />
</LinearLayout>
</LinearLayout>

<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_below="@+id/ll"
android:background="@color/gray" />

</RelativeLayout>

3. 源码分析–本源


3.1 List 数据和 ListView 是如何对应的?
要求要在第20条餐食目录中插入一条广告–一张美食图片。
Server 返回的数据是不包括广告内容,想要添加广告就得先理解List 数据和 ListView 是如何对应的。
思考解决方案:根据 server 返回的数据,解析后循环,在19和20之间插入一条数据,标识为 flag == ads, 视图中在19 和 20 之间 ListView 的 Adapter 加载数据,根据 position 判断位置,在 position % 20 == 0 时( 注意 List 数据下标是从 0 开始的),切换加载的布局文件。

3.2 具体逻辑
部分示例代码–数据插入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
final List<Row> datas = new ArrayList<Row>();
for (int i = 0; i < rows.size(); i++) {
if (i == 20){
//增加一条ads
Row row1 = new Row();
row1.setNo(-2); //flag
row1.setSeq(rows.get(i).getSeq());
row1.setSeats(rows.get(i).getSeats());
row1.setMxy(rows.get(i).getMxy());
row1.setNullsnos(rows.get(i).getNullsnos());
row1.setStqs(rows.get(i).getStqs());
datas.add(row1);

Row row = rows.get(i);
String sq1 = row.getSeq();
row.setNo(20);
List<Seat> nulllist = row.getNullsnos();
if (nulllist == null || nulllist.size() != sq1.length()) {
datas.add(row);
}

}else {
Row row = rows.get(i);
String sq = row.getSeq();
List<Seat> nulls = row.getNullsnos();
if (nulls == null || nulls.size() != sq.length()) {
datas.add(row);
}
}

}

部分示例显示部分:

1
2
3
4
5
6
7
8
9
10
11
12
if (positon == 20) {
//增加ads
child = inflater.inflate(R.layout.advertisement_item, null);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER;
child.setLayoutParams(lp);
//child.setBackgroundResource(R.drawable.exit_icon);
}
else {
LinearLayout view = (LinearLayout) inflater.inflate(R.layout.row, null);
view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, ViewTool.dip2px(this, 50)));
}

4.自定义造轮子–创新


4.1 轮子设计
FoodItemView
item
4.2 demo 地址

5. 总结


文章是 Android 面向需求开发系列中的一文,更多相关文章请关注。如若有什么问题,也可以通过扫描二维码发消息给我。转载请注明出处,谢谢!

二维码

作者:Emily CH
2019年3月7日