文章目录
- 目标
- 一、项目分析
- 目标
- 项目概述
- 开发环境
- 模块说明
- 二、效果展示
- 目标
- 店铺界面
- 店铺详情界面
- 店铺详情界面
- 确认清空购物车的对话框
- 菜品详情界面
- 订单界面和支付界面
- 三、服务器数据准备
- 目标
- 注意
- 四、店铺功能业务实现
- 目标
- 4.1 搭建标题栏布局
- 4.2 搭建广告栏界面布局
- 4.3 搭建店铺界面布局
- 4.4 搭建店铺列表条目界面布局
- 4.5 封装店铺信息与菜品信息的实体类
- 创建ShopBean类
- 创建FoodBean类
- 4.6 编写广告栏的适配器
- 4.7 编写店铺列表适配器
- 4.8 实现店铺界面显示功能
- 五、店铺详情功能业务实现
- 目标
- 5.1 搭建店铺详情界面布局
- 5.2 搭建菜单列表条目界面布局
- 5.3 搭建购物车列表条目界面布局
- 5.4 搭建确认清空购物车界面布局
- 5.5 编写菜单列表适配器
- 5.6 编写购物车列表适配器
- 5.7 实现菜单显示与购物车功能
- 六、菜品详情功能业务实现
- 目标
- 6.1 搭建菜品详情界面布局
- 6.2 实现菜品界面显示功能
- 七、订单功能业务实现
- 目标
- 7.1 搭建订单界面布局
- 7.2 搭建订单列表条目界面布局
- 7.3 搭建支付界面布局
- 7.4 编写订单列表适配器
- 7.5 实现订单显示与支付功能
- 总结
- 总结
目标
- 了解仿美团外卖项目的分析,能够说出项目的开发环境和模块
- 掌握服务器的搭建方式,能够独立搭建服务器
- 掌握店铺界面的开发过程,能够实现店铺界面的显示效果
- 掌握店铺详情界面与购物车的开发过程,能够独立实现购物车功能
- 掌握菜品详情界面的开发过程,能够实现菜品详情界面的功能
- 掌握订单界面的开发过程,能够实现订单界面的效果
为了巩固第1~11章的Android基础知识,本章要开发一款仿美团外卖的项目,该项目与我们平常看到的美团外卖项目界面比较类似,展示的内容包括店铺、菜单、购物车、订单与支付等信息。为了让大家能够熟练掌握仿美团外卖项目中用到的知识点,接下来我们将从项目分析开始,一步一步带领大家开发仿美团外卖项目的各个功能。
一、项目分析
目标
- 了解仿美团外卖项目的分析,能够说出项目的开发环境和模块
项目概述
仿美团外卖项目是一个网上订餐项目,该项目中包含订餐的店铺、各店铺的菜单、购物车以及订单与付款等模块。在店铺列表中可以看到店铺的名称、月售数量、起送价格与配送费用、配送时间以及店铺特色等信息,点击店铺列表中的任意一个店铺,程序会进入到店铺详情界面,该界面主要用于显示店铺中的菜单信息,同时可以将想要吃的菜添加到购物车中,选完菜之后可以点击该界面中的“去结算”按钮,进入到订单界面,在该界面核对已点的菜单信息,并通过“去支付”按钮进行付款。
开发环境
操作系统:
- Windows系统 8
开发工具:
-
JDK 8
-
Android Studio 3.2 +模拟器(天天模拟器)
-
Tomcat 8.5.59
API版本:
- Android API 28
由于本项目使用的是在实际开发中的网络请求代码来访问Tomcat服务器上的数据,所以开发工具中的模拟器必须为第三方模拟器(如,夜神模拟器、天天模拟器),如果用Android原生模拟器,则会访问不到数据。
模块说明
二、效果展示
目标
- 了解仿美团外卖项目的效果展示,能够说出项目中各个界面的跳转关系
店铺界面
程序启动后,首先会进入店铺界面,该界面展示的是一些由店铺信息组成的列表与一个滑动的广告栏。
店铺详情界面
点击店铺列表中任意一个条目或广告栏中的任意一张图片,程序都会跳转到对应的店铺详情界面,该界面展示的是店铺的公告信息、配送信息、菜单列表信息以及购物车信息。
店铺详情界面
点击菜单列表条目右侧的“加入购物车”按钮可以将菜品添加到购物车中,在界面左下角可以看到购物车中添加的菜品数量。
确认清空购物车的对话框
已选商品列表的右上角有一个“清空”按钮,点击该按钮会弹出一个确认清空购物车的对话框。
菜品详情界面
在店铺详情界面中,点击菜单列表的任意一个条目,程序都会跳转到菜品详情界面,菜品详情界面是一个对话框的样式。
订单界面和支付界面
在店铺详情界面中,点击“去结算”按钮会跳转到订单界面,该界面通过一个列表展示购物车中的菜品信息,点击“去支付”按钮,程序会弹出一个显示支付二维码的对话框。
三、服务器数据准备
目标
- 掌握服务器的搭建方式,能够独立搭建服务器
上述图中,ROOT文件夹在apache-tomcat-7.0.56/webapps/目录下,表示Tomcat的根目录。order文件夹存放的是订餐项目用到的所有数据,其中,order/img文件夹存放的是图片资源,包含店铺图片和菜单图片。shop_list_data.json文件中存放的是店铺列表与店铺详情界面的数据,数据的具体内容可参考教材。
注意
上述文件中的IP地址需要修改为自己电脑上的IP地址,否则访问不到Tomcat服务器中的数据。
如果想要启动Tomcat服务器,可以在apache-tomcat-8.5.59bin包中找到startup.bat文件,双击该文件即可。
四、店铺功能业务实现
目标
- 掌握店铺界面的开发过程,能够实现店铺界面的显示效果
当打开仿美团外卖项目时,程序会直接进入主界面,也就是店铺列表界面。店铺列表界面从上至下分为标题栏、水平滑动广告栏和店铺列表三部分。其中,广告栏与店铺列表的数据是通过网络请求从服务器上获取的JSON数据,接下来本节将针对店铺功能的相关业务进行开发。
4.1 搭建标题栏布局
在仿美团外卖项目中,大部分界面都有一个返回键和一个标题栏。为了便于代码重复利用,可以将返回键和标题栏抽取出来单独放在一个布局文件(title_bar.xml)中。
放置界面控件 reslayouttitle_bar.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="@android:color/transparent">
<TextView
android:id="@+id/tv_back"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="@drawable/go_back_selector" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="@android:color/white"
android:textSize="20sp" />
</RelativeLayout>
创建背景选择器 drawablego_back_selector.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/iv_back_selected" android:state_pressed="true"/>
<item android:drawable="@drawable/iv_back"/>
</selector>
4.2 搭建广告栏界面布局
广告栏界面主要用于展示广告图片信息与跟随图片滑动的小圆点,当前显示的广告图片对应的小圆点颜色为白色,其余小圆点的颜色为灰色。
放置界面控件 reslayoutadbanner.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/adbanner_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v4.view.ViewPager
android:id="@+id/slidingAdvertBanner"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginBottom="1dp"
android:background="@android:color/black"
android:gravity="center" />
<cn.itcast.order.views.ViewPagerIndicator
android:id="@+id/advert_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:padding="10dp" />
</RelativeLayout>
自定义控件ViewPagerIndicator类 orderviewsViewPagerIndicator.java
package cn.itcast.order.views;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.LinearLayout;
import cn.itcast.order.R;
public class ViewPagerIndicator extends LinearLayout {
private int mCount; //小圆点的个数
private int mIndex; //当前小圆点的位置
private Context context;
public ViewPagerIndicator(Context context) {
this(context, null);
}
public ViewPagerIndicator(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
/**
* 设置滑动到当前小圆点时其他圆点的位置
*/
public void setCurrentPostion(int currentIndex) {
mIndex = currentIndex; //当前小圆点
this.removeAllViews(); //移除界面上存在的view
int pex = context.getResources().getDimensionPixelSize(
R.dimen.view_indicator_padding);
for (int i = 0; i < this.mCount; i++) {
//创建一个ImageView控件来放置小圆点
ImageView imageView = new ImageView(context);
if (mIndex == i) { //滑动到的当前界面
//设置小圆点的图片为白色图片
imageView.setImageResource(R.drawable.indicator_on);
}else {
//设置小圆点的图片为灰色图片
imageView.setImageResource(R.drawable.indicator_off);
}
imageView.setPadding(pex, 0, pex, 0);//设置小圆点图片上下左右的padding
this.addView(imageView);//把小圆点添加到自定义ViewPagerIndicator控件上
}
}
/**
* 设置小圆点的数目
*/
public void setCount(int count) {
this.mCount = count;
}
}
设置界面上圆点间的距离 resvaluesdimens.xml
<resources>
<dimen name="view_indicator_padding">5dp</dimen>
</resources>
白色和灰色的小圆点图片 resdrawableindicator_on.xml和indicator_off.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size android:height="6dp" android:width="6dp" />
<solid android:color="@android:color/white" />
</shape>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size android:height="6dp" android:width="6dp" />
<solid android:color="#BCBCBC" />
</shape>
4.3 搭建店铺界面布局
店铺界面是由一个标题栏、一个广告栏以及一个店铺列表组成,标题栏主要用于展示该界面的标题,广告栏主要用于展示店铺中的菜品广告图片,店铺列表主要用于展示各店铺的信息。
放置界面控件 reslayoutactivity_shop.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:orientation="vertical">
<include layout="@layout/title_bar" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f5f5f6"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/adbanner" />
<cn.itcast.order.views.ShopListView
android:id="@+id/slv_list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
android:dividerHeight="8dp"
android:scrollbars="none" />
</LinearLayout>
</ScrollView>
</LinearLayout>
创建自定义控件ShopListView orderviewsShopListView.java
package cn.itcast.order.views;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;
public class ShopListView extends ListView {
public ShopListView(Context context) {
super(context);
}
public ShopListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ShopListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
4.4 搭建店铺列表条目界面布局
由于店铺界面使用自定义控件ShopListView展示店铺列表,所以需要创建一个该列表的条目界面。在条目界面中需要展示店铺名称、月销售商品的数量、起送价格、配送费用、店铺特色以及配送时间。
放置界面控件 reslayoutshop_item.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
android:background="@drawable/item_bg_selector"
android:padding="10dp">
<ImageView
android:id="@+id/iv_shop_pic"
android:layout_width="100dp"
android:layout_height="70dp"
android:layout_alignParentLeft="true" />
<LinearLayout
android:id="@+id/ll_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/iv_shop_pic"
android:orientation="vertical">
<TextView
android:id="@+id/tv_shop_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
android:textSize="14sp" />
<TextView
android:id="@+id/tv_sale_num"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="@color/color_gray"
android:textSize="12sp" />
<TextView
android:id="@+id/tv_cost"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="@color/color_gray"
android:textSize="12sp" />
</LinearLayout>
<TextView
android:id="@+id/tv_feature"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/ll_info"
android:layout_marginLeft="8dp"
android:layout_marginTop="10dp"
android:layout_toRightOf="@id/iv_shop_pic"
android:background=