基于Android的美团外卖

前言

该项目是教材上的一个完整实列,我实现了,代码都是书上的,难以实现的是连接tomcat服务器,网络编程,来完成数据的实现

一、实验题目

网上商城/外卖小助手

二、实验目的

  1. 掌握 Android 中的菜单及导航框架。
  2. 掌握自定义布局。
  3. 掌握 Android 中的数据存储。

三、总体设计

需求分析:仿美团外卖项目是一个网上订餐项目,包含订餐的店铺,各店铺的菜单,购物车及订单与付款等内容,该店铺列表可以看见店铺的名称,月售数量,起送价格与配送费,配送时间以及店铺特色等信息。点击店铺列表中的任意一个店铺,程序会进入店铺详情界面,该界面主要用于显示店铺中的菜单信息,同时可以将需要吃的菜添加到购物车中,选完菜后可以点击该界面中的“去结算”按钮,进入订单界面,在该界面核对已点的菜单信息,并点击“去支付”按钮进行付款。

模块介绍:店铺和订单两大模块

由下图可知,店铺列表界面用于显示各个店铺的信息,店铺详情界面不仅显示店铺的详细信息,还显示店铺中的菜单列表信息与购物车列表信息,订单模块包含确认订单界面与支付界面,确认订单界面用于显示购物车中已添加的商品信息,支付界面用于显示付款的二维码信息。

服务器数据准备:

四、详细设计

(1)店铺功能业务实现

打开项目时,程序会进入店铺列表界面。店铺列表界面从上至下分为标题栏,水平滑动的广告栏和店铺列表三部分。其中公告栏与店铺列表的数据是通过网络请求从服务器上获取的json数据。

1.1搭建标题栏布局:便于代码重复利用返回键和标题栏取出来放在title_bar.xml中。

1.2创建背景选择器:标题栏界面的返回键在按下与弹起会有明显区别,通过背景选择器go_back_selector.xml实现,按钮被按下时显示灰色图片,按钮弹起时显示白色图片。

1.3搭建广告栏界面布局:用于展示广告图片信息与跟随图片滑动的小圆点,当前显示的广告图片对应的小圆点为白色,其余为灰色。

在res/layout文件中,创建一个布局文件adbanner.xml,放置一个ViewPager控件用于显示左右滑动的广告图片,由于广告栏中的小圆点随着图片的滑动而发生变化的,需要自定义一个控件ViewPagerIndicator来显示界面上的小圆点。

 1.4搭建店铺列表界面布局:由一个标题栏,一个广告栏及店铺列表组成,标题栏用于展示该界面的标题,广告栏主要用于展示店铺中的菜品广告图片,店铺列表主要用于展示各店铺的信息,在activity_shop.xml文件中通过<include>标签引入title_bar.xml(标题栏)和adbanner.xml(广告栏),放置一个自定义ShopListView用于显示店铺列表。

<?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: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" />
            <com.example.shop.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>

由于店铺列表界面上的列表滑动时,列表上方的广告栏也需要跟着滑动,所以在广告栏与列表控件的外层放置了一个ScrollView控件,ListView控件包含在ScrollView控件中会导致列表数据不完整,所以自定义一个ShopListView控件。ShopListView控件具体代码如下;

package com.example.shop.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);
    }
}

1.5搭建店铺列表条目界面的布局:由于店铺列表界面使用自定义控件,所以需要重新创建一个该列表的条目界面,用于展示店铺名称,月售数量,起送价格,配送费,店铺特色以及配送时间,布局名称为shop_item.xml

<?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="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="@drawable/feature_bg"
        android:gravity="center"
        android:padding="4dp"
        android:textColor="@color/feature_text_color"
        android:textSize="12sp" />
    <TextView
        android:id="@+id/tv_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_marginTop="30dp"
        android:textColor="@color/color_gray"
        android:textSize="12sp" />
</RelativeLayout>

1.6创建条目界面的背景选择器:店铺列表条目界面的背景的四个角是圆角,并且在条目在按下与弹起时,其背景颜色会有明显区别。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" >
        <shape android:shape="rectangle">
            <corners android:radius="8dp"/>
            <solid android:color="@color/item_bg_color"/>
        </shape>
    </item>
    <item android:state_pressed="false" >
        <shape android:shape="rectangle">
            <corners android:radius="8dp"/>
            <solid android:color="#ffffff" />
        </shape>
    </item>
</selector>

1.7封装店铺信息与菜品信息的实体类:由于店铺信息和菜品信息都包含很多属性,所以创建ShopBean类和FoodBean类封装店铺信息和菜品信息的属性。

package com.example.order.bean;

import java.io.Serializable;
import java.math.BigDecimal;

public class FoodBean implements Serializable {
    private static final long serialVersionUID = 1L; //序列化时保持FoodBean类版本的兼容性
    private int foodId;        	  //菜品Id
    private String foodName;   	  //菜品名称
    private String popularity;    //人气
    private String saleNum;    	  //月售量
    private BigDecimal price;	  //价格
    private int count;         	  //添加到购物车中的数量
    private String foodPic;        //菜品图片
    public int getFoodId() {
        return foodId;
    }
    public void setFoodId(int foodId) {
        this.foodId = foodId;
    }
    public String getFoodName() {
        return foodName;
    }
    public void setFoodName(String foodName) {
        this.foodName = foodName;
    }
    public String getPopularity() {
        return popularity;
    }
    public void setPopularity(String popularity) {
        this.popularity = popularity;
    }
    public String getSaleNum() {
        return saleNum;
    }
    public void setSaleNum(String saleNum) {
        this.saleNum = saleNum;
    }
    public BigDecimal getPrice() {
        return price;
    }
    public void setPrice(BigDecimal price) {
        this.price = price;
    }
    public String getFoodPic() {
        return foodPic;
    }
    public void setFoodPic(String foodPic) {
        this.foodPic = foodPic;
    }
    public int getCount() {
        return count;
    }
    public void setCount(int count) {
        this.count = count;
    }
}
package com.example.order.bean;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;

