简单购物车

依赖


  //okhttp
    compile 'com.squareup.okhttp3:okhttp:3.6.0'
    compile 'com.squareup.okio:okio:1.11.0'


    //gson
    compile 'com.google.code.gson:gson:2.8.2'


    //glide
    implementation 'com.github.bumptech.glide:glide:4.4.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.4.0'


//自定义的listview布局_MyExpanableListView

public class MyExpanableListView extends ExpandableListView {
    public MyExpanableListView(Context context) {
        super(context);
    }


    public MyExpanableListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    public MyExpanableListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //高度
        int height = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE>>2,MeasureSpec.AT_MOST);


        super.onMeasure(widthMeasureSpec, height);
    }
}


//activity_main布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.dash.a18_shopping_cart.view.activity.MainActivity">


    <ScrollView
        android:layout_above="@+id/linear_bottom"
        android:layout_width="match_parent"
        android:layout_height="match_parent">


        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent">


            <!--二级列表-->
            <com.dash.a18_shopping_cart.view.custom.MyExpanableListView
                android:id="@+id/expanable_list_view"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">


            </com.dash.a18_shopping_cart.view.custom.MyExpanableListView>


            <!--recyclerView展示为你推荐-->
            <TextView
                android:background="#00ff00"
                android:text="为你推荐"
                android:layout_marginTop="10dp"
                android:layout_gravity="center_horizontal"
                android:layout_width="match_parent"
                android:layout_height="400dp" />




        </LinearLayout>


    </ScrollView>


    <LinearLayout
        android:orientation="horizontal"
        android:id="@+id/linear_bottom"
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="50dp">


        <CheckBox
            android:button="@null"
            android:background="@drawable/check_box_selector"
            android:layout_marginLeft="10dp"
            android:id="@+id/check_all"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />


        <TextView
            android:id="@+id/text_total"
            android:text="合计:¥0.00"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="10dp"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content" />


        <TextView
            android:id="@+id/text_buy"
            android:background="#ff0000"
            android:textColor="#ffffff"
            android:gravity="center"
            android:text="去结算(0)"
            android:layout_width="100dp"
            android:layout_height="match_parent" />






    </LinearLayout>


</RelativeLayout>


//子条目的布局child_layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:padding="10dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">


    <CheckBox
        android:button="@null"
        android:background="@drawable/check_box_selector"
        android:layout_centerVertical="true"
        android:id="@+id/child_check"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />


    <ImageView
        android:layout_marginLeft="10dp"
        android:layout_toRightOf="@+id/child_check"
        android:id="@+id/child_image"
        android:layout_width="100dp"
        android:layout_height="100dp" />


    <TextView
        android:maxLines="2"
        android:minLines="2"
        android:id="@+id/child_title"
        android:layout_marginLeft="5dp"
        android:layout_toRightOf="@+id/child_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />


    <TextView
        android:id="@+id/child_price"
        android:textColor="#ff0000"
        android:text="¥0.00"
        android:layout_toRightOf="@+id/child_image"
        android:layout_alignBottom="@+id/child_image"
        android:layout_marginLeft="5dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />




    <LinearLayout
        android:layout_alignParentRight="true"
        android:layout_alignBottom="@+id/child_image"
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">


        <TextView
            android:padding="5dp"
            android:background="@drawable/bian_kuang"
            android:text="-"
            android:id="@+id/text_jian"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />


        <TextView
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:paddingBottom="5dp"
            android:paddingTop="5dp"
            android:background="@drawable/bian_kuang"
            android:text="1"
            android:id="@+id/text_num"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />


        <TextView
            android:padding="5dp"
            android:background="@drawable/bian_kuang"
            android:text="+"
            android:id="@+id/text_add"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />


    </LinearLayout>






</RelativeLayout>


//父条目的布局


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:padding="10dp"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <CheckBox
        android:button="@null"
        android:background="@drawable/check_box_selector"
        android:id="@+id/group_check"
        android:layout_gravity="center_vertical"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />


    <TextView
        android:id="@+id/group_text"
        android:layout_marginLeft="10dp"
        android:layout_gravity="center_vertical"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />


