目录:
功能需求–分析
具体实现–动手
源码分析–本源
自定义造轮子–创新
总结
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
4.2 demo 地址
5. 总结
文章是 Android 面向需求开发系列中的一文,更多相关文章请关注。如若有什么问题,也可以通过扫描二维码发消息给我。转载请注明出处,谢谢!
作者:Emily CH
2019年3月7日