public class ShopBean implements Serializable {
    private static final long serialVersionUID = 1L; //序列化时保持ShopBean类版本的兼容性
    private int id;                                //店铺Id
    private String shopName;                    //店铺名称
    private int saleNum;                        //月售数量
    private BigDecimal offerPrice;            //起送价格
    private BigDecimal distributionCost;    //配送费用
    private String feature;                    //店铺特色
    private String time;                        //配送时间
    private String banner;                        //广告栏图片
    private String shopPic;                    //店铺图片
    private String shopNotice;                //店铺公告
    private List<FoodBean> foodList;        //菜单列表

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getShopName() {
        return shopName;
    }

    public void setShopName(String shopName) {
        this.shopName = shopName;
    }

    public int getSaleNum() {
        return saleNum;
    }

    public void setSaleNum(int saleNum) {
        this.saleNum = saleNum;
    }

    public BigDecimal getOfferPrice() {
        return offerPrice;
    }

    public void setOfferPrice(BigDecimal offerPrice) {
        this.offerPrice = offerPrice;
    }

    public BigDecimal getDistributionCost() {
        return distributionCost;
    }

    public void setDistributionCost(BigDecimal distributionCost) {
        this.distributionCost = distributionCost;
    }

    public String getFeature() {
        return feature;
    }

    public void setFeature(String feature) {
        this.feature = feature;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }

    public String getShopPic() {
        return shopPic;
    }

    public String getBanner() {
        return banner;
    }

    public void setBanner(String banner) {
        this.banner = banner;
    }

    public void setShopPic(String shopPic) {
        this.shopPic = shopPic;
    }

    public String getShopNotice() {
        return shopNotice;
    }

    public void setShopNotice(String shopNotice) {
        this.shopNotice = shopNotice;
    }

    public List<FoodBean> getFoodList() {
        return foodList;
    }

    public void setFoodList(List<FoodBean> foodList) {
        this.foodList = foodList;
    }
}

1.8编写广告栏的数据适配器AdBannerAdapter:为了给ViewPager控件填充数据,获取到的数据传递到AdBannerFragment中,AdBannerAdapter具体代码如下:

package com.example.shop.adapter;

import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Lifecycle;
import androidx.viewpager2.adapter.FragmentStateAdapter;

import com.example.order.bean.ShopBean;
import com.example.shop.fragment.AdBannerFragment;

import java.util.List;

public class AdBannerAdapter extends FragmentStateAdapter {

    //存放店铺的列表(也是广告的Fragment列表,因为一个店铺就一个广告Fragment)
    private List<ShopBean> shopBeanList; //适配器的数据对象

    //构造函数
    public AdBannerAdapter(FragmentManager fragmentManager,Lifecycle lifecycle) {
        super(fragmentManager, lifecycle);
    }


    //设置广告数据并更新界面,也就是给类变量赋值
    public void setData(List<ShopBean> sbl) {
        //将网络上访问到的 ShopBean 的数量(广告数量)赋值给适配器
        this.shopBeanList = sbl;
        //更新数据源
        //适配器的内容改变时需要强制刷新每个Item的内容,可以实现动态的刷新列表的功能
        //notifyDataSetChanged();
    }

    //该方法返回当前的 Fragment,交给相关联的 Activity 中的 ViewPager2
    //该方法将Fragment与 ViewPager2 完美结合
    @NonNull
    @Override
    public Fragment createFragment(int position) {
        Bundle args = new Bundle();//创建bundle,传递数据给 广告 AdBannerFragment
        if (shopBeanList.size() > 0)
            args.putSerializable("ad", shopBeanList.get(position % shopBeanList.size()));
        return AdBannerFragment.newInstance(args);
    }

    //获取广告总数
    @Override
    public int getItemCount() {
        //return shopBeanList.size();
        return shopBeanList == null ? 0 : shopBeanList.size();
    }
}

 1.9将数据设置到广告栏界面上:广告栏的滑动图片用Fragment来显示,需要导入glide-3.7.0jar包

package com.example.shop.fragment;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import androidx.fragment.app.Fragment;

import com.bumptech.glide.Glide;
import com.example.meituan.R;
import com.example.order.bean.ShopBean;


public class AdBannerFragment extends Fragment {

    private ShopBean shopBean;   //广告
    private ImageView imageView;  //图片
    //客户端构造 该广告 Fragment所用
    public static AdBannerFragment newInstance(Bundle args) {
        AdBannerFragment af = new AdBannerFragment();
        af.setArguments(args);
        return af;
    }
    //在这里创建碎片
    //生成广告对象时,获取 bundle 数据,并转换为一个 shopBean
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle arg = getArguments();
        shopBean = (ShopBean) arg.getSerializable("ad"); //获取一个店铺对象
    }

    //在当前Activity中添加一个Fragment时,被添加的Fragment都会调用onResume
    @Override
    public void onResume() {
        super.onResume();
        if (shopBean != null) {
            //调用Glide框架加载图片
            Glide
                    .with(getActivity())
                    .load(shopBean.getBanner())
                    .error(R.mipmap.ic_launcher)
                    .into(imageView);
        }
    }
    //该方法创建一个视图,返回 ImageView 控件对象的视图
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        imageView = new ImageView(getActivity()); //创建一个 ImageView 控件的对象
        //定义一个视图容器对象,用来存放图片对象,容器的宽度和高度都是 MATCH_PARENT
        ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT);
        imageView.setLayoutParams(lp);      //设置ImageView控件的宽高参数
        imageView.setScaleType(ImageView.ScaleType.FIT_XY); //把图片填满整个控件