</LinearLayout>



//ApiUtil 路径

public class ApiUtil {


    //查询购物车的路径 https://www.zhaoapi.cn/product/getCarts?uid=71&source=android
    public static String selectCartUrl = "https://www.zhaoapi.cn/product/getCarts";


    //删除购物车


    //更新购物车


    //商品详情.....


}


//OkHttp3Util工具包4



public class OkHttp3Util {




    /**
     * 懒汉 安全 加同步
     * 1.私有的静态成员变量 只声明不创建
     * 2.私有的构造方法
     * 3.提供返回实例的静态方法
     */
    private static OkHttpClient okHttpClient = null;




    private OkHttp3Util() {
    }


    public static OkHttpClient getInstance() {


        if (okHttpClient == null) {
            //加同步安全
            synchronized (OkHttp3Util.class) {
                if (okHttpClient == null) {
                    //okhttp可以缓存数据....指定缓存路径
                    File sdcache = new File(Environment.getExternalStorageDirectory(), "cache");
                    //指定缓存大小
                    int cacheSize = 10 * 1024 * 1024;


                    okHttpClient = new OkHttpClient.Builder()//构建器
                            .connectTimeout(15, TimeUnit.SECONDS)//连接超时
                            .writeTimeout(20, TimeUnit.SECONDS)//写入超时
                            .readTimeout(20, TimeUnit.SECONDS)//读取超时




                            .cache(new Cache(sdcache.getAbsoluteFile(), cacheSize))//设置缓存
                            .build();
                }
            }


        }


        return okHttpClient;
    }


    /**
     * get请求
     * 参数1 url
     * 参数2 回调Callback
     */


    public static void doGet(String oldUrl, Callback callback) {


        //创建OkHttpClient请求对象
        OkHttpClient okHttpClient = getInstance();
        //创建Request
        Request request = new Request.Builder().url(oldUrl).build();
        //得到Call对象
        Call call = okHttpClient.newCall(request);
        //执行异步请求
        call.enqueue(callback);




    }


    /**
     * post请求
     * 参数1 url
     * 参数2 Map<String, String> params post请求的时候给服务器传的数据
     *      add..("","")
     *      add()
     */


    public static void doPost(String url, Map<String, String> params, Callback callback) {
        //创建OkHttpClient请求对象
        OkHttpClient okHttpClient = getInstance();
        //3.x版本post请求换成FormBody 封装键值对参数


        FormBody.Builder builder = new FormBody.Builder();
        //遍历集合,,,map集合遍历方式
        for (String key : params.keySet()) {
            builder.add(key, params.get(key));


        }




        //创建Request....formBody...new formBody.Builder()...add()....build()
        Request request = new Request.Builder().url(url).post(builder.build()).build();


        Call call = okHttpClient.newCall(request);
        call.enqueue(callback);


    }


    /**
     * post请求上传文件....包括图片....流的形式传任意文件...
     * 参数1 url
     * file表示上传的文件
     * fileName....文件的名字,,例如aaa.jpg
     * params ....传递除了file文件 其他的参数放到map集合
     *
     */
    public static void uploadFile(String url, File file, String fileName,Map<String,String> params,Callback callback) {
        //创建OkHttpClient请求对象
        OkHttpClient okHttpClient = getInstance();


        //MultipartBody多功能的请求实体对象,,,formBody只能传表单形式的数据
        MultipartBody.Builder builder = new MultipartBody.Builder();
        builder.setType(MultipartBody.FORM);


        //参数
        if (params != null){
            for (String key : params.keySet()){
                builder.addFormDataPart(key,params.get(key));
            }
        }
        //文件...参数name指的是请求路径中所接受的参数...如果路径接收参数键值是fileeeee,此处应该改变
        builder.addFormDataPart("file",fileName,RequestBody.create(MediaType.parse("application/octet-stream"),file));


        //构建
        MultipartBody multipartBody = builder.build();


        //创建Request
        Request request = new Request.Builder().url(url).post(multipartBody).build();


        //得到Call
        Call call = okHttpClient.newCall(request);
        //执行请求
        call.enqueue(callback);


    }