//        imageView.setOnClickListener(new View.OnClickListener() {
//            @Override
//            public void onClick(View v) {
//                //跳转到店铺详情界面
//                if (sb == null) return;
//                Intent intent = new Intent(getActivity(), ShopDetailActivity.class);
//                intent.putExtra("shop", shopBean);
//                getActivity().startActivity(intent);
//            }
//        });
        return imageView;
    }
}

 1.10编写店铺列表的数据适配器:由于店铺列表是用ShopListView控件展示的,所以需要创建一个数据适配器ShopAdapter对ShopListView控件进行数据适配。

package com.example.shop.adapter;

import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.example.meituan.R;
import com.example.meituan.ShopDetailActivity;
import com.example.order.bean.ShopBean;

import java.util.List;

public class ShopAdapter  extends BaseAdapter {
    private Context mContext;
    private List<ShopBean> sbl;
    public ShopAdapter(Context context) {
        this.mContext = context;
    }
    /**
     * 获取数据并更新界面
     */
    public void setData(List<ShopBean> sbl) {
        this.sbl = sbl;
        notifyDataSetChanged();
    }
    /**
     * 获取条目的总数
     */
    @Override
    public int getCount() {
        return sbl == null ? 0 : sbl.size();
    }
    /**
     * 根据position得到对应条目的对象
     */
    @Override
    public ShopBean getItem(int position) {
        return sbl == null ? null : sbl.get(position);
    }
    /**
     * 根据position得到对应条目的Id
     */
    @Override
    public long getItemId(int position) {
        return position;
    }
    /**
     * 得到相应position对应的条目视图,position是当前条目的位置,
     * convertView参数是滚出屏幕的条目视图
     */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final ViewHolder vh;
        //复用convertView
        if (convertView == null) {
            vh = new ViewHolder();
            convertView= LayoutInflater.from(mContext).inflate(R.layout.shop_item,null);
            vh.tv_shop_name = convertView.findViewById(R.id.tv_shop_name);
            vh.tv_sale_num = convertView.findViewById(R.id.tv_sale_num);
            vh.tv_cost =  convertView.findViewById(R.id.tv_cost);
            vh.tv_feature = convertView.findViewById(R.id.tv_feature);
            vh.tv_time = convertView.findViewById(R.id.tv_time);
            vh.iv_shop_pic = convertView.findViewById(R.id.iv_shop_pic);
            convertView.setTag(vh);
        } else {
            vh = (ViewHolder) convertView.getTag();
        }
        //获取position对应条目的数据对象
        final ShopBean bean = getItem(position);
        if (bean != null) {
            vh.tv_shop_name.setText(bean.getShopName());
            vh.tv_sale_num.setText("月售" + bean.getSaleNum());
            vh.tv_cost.setText("起送¥" + bean.getOfferPrice() + " | 配送¥" +
                    bean.getDistributionCost());
            vh.tv_time.setText(bean.getTime());
            vh.tv_feature.setText(bean.getFeature());
            Glide.with(mContext)
                    .load(bean.getShopPic())
                    .error(R.mipmap.ic_launcher)
                    .into(vh.iv_shop_pic);
        }
        //每个条目的点击事件
        convertView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //跳转到店铺详情界面
                if (bean == null) return;
                Intent intent = new Intent(mContext, ShopDetailActivity.class);
                //把店铺的详细信息传递到店铺详情界面
                intent.putExtra("shop", bean);
                mContext.startActivity(intent);
            }
        });
        return convertView;
    }
    class ViewHolder {
        public TextView tv_shop_name, tv_sale_num, tv_cost, tv_feature, tv_time;
        public ImageView iv_shop_pic;
    }
}

1.11实现店铺列表界面显示功能:使用OkHttpClient类向服务器请求数据,获取到的数据通过Gson库解析获取到的JSON数据显示到界面上。

1.11.1添加OkHttp库

1.11.2添加Gson库

1.11.3创建Constant类:存放各界面在服务器上请求数据时使用的接口地址

内网接口IP地址要换成自己电脑的

package com.example.shop.utils;

public class Constant {
    public static final String WEB_SITE = "http://10.0.2.2:8080/order";//内网接口
    public static final String REQUEST_SHOP_URL = "/shop_list_data.json";  //店铺列表接口
}

 1.11.4创建JsonParse类:用于解析获取到的JSON数据,具体代码如下

package com.example.shop.utils;

import com.example.order.bean.ShopBean;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
import java.util.List;

public class JsonParse {
    private static JsonParse instance;
    private JsonParse() {
    }
    public static JsonParse getInstance() {
        if (instance == null) {
            instance = new JsonParse();
        }
        return instance;
    }
    public List<ShopBean> getShopList(String json) {
        Gson gson = new Gson(); // 使用gson库解析JSON数据
        // 创建一个TypeToken的匿名子类对象,并调用对象的getType()方法
        Type listType = new TypeToken<List<ShopBean>>() {
        }.getType();
        // 把获取到的信息集合存到shopList中
        List<ShopBean> shopList = gson.fromJson(json, listType);
        return shopList;
    }
}

 1.11.5将数据显示到店铺列表界面上,需要创建init()方法用于初始化界面控件与获取界面的数据并将数据显示到界面上。ShopActivity.java

package com.example.meituan;

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;

import com.example.shop.adapter.AdBannerAdapter;
import com.example.order.bean.ShopBean;
import com.example.shop.adapter.ShopAdapter;
import com.example.shop.utils.Constant;
import com.example.shop.utils.JsonParse;
import com.example.shop.views.ShopListView;
import com.example.shop.views.ViewPagerIndicator;

import java.io.IOException;
import java.util.List;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class ShopActivity extends AppCompatActivity {

    private TextView tv_back,tv_title;        //返回键与标题控件
    //    private ShopListView slv_list;             //列表控件
//    private ShopAdapter adapter;               //列表的适配器
    private RelativeLayout rl_title_bar;
    private ViewPager2 viewPager;         //广告
    private ViewPagerIndicator viewPagerIndicator;   //小圆点
    private View adBannerLay;          //广告条容器
    private AdBannerAdapter adBannerAdapter;      //广告ViewPager2适配器
    public static final int MSG_AD_SLID = 1;  //广告自动滑动
    public static final int MSG_SHOP_OK = 2;  //获取数据
    private MHandler mHandler;
    private ShopListView slv_list;             //列表控件
    private ShopAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_shop);
        mHandler=new MHandler();
        initData(); //访问网络,获取数据并将数据显示在界面上
        init(); //初始化界面控件
    }
    /**
     * 初始化界面控件
     */
    private void init(){
        slv_list= findViewById(R.id.slv_list);
        adapter = new ShopAdapter(this);
        slv_list.setAdapter(adapter);
        tv_back = findViewById(R.id.tv_back);
        tv_title = findViewById(R.id.tv_title);
        tv_title.setText("店铺");
        rl_title_bar = findViewById(R.id.title_bar);
        rl_title_bar.setBackgroundColor(getResources().getColor(R.color.blue));
        tv_back.setVisibility(View.GONE);
//        slv_list= findViewById(R.id.slv_list);
//        adapter=new ShopAdapter(this);
//        slv_list.setAdapter(adapter);
        adBannerLay = findViewById(R.id.adbanner_layout);
        viewPager =  findViewById(R.id.slidingAdvertBanner);
        viewPagerIndicator = findViewById(R.id.advert_indicator);
        viewPager.setLongClickable(false);
        adBannerAdapter = new AdBannerAdapter(getSupportFragmentManager(),
                getLifecycle());
        viewPager.setAdapter(adBannerAdapter);
        viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
            //ViewPager2滑动到新的页时,需要完成的功能
            @Override
            public void onPageSelected(int position) {
                //super.onPageSelected(position);
                if (adBannerAdapter.getItemCount() > 0) {
                    //设置当前小圆点
                    viewPagerIndicator.setCurrentPostion(
                            position % adBannerAdapter.getItemCount());
                }
            }
        });
        resetSize();//自定义函数:计算控件大小
        new AdAutoSlidThread().start();//开启一个子线程
    }
    //定义一个无限循环的子线程,子线程每5秒钟发送一个消息个主线程
    //主线程每5秒钟接收到该消息,然后显示一下个广告(Fragment)
    class AdAutoSlidThread extends Thread {
        @Override
        public void run() {
            super.run();
            while (true) {
                try {
                    sleep(5000); //睡眠5秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (mHandler != null)
                    mHandler.sendEmptyMessage(MSG_AD_SLID);
            }
        }
    }

    //访问网络,获取数据
    private void initData() {
        OkHttpClient okHttpClient = new OkHttpClient();
        Request request = new Request.Builder().url(Constant.WEB_SITE +
                Constant.REQUEST_SHOP_URL).build();
        Call call = okHttpClient.newCall(request);
        // 开启异步线程访问网络
        call.enqueue(new Callback() {
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String res = response.body().string(); //获取店铺数据
                Message msg = new Message();
                msg.what = MSG_SHOP_OK;
                msg.obj = res;
                mHandler.sendMessage(msg);
            }
            @Override
            public void onFailure(Call call, IOException e) {
            }
        });
    }
    /**
     * 事件捕获
     */
    class MHandler extends Handler {
        //处理子线程发送过来的消息
        @Override
        public void dispatchMessage(Message msg) {
            super.dispatchMessage(msg);
            switch (msg.what) {
                case MSG_SHOP_OK://接收访问网络子线程发送过来的消息
                    if (msg.obj != null) {
                        String vlResult = (String) msg.obj;
                        Log.i("tag",vlResult);
                        //解析获取的JSON数据
                        List<ShopBean> shopBeanList = JsonParse.getInstance().getShopList(vlResult);
                        Log.i("tag",shopBeanList.toString());
                        adapter.setData(shopBeanList);
                        if (shopBeanList != null) {
                            if (shopBeanList.size() > 0) {
                                //设置广告栏数据到适配器上
                                //将网络上访问到的 ShopBean 的列表数据(广告列表数据)赋值给适配器
                                adBannerAdapter.setData(shopBeanList);
                                //更新数据源
                                //适配器的内容改变时需要强制刷新每个Item的内容,
                                //可以实现动态的刷新列表的功能
                                adBannerAdapter.notifyDataSetChanged();
                                //设置小圆点数目
                                viewPagerIndicator.setCount(shopBeanList.size());
                                //设置当前小圆点的位置为0
                                viewPagerIndicator.setCurrentPostion(0);
                            }
                        }
                    }
                    break;
                case MSG_AD_SLID://接收AdAutoSlidThread子线程发送过来的消息(每5秒钟发送一个消息)
                    if (adBannerAdapter.getItemCount() > 0) {//获取广告适配器的数据大小
                        //判断广告是否滑动到了最后一个
                        if(viewPager.getCurrentItem() +1 >= adBannerAdapter.getItemCount()){
                            //广告从第一个开始重新显示
                            viewPager.setCurrentItem(0);
                        }else{
                            //设置滑动到下一张广告图片
                            viewPager.setCurrentItem(viewPager.getCurrentItem() + 1);
                        }
                    }
                    break;
            }

        }


    }
    /**
     * 计算控件大小
     */
    private void resetSize() {
        int sw = getScreenWidth();//获取屏幕宽度
        int adLheight = sw /3; //广告条高度
        ViewGroup.LayoutParams adlp = adBannerLay.getLayoutParams();
        adlp.width = sw;
        adlp.height = adLheight;
        adBannerLay.setLayoutParams(adlp);
    }
    /**
     * 获取屏幕宽度
     */
    public int getScreenWidth() {
        WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.widthPixels;
    }

    protected long exitTime;//记录第一次点击时的时间
    //点击2次返回键的时间间隔小于2秒钟,退出APP
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK
                && event.getAction() == KeyEvent.ACTION_DOWN) {
            if ((System.currentTimeMillis() - exitTime) > 2000) {
                Toast.makeText(ShopActivity.this, "再按一次退出仿美团外卖应用",
                        Toast.LENGTH_SHORT).show();
                exitTime = System.currentTimeMillis();
            } else {
                ShopActivity.this.finish();
                System.exit(0);
            }
            return true;
        }
        return super.onKeyDown(keyCode, event);


    }
}

 