    /**
     * Post请求发送JSON数据....{"name":"zhangsan","pwd":"123456"}
     * 参数一:请求Url
     * 参数二:请求的JSON
     * 参数三:请求回调
     */
    public static void doPostJson(String url, String jsonParams, Callback callback) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonParams);
        Request request = new Request.Builder().url(url).post(requestBody).build();
        Call call = getInstance().newCall(request);
        call.enqueue(callback);


    }


    /**
     * 下载文件 以流的形式把apk写入的指定文件 得到file后进行安装
     * 参数er:请求Url
     * 参数san:保存文件的文件夹....download
     */
    public static void download(final Activity context, final String url, final String saveDir) {
        Request request = new Request.Builder().url(url).build();
        Call call = getInstance().newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //com.orhanobut.logger.Logger.e(e.getLocalizedMessage());
            }


            @Override
            public void onResponse(Call call, final Response response) throws IOException {


                InputStream is = null;
                byte[] buf = new byte[2048];
                int len = 0;
                FileOutputStream fos = null;
                try {
                    is = response.body().byteStream();//以字节流的形式拿回响应实体内容
                    //apk保存路径
                    final String fileDir = isExistDir(saveDir);
                    //文件
                    File file = new File(fileDir, getNameFromUrl(url));


                    fos = new FileOutputStream(file);
                    while ((len = is.read(buf)) != -1) {
                        fos.write(buf, 0, len);
                    }


                    fos.flush();


                    context.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(context, "下载成功:" + fileDir + "," + getNameFromUrl(url), Toast.LENGTH_SHORT).show();
                        }
                    });


                    //apk下载完成后 调用系统的安装方法
                    Intent intent = new Intent(Intent.ACTION_VIEW);
                    intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
                    context.startActivity(intent);




                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (is != null) is.close();
                    if (fos != null) fos.close();




                }
            }
        });


    }


    /**
     * 判断下载目录是否存在......并返回绝对路径
     *
     * @param saveDir
     * @return
     * @throws IOException
     */
    public static String isExistDir(String saveDir) throws IOException {
        // 下载位置
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {


            File downloadFile = new File(Environment.getExternalStorageDirectory(), saveDir);
            if (!downloadFile.mkdirs()) {
                downloadFile.createNewFile();
            }
            String savePath = downloadFile.getAbsolutePath();
            Log.e("savePath", savePath);
            return savePath;
        }
        return null;
    }


    /**
     * @param url
     * @return 从下载连接中解析出文件名
     */
    private static String getNameFromUrl(String url) {
        return url.substring(url.lastIndexOf("/") + 1);
    }


}




//模块层MainModel


public class MainModel {


    private IMainPresenter iMainPresenter;


    public MainModel(IMainPresenter iMainPresenter) {
        this.iMainPresenter = iMainPresenter;
    }


    //在这里真正获取购物车的数据
    public void getCartData(String selectCartUrl) {


        Map<String, String> params = new HashMap<>();
        params.put("uid","71");
        params.put("source","android");


        OkHttp3Util.doPost(selectCartUrl, params, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {


            }


            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()){


                    String json = response.body().string();


                    //解析
                    CartBean cartBean = new Gson().fromJson(json,CartBean.class);


                    //接口回调...presenter层
                    iMainPresenter.onSuccess(cartBean);


                }
            }
        });


    }
}


//CartBean 类


//CountPriceBean类


public class CountPriceBean {
    private String priceString;
    private int count;


    public CountPriceBean(String priceString, int count) {
        this.priceString = priceString;
        this.count = count;
    }


    public String getPriceString() {
        return priceString;
    }


    public void setPriceString(String priceString) {
        this.priceString = priceString;
    }


    public int getCount() {
        return count;
    }


    public void setCount(int count) {
        this.count = count;
    }
}


//中间者MainPresenter


public class MainPresenter implements IMainPresenter{


    private MainModel mainModel;
    private IMainActivity iMainActivity;


    public MainPresenter(IMainActivity iMainActivity) {


        this.iMainActivity = iMainActivity;


        //创建model
        mainModel = new MainModel(this);


    }