2、店铺详情功能业务实现:

当店铺列表界面的条目被点击后,程序会跳转到店铺详情界面,该界面主要分为三部分,第一部分部分用于展示店铺的信息,如店铺名称,店铺图片,店铺公告及配送时间,第二部分用于展示店铺中的菜单列表,第三部分用于展示购物车

2.1搭建店铺详情界面布局

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:id="@+id/ll_intro"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/shop_bg"
        android:orientation="vertical">
        <include layout="@layout/title_bar" />
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="65dp"
            android:background="@android:color/white"
            android:orientation="vertical"
            android:paddingTop="60dp">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:text="菜单"
                android:textColor="@android:color/black"
                android:textSize="16sp" />
            <View
                android:layout_width="match_parent"
                android:layout_height="1dp"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:background="@color/light_gray" />
        </LinearLayout>
    </LinearLayout>
    <include layout="@layout/shop_detail_head" />
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="220dp">
        <ListView
            android:id="@+id/lv_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="50dp" />
        <include layout="@layout/car_list" />
        <include layout="@layout/shop_car" />
    </RelativeLayout>
</FrameLayout>

2.2创建shop_detail_head.xml显示店铺名称,配送时间以及店铺公告,配送时间的图标和店铺的图片

<?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="wrap_content"
    android:paddingTop="20dp"
    android:background="@android:color/transparent">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginTop="50dp"
        android:background="@drawable/corner_bg"
        android:orientation="vertical"
        android:padding="10dp">
        <TextView
            android:id="@+id/tv_shop_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textColor="@android:color/black"
            android:textSize="18sp" />
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="4dp"
            android:orientation="horizontal">
            <ImageView
                android:layout_width="15dp"
                android:layout_height="15dp"
                android:layout_alignParentLeft="true"
                android:scaleType="fitXY"
                android:src="@drawable/time_icon" />
            <TextView
                android:id="@+id/tv_time"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="4dp"
                android:textColor="@color/color_gray"
                android:textSize="12sp" />
        </LinearLayout>
        <TextView
            android:id="@+id/tv_notice"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="4dp"
            android:textColor="@color/color_gray"
            android:textSize="12sp" />
    </LinearLayout>
    <ImageView
        android:id="@+id/iv_shop_pic"
        android:layout_width="85dp"
        android:layout_height="60dp"
        android:layout_alignParentRight="true"
        android:layout_margin="20dp"
        android:scaleType="fitXY" />
</RelativeLayout>

2.3创建shop_car.xml用于显示“未选购商品”,“去结算”,“不够起送价格”的文本信息与配送费信息。

<?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="match_parent">
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="65dp"
        android:layout_alignParentBottom="true">
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_marginTop="15dp"
            android:background="@color/car_gray_color"
            android:paddingLeft="60dp">
            <TextView
                android:id="@+id/tv_money"
                android:layout_width="wrap_content"
                android:layout_height="25dp"
                android:layout_marginLeft="4dp"
                android:layout_marginTop="4dp"
                android:gravity="center"
                android:text="未选购商品"
                android:textColor="@color/light_gray"
                android:textSize="16sp" />
            <TextView
                android:id="@+id/tv_distribution_cost"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@id/tv_money"
                android:layout_marginLeft="4dp"
                android:textColor="@android:color/white"
                android:textSize="12sp"
                android:textStyle="bold"
                android:visibility="gone" />
            <TextView
                android:id="@+id/tv_settle_accounts"
                android:layout_width="100dp"
                android:layout_height="match_parent"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:background="@color/account_color"
                android:gravity="center"
                android:text="去结算"
                android:textColor="@android:color/white"
                android:textSize="16sp"
                android:visibility="gone" />
            <TextView
                android:id="@+id/tv_not_enough"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_alignParentRight="true"
                android:background="@color/account_gray_color"
                android:gravity="center"
                android:padding="8dp"
                android:textColor="@color/light_gray"
                android:textSize="16sp" />
        </RelativeLayout>
        <include layout="@layout/car" />
    </FrameLayout>
</RelativeLayout>

2.4创建badge_bg.xml

购物车右上角有一个显示商品数量的控件

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <gradient
        android:endColor="#fe451d"
        android:startColor="#fe957f"
        android:type="linear" />
    <corners android:radius="180dp" />
</shape>

 2.5搭建菜单列表条目界面布局:用ListView控件来展示菜单信息,展示菜品的名称,人气,月售数量与好评度,价格及“加入购物车”按钮。

<?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="wrap_content"
    android:layout_marginLeft="8dp"
    android:layout_marginTop="8dp"
    android:layout_marginRight="8dp"
    android:background="@drawable/menu_item_bg_selector"
    android:padding="10dp">
    <ImageView
        android:id="@+id/iv_food_pic"
        android:layout_width="80dp"
        android:layout_height="60dp"
        android:layout_alignParentLeft="true" />
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_toRightOf="@id/iv_food_pic"
        android:orientation="vertical">
        <TextView
            android:id="@+id/tv_food_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textColor="@android:color/black"
            android:textSize="14sp" />
        <TextView
            android:id="@+id/tv_popularity"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="4dp"
            android:background="@drawable/feature_bg"
            android:padding="4dp"
            android:textColor="@color/feature_text_color"
            android:textSize="12sp" />
        <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_price"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="4dp"
            android:textColor="@color/price_red"
            android:textSize="16sp" />
    </LinearLayout>
    <Button
        android:id="@+id/btn_add_car"
        android:layout_width="65dp"
        android:layout_height="25dp"
        android:layout_alignParentRight="true"
        android:layout_marginTop="30dp"
        android:background="@drawable/add_car_selector"
        android:gravity="center"
        android:text="加入购物车"
        android:textColor="@android:color/white"
        android:textSize="10sp" />
</RelativeLayout>

 2.6搭建购物车列表条目界面布局car_item.xml

<?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="60dp"
    android:gravity="center_vertical"
    android:orientation="vertical"
    android:padding="8dp">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_vertical">
        <TextView
            android:id="@+id/tv_food_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="8dp"
            android:maxLines="1"
            android:textColor="#757575"
            android:textSize="16sp" />
        <ImageView
            android:id="@+id/iv_add"
            android:layout_width="25dp"
            android:layout_height="25dp"
            android:layout_alignParentRight="true"
            android:src="@drawable/car_add" />
        <TextView
            android:id="@+id/tv_food_count"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="10dp"
            android:layout_marginTop="4dp"
            android:layout_toLeftOf="@id/iv_add"
            android:textColor="@android:color/black" />
        <ImageView
            android:id="@+id/iv_minus"
            android:layout_width="25dp"
            android:layout_height="25dp"
            android:layout_marginRight="10dp"
            android:layout_toLeftOf="@id/tv_food_count"
            android:src="@drawable/car_minus" />
        <TextView
            android:id="@+id/tv_food_price"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="10dp"
            android:layout_marginTop="4dp"
            android:layout_toLeftOf="@id/iv_minus"
            android:textColor="@color/price_red"
            android:textSize="14sp"
            android:textStyle="bold" />
    </RelativeLayout>
</LinearLayout>

 2.7创建slide_bottom_to_top.xml文件用于实现弹出的动画效果

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator">
    <translate
        android:duration="500"
        android:fromYDelta="100.0%"
        android:toYDelta="10.000002%" />
    <alpha
        android:duration="500"
        android:fromAlpha="0.0"
        android:toAlpha="1.0" /></set>

2.8搭建确认清空购物车界面布局

2.9编写菜单列表的数据适配器

2.9.1创建菜单列表的数据适配器MenuAdapter,MenuAdapter具体代码如下:

package com.example.shop.adapter;

import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.example.order.bean.FoodBean;
import com.example.meituan.FoodActivity;
import com.example.meituan.R;
import com.example.order.bean.FoodBean;

import java.util.List;

public class MenuAdapter extends BaseAdapter {
    private Context mContext;
    private List<FoodBean> fbl;                   //菜单列表数据
    private OnSelectListener onSelectListener; //加入购物车按钮的监听事件
    public MenuAdapter(Context context, OnSelectListener onSelectListener) {
        this.mContext = context;
        this.onSelectListener=onSelectListener;
    }
    /**
     * 设置数据更新界面
     */
    public void setData(List<FoodBean> fbl) {
        this.fbl = fbl;
        notifyDataSetChanged();
    }
    /**
     * 获取条目的总数
     */
    @Override
    public int getCount() {
        return fbl == null ? 0 : fbl.size();
    }
    /**
     * 根据position得到对应条目的对象
     */
    @Override
    public FoodBean getItem(int position) {
        return fbl == null ? null : fbl.get(position);
    }
    /**
     * 根据position得到对应条目的Id
     */
    @Override
    public long getItemId(int position) {
        return position;
    }
    /**
     * 得到相应position对应的条目视图,position是当前条目的位置,
     * convertView参数是滚出屏幕的条目视图
     */
    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        final ViewHolder vh;
        //复用convertView
        if (convertView == null) {
            vh = new ViewHolder();
            convertView = LayoutInflater.from(mContext).inflate(R.layout.menu_item,
                    null);
            vh.tv_food_name = convertView.findViewById(R.id.tv_food_name);
            vh.tv_popularity =  convertView.findViewById(R.id.tv_popularity);
            vh.tv_sale_num = convertView.findViewById(R.id.tv_sale_num);
            vh.tv_price =  convertView.findViewById(R.id.tv_price);
            vh.btn_add_car = convertView.findViewById(R.id.btn_add_car);
            vh.iv_food_pic =  convertView.findViewById(R.id.iv_food_pic);
            convertView.setTag(vh);
        } else {
            vh = (ViewHolder) convertView.getTag();
        }
        //获取position对应条目的数据对象
        final FoodBean bean = getItem(position);
        if (bean != null) {
            vh.tv_food_name.setText(bean.getFoodName());
            vh.tv_popularity.setText(bean.getPopularity ());
            vh.tv_sale_num.setText("月售" + bean.getSaleNum());
            vh.tv_price.setText("¥"+bean.getPrice());
            Glide.with(mContext)
                    .load(bean.getFoodPic())
                    .error(R.mipmap.ic_launcher)
                    .into(vh.iv_food_pic);
        }
        //每个条目的点击事件
        convertView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //跳转到菜品详情界面
                if (bean == null)return;
                Intent intent = new Intent(mContext, FoodActivity.class);
                //把菜品的详细信息传递到菜品详情界面
                intent.putExtra("food", bean);
                mContext.startActivity(intent);
            }
        });
        vh.btn_add_car.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) { //加入购物车按钮的点击事件
                onSelectListener.onSelectAddCar(position);
            }
        });
        return convertView;
    }
    class ViewHolder {
        public TextView tv_food_name, tv_popularity, tv_sale_num, tv_price;
        public Button btn_add_car;
        public ImageView iv_food_pic;
    }
    public interface OnSelectListener {
        void onSelectAddCar (int position); //处理加入购物车按钮的方法
    }
}