    //当前中间者不去直接获取网络数据,,,需要让model获取,,,创建presenter的时候就去创建出model,,,构造方法中
    public void getCartData(String selectCartUrl) {
        //需要让model获取,


        mainModel.getCartData(selectCartUrl);


    }


    @Override
    public void onSuccess(CartBean cartBean) {
        //回调给view层...activity
        iMainActivity.onCartSuccess(cartBean);
    }
}



//接口IMainPresenter


public interface IMainPresenter {


    void onSuccess(CartBean cartBean);
}


//接口IMainActivity


public interface IMainActivity {
    void onCartSuccess(CartBean cartBean);
}



//适配器MyAdapter


public class MyAdapter extends BaseExpandableListAdapter{
    private Handler handler;
    private CartBean cartBean;
    private Context context;


    public MyAdapter(Context context, CartBean cartBean, Handler handler) {
        this.context = context;
        this.cartBean = cartBean;
        this.handler = handler;
    }


    @Override
    public int getGroupCount() {
        return cartBean.getData().size();
    }


    @Override
    public int getChildrenCount(int groupPosition) {
        return cartBean.getData().get(groupPosition).getList().size();
    }


    @Override
    public Object getGroup(int groupPosition) {
        return cartBean.getData().get(groupPosition);
    }


    @Override
    public Object getChild(int groupPosition, int childPosition) {


        return cartBean.getData().get(groupPosition).getList().get(childPosition);
    }


    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }


    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }


    @Override
    public boolean hasStableIds() {
        return true;
    }


    @Override
    public View getGroupView(int groupPosition, boolean b, View view, ViewGroup viewGroup) {
        GroupHolder holder;
        if (view == null){
            view = View.inflate(context, R.layout.group_layout,null);
            holder = new GroupHolder();


            holder.checkBox = view.findViewById(R.id.group_check);
            holder.textView = view.findViewById(R.id.group_text);


            view.setTag(holder);
        }else {
            holder = (GroupHolder) view.getTag();
        }


        CartBean.DataBean dataBean = cartBean.getData().get(groupPosition);
        //赋值
        holder.textView.setText(dataBean.getSellerName());
        holder.checkBox.setChecked(dataBean.isGroup_check());


        return view;
    }


    @Override
    public View getChildView(int groupPosition, int childPosition, boolean b, View view, ViewGroup viewGroup) {
        ChildHolder holder;
        if (view == null){
            view = View.inflate(context, R.layout.child_layout,null);
            holder = new ChildHolder();


            holder.checkBox = view.findViewById(R.id.child_check);
            holder.text_title = view.findViewById(R.id.child_title);
            holder.imageView = view.findViewById(R.id.child_image);
            holder.text_price = view.findViewById(R.id.child_price);
            holder.text_jian = view.findViewById(R.id.text_jian);
            holder.text_num = view.findViewById(R.id.text_num);
            holder.text_add = view.findViewById(R.id.text_add);


            view.setTag(holder);
        }else {
            holder = (ChildHolder) view.getTag();
        }


        CartBean.DataBean.ListBean listBean = cartBean.getData().get(groupPosition).getList().get(childPosition);


        //赋值
        holder.text_title.setText(listBean.getTitle());
        holder.text_price.setText("¥"+listBean.getBargainPrice());


        String[] strings = listBean.getImages().split("\\|");
        Glide.with(context).load(strings[0]).into(holder.imageView);


        holder.checkBox.setChecked(listBean.getSelected() == 0? false:true);//根据0,1进行设置是否选中
        //setText()我们使用一定是设置字符串
        holder.text_num.setText(listBean.getNum()+"");


        return view;
    }


    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }


    /**
     * 计算数量和价格,,,并发送到activity显示
     */
    public void sendPriceAndCount() {
        double price = 0;
        int count = 0;


        for (int i=0;i<cartBean.getData().size();i++){


            List<CartBean.DataBean.ListBean> listBeans = cartBean.getData().get(i).getList();
            for (int j = 0; j< listBeans.size(); j++){
                CartBean.DataBean.ListBean listBean = listBeans.get(j);


                //选中的时候计算价格和数量
                if (listBean.getSelected() == 1){


                    price += listBean.getBargainPrice() * listBean.getNum();
                    count += listBean.getNum();
                }


            }
        }


        DecimalFormat decimalFormat = new DecimalFormat("0.00");
        String priceString = decimalFormat.format(price);


        //封装一下
        CountPriceBean countPriceBean = new CountPriceBean(priceString, count);
        //发送给activity/fragment进行显示


        Message msg = Message.obtain();


        msg.what = 0;
        msg.obj = countPriceBean;
        handler.sendMessage(msg);


    }


    private class GroupHolder{
        CheckBox checkBox;
        TextView textView;
    }


    private class ChildHolder{
        CheckBox checkBox;
        ImageView imageView;
        TextView text_title;
        TextView text_price;
        TextView text_num;
        TextView text_jian;
        TextView text_add;
    }
}