3.菜品详情功能业务实现

3.1搭建菜品详情界面布局,放置三个TextView用于展示菜品名称,月售数量与好评度及价格,放置一个ImageView控件用于显示菜品的图片。

3.2实现菜品详情界面显示功能

package com.example.meituan;

import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import com.bumptech.glide.Glide;
import com.example.order.bean.FoodBean;

public class FoodActivity extends AppCompatActivity {

    private FoodBean bean;
    private TextView tv_food_name, tv_sale_num, tv_price;
    private ImageView iv_food_pic;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_food);
        //从店铺详情界面传递过来的菜的数据
        bean = (FoodBean) getIntent().getSerializableExtra("food");
        initView();
        setData();
    }
    /**
     * 初始化界面控件
     */
    private void initView() {
        tv_food_name = findViewById(R.id.tv_food_name);
        tv_sale_num = findViewById(R.id.tv_sale_num);
        tv_price = findViewById(R.id.tv_price);
        iv_food_pic = findViewById(R.id.iv_food_pic);
    }
    /**
     * 设置界面数据
     */
    private void setData() {
        if (bean == null) return;
        tv_food_name.setText(bean.getFoodName());
        tv_sale_num.setText("月售" + bean.getSaleNum());
        tv_price.setText("¥" + bean.getPrice());
        Glide.with(this)
                .load(bean.getFoodPic())
                .error(R.mipmap.ic_launcher)
                .into(iv_food_pic);
    }
}

4、订单功能业务实现

4.1搭建订单界面布局,用于展示收获地址,订单列表,小计,配送费,订单总价及“去支付”按钮。具体代码如下:

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout

    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/order_head"/>

    <include layout="@layout/payment" />

</FrameLayout>

其中order_head.xml放置五个TextView用于显示“收货地址:”“小计”“配送费”放置一个EditText控件用于输入收货地址。Payment.xml放置三个TextView控件分别用于显示“订单总价”以及“去支付”按钮。

4.2搭建订单列表条目界面布局:用于展示菜品的名称数量及总价信息,布局代码如下:

<?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="wrap_content"
    android:layout_marginLeft="8dp"
    android:layout_marginTop="8dp"
    android:layout_marginRight="8dp"
    android:background="@drawable/menu_item_bg_selector"
    android:padding="10dp">
    <ImageView
        android:id="@+id/iv_food_pic"
        android:layout_width="80dp"
        android:layout_height="60dp"
        android:layout_alignParentLeft="true" />
    <LinearLayout
        android:id="@+id/ll_info"
        android:layout_width="wrap_content"
        android:layout_height="60dp"
        android:layout_marginLeft="10dp"
        android:layout_toRightOf="@id/iv_food_pic"
        android:gravity="center"
        android:orientation="vertical">
        <TextView
            android:id="@+id/tv_food_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textColor="@android:color/black"
            android:textSize="14sp" />
        <TextView
            android:id="@+id/tv_count"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:textColor="@android:color/black"
            android:textSize="12sp" />
    </LinearLayout>
    <TextView
        android:id="@+id/tv_money"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="10dp"
        android:textColor="@android:color/black"
        android:textSize="12sp" />
</RelativeLayout>

4.3搭建支付界面布局:该界面为一个对话框的样式,显示一个文本信息和二维码图片该界面布局如下: 

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp"
        android:layout_marginLeft="6dp"
        android:text="请扫描下方二维码进行支付"
        android:textColor="@android:color/white"
        android:textSize="16sp" />
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:scaleType="fitXY"
        android:src="@drawable/qr_code" />
</LinearLayout>

 4.4编写订单列表的数据适配器:创建一个数据适配器OrderAdapter对ListView控件进行数据适配

package com.example.shop.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.example.meituan.R;
import com.example.order.bean.FoodBean;

import java.math.BigDecimal;
import java.util.List;

public class OrderAdapter  extends BaseAdapter {
    private Context mContext;
    private List<FoodBean> fbl;
    public OrderAdapter(Context context) {
        this.mContext = context;
    }
    /**
     * 设置数据更新界面
     */
    public void setData(List<FoodBean> fbl) {
        this.fbl = fbl;
        notifyDataSetChanged();
    }
    /**
     * 获取条目的总数
     */
    @Override
    public int getCount() {
        return fbl == null ? 0 : fbl.size();
    }
    /**
     * 根据position得到对应条目的对象
     */
    @Override
    public FoodBean getItem(int position) {
        return fbl == null ? null : fbl.get(position);
    }
    /**
     * 根据position得到对应条目的Id
     */
    @Override
    public long getItemId(int position) {
        return position;
    }
    /**
     * 得到相应position对应的条目视图,position是当前条目的位置,
     * convertView参数是滚出屏幕的条目的视图
     */
    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        final ViewHolder vh;
        //复用convertView
        if (convertView == null) {
            vh = new ViewHolder();
            convertView = LayoutInflater.from(mContext).inflate(R.layout.order_item,
                    null);
            vh.tv_food_name = convertView.findViewById(R.id.tv_food_name);
            vh.tv_count = convertView.findViewById(R.id.tv_count);
            vh.tv_money = convertView.findViewById(R.id.tv_money);
            vh.iv_food_pic = convertView.findViewById(R.id.iv_food_pic);
            convertView.setTag(vh);
        } else {
            vh = (ViewHolder) convertView.getTag();
        }
        //获取position对应的条目数据对象
        final FoodBean bean = getItem(position);
        if (bean != null) {
            vh.tv_food_name.setText(bean.getFoodName());
            vh.tv_count.setText("x"+bean.getCount());
            vh.tv_money.setText("¥"+bean.getPrice().multiply(BigDecimal.valueOf(
                    bean.getCount())));
            Glide.with(mContext)
                    .load(bean.getFoodPic())
                    .error(R.mipmap.ic_launcher)
                    .into(vh.iv_food_pic);
        }
        return convertView;
    }
    class ViewHolder {
        public TextView tv_food_name, tv_count, tv_money;
        public ImageView iv_food_pic;
    }
}

 4.5实现订单显示与支付功能:订单界面的数据是从店铺详情界面传递过来的

package com.example.meituan;

import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import com.example.shop.adapter.OrderAdapter;
import com.example.order.bean.FoodBean;

import java.math.BigDecimal;
import java.util.List;

public class OrderActivity extends AppCompatActivity {

    private ListView lv_order;
    private OrderAdapter adapter;
    private List<FoodBean> carFoodList;
    private TextView tv_title, tv_back,tv_distribution_cost,tv_total_cost,
            tv_cost,tv_payment;
    private RelativeLayout rl_title_bar;
    private BigDecimal money,distributionCost;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_order);
        //获取购物车中的数据
        carFoodList= (List<FoodBean>) getIntent().getSerializableExtra(
                "carFoodList");
        //获取购物车中菜的总价格
        money=new BigDecimal(getIntent().getStringExtra("totalMoney"));
        //获取店铺的配送费
        distributionCost=new BigDecimal(getIntent().getStringExtra(
                "distributionCost"));
        initView();
        setData();
    }
    /**
     * 初始化界面控件
     */
    private void initView(){
        tv_title = findViewById(R.id.tv_title);
        tv_title.setText("订单");
        rl_title_bar = findViewById(R.id.title_bar);
        rl_title_bar.setBackgroundColor(getResources().getColor(R.color.
                blue_color));
        tv_back =  findViewById(R.id.tv_back);
        lv_order= findViewById(R.id.lv_order);
        tv_distribution_cost = findViewById(R.id.tv_distribution_cost);

        tv_total_cost =  findViewById(R.id.tv_total_cost);
        tv_cost =  findViewById(R.id.tv_cost);
        tv_payment =  findViewById(R.id.tv_payment);
        // 返回键的点击事件
        tv_back.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
        tv_payment.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) { //“去支付”按钮的点击事件
                Dialog dialog = new Dialog(OrderActivity.this, R.style.
                        Dialog_Style);
                dialog.setContentView(R.layout.qr_code);
                dialog.show();
            }
        });
    }
    /**
     * 设置界面数据
     */
    private void setData() {
        adapter=new OrderAdapter(this);
        lv_order.setAdapter(adapter);
        adapter.setData(carFoodList);
        tv_cost.setText("¥"+money);
        tv_distribution_cost.setText("¥"+distributionCost);
        tv_total_cost.setText("¥"+(money.add(distributionCost)));
    }
}
  • 五、实验结果与分析

店铺列表界面:展示一些店铺信息组成的列表与一个水平滑动的广告栏

店铺详情界面:点击店铺列表中的任意一个条目或广告栏中的任意一张图片,程序会跳转到对应的店铺详情界面,该界面展示的是店铺的公告信息,配送信息,菜单列表以及购物车列表界面,点击菜单列表条目右侧的“加入购物车”按钮可以将菜品添加的菜品数量。如图所示:

点击购物车会弹起一个已选商品的列表,点击“-”和“+”可以减少或者增加菜品的数量,如果加入购物车的菜品总价达不到起送价,会显示还差多少起送,要是达到起送价格,会显示“去结算”按钮。在最右边的这张图中,有个清空的按钮,界面为对话框样式。如下图所示:

菜品详情界面:点击菜单列表任意一个条目,程序会跳转到菜品详情界面,该界面也是一个对话框的样式。界面如上右边这个图所示

订单界面:点击“去结算”按钮会跳出订单界面,该界面会通过列表展示购物车中的菜品信息,点击“去支付”,程序会弹出一个显示支付二维码的对话框,如下图所示

 

  • 53
    点赞
  • 83
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值