//主要的MainActivity




public class MainActivity extends AppCompatActivity implements IMainActivity{


    private MyExpanableListView expanableListView;
    private MainPresenter mainPresenter;
    private CheckBox check_all;
    private TextView text_total;
    private TextView text_buy;


    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {


            if (msg.what == 0){
                CountPriceBean countPriceBean = (CountPriceBean) msg.obj;


                text_total.setText("合计:¥"+countPriceBean.getPriceString());
                text_buy.setText("去结算("+countPriceBean.getCount()+")");
            }


        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        //找到控件
        expanableListView = findViewById(R.id.expanable_list_view);
        check_all = findViewById(R.id.check_all);
        text_total = findViewById(R.id.text_total);
        text_buy = findViewById(R.id.text_buy);






        //去掉默认的指示器
        expanableListView.setGroupIndicator(null);


        //获取数据....MVP
        mainPresenter = new MainPresenter(this);




    }


    @Override
    protected void onResume() {
        super.onResume();


        //调用获取数据的方法
        mainPresenter.getCartData(ApiUtil.selectCartUrl);


    }


    /**
     * 只要购物车页面显示  就要去网络获取新的数据....获取购物车数据操作放到获取焦点的生命周期方法中
     */




    @Override
    public void onCartSuccess(final CartBean cartBean) {
        //处于子线程!!!!!!!!!!!!!!!!!!!


        runOnUiThread(new Runnable() {
            @Override
            public void run() {


                //需要更改获取的cartBean数据


                //1.根据某一个组中的二级所有的子条目是否选中,确定当前一级列表是否选中
                for (int i = 0;i<cartBean.getData().size();i++){


                    if(isChildInGroupChecked(i,cartBean)){
                        cartBean.getData().get(i).setGroup_check(true);
                    }
                }


                //2.设置是否全选选中...根据所有的一级列表是否选中,确定全选是否选中
                if (isAllGroupChecked(cartBean)){
                    check_all.setChecked(true);
                }




                //设置适配器
                MyAdapter myAdapter = new MyAdapter(MainActivity.this, cartBean,handler);
                expanableListView.setAdapter(myAdapter);


                //展开所有的组...expanableListView.expandGroup()
                for (int i = 0;i<cartBean.getData().size();i++){
                    expanableListView.expandGroup(i);
                }


                //3.计算总价和商品的数量
                myAdapter.sendPriceAndCount();


            }
        });


    }


    /**
     * 所有的组是否选中
     * @return
     * @param cartBean
     */
    private boolean isAllGroupChecked(CartBean cartBean) {
        for (int i =0;i<cartBean.getData().size();i++){
            if (! cartBean.getData().get(i).isGroup_check()){//表示有没选中的组
                return false;
            }
        }


        return true;
    }


    /**
     * 当前组中所有的子条目是否全部选中
     * @param i
     * @param cartBean
     * @return
     */
    private boolean isChildInGroupChecked(int i, CartBean cartBean) {
        //当前组中所有子条目的数据
        List<CartBean.DataBean.ListBean> listBeans = cartBean.getData().get(i).getList();
        for (int j = 0;j<listBeans.size();j++){
            if (listBeans.get(j).getSelected() == 0){//有未选中的条目
                return false;
            }
        }


        return true;
    }
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值