效果:
1:build.gradle中导入依赖
implementation 'com.squareup.okhttp3:okhttp:3.9.0'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
implementation 'com.facebook.fresco:fresco:0.14.1'
implementation 'io.reactivex.rxjava2:rxjava:2.1.7'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'com.jcodecraeer:xrecyclerview:1.2.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.github.bumptech.glide:glide:4.8.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'
2:AndroidManifest.xml清单文件中加入网络权限
<uses-permission android:name="android.permission.INTERNET"/>
3:整体架构
4:创建一个类实现接口拼接
1:public class StringUrl {
public static final String BASE_URL="http://www.zhaoapi.cn/";
}
2:public interface ApiService {
//全部网址:http://www.zhaoapi.cn/product/getCarts?uid=71
@GET("product/getCarts?uid=71")
Observable<Cart> getCarts();
}
5:工具类Retrofitutils
public class RetrofitUtils {
//支持RxJava
public static ApiService getNetDatas(){ //这里的ApiService是拼接网址的接口名
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(5, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS)
.build();
Retrofit retrofit = new Retrofit.Builder()
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.baseUrl(StringUrl.BASE_URL)
.build();
ApiService api = retrofit.create(ApiService.class);
return api;
}
}
6:创建bean类
网址:http://www.zhaoapi.cn/product/getCarts?uid=71
7:MVP框架搭建
1:view层**
public interface CartView {
void getCart(Cart cart);
void faild(Exception e);
}
2:model层
2.1:
public interface CartModel {
void cartrecy(Observer observer);
}
2.2:
public class MyCartModel implements CartModel{
@Override
public void cartrecy(Observer observer) {
RetrofitUtils.getNetDatas().getCarts()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe( observer);
}
}
3.presenter层
public class CartPresenter {
private CartView view;
private CartModel model;
public CartPresenter(CartView view) {
this.view = view;
model = new MyCartModel();
}
public void showCart(){
model.cartrecy(new Observer<Cart>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Cart cart) {
view.getCart(cart);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
//解绑
public void onDstory(){
view = null;
}
}
8:初始化全局的application在AndroidManifest.xml中加入name属性
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
Fresco.initialize(this);
}
}
9:购物车加减器的布局
<TextView
android:background="#ffffff"
android:layout_weight="1"
android:id="@+id/sub_tv"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="10dp"
android:text="-"
android:textSize="20sp" />
<TextView
android:text="1"
android:layout_marginLeft="2dp"
android:background="#ffffff"
android:layout_weight="1"
android:id="@+id/product_number_tv"
android:layout_width="0dp"
android:padding="10dp"
android:layout_height="wrap_content"
android:textSize="20sp"
android:gravity="center"
/>
<TextView
android:layout_marginLeft="2dp"
android:layout_weight="1"
android:id="@+id/add_tv"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="10dp"
android:gravity="center"
android:text="+"
android:textSize="20sp" />
10:购物车的加减器使用自定义组合控件使用
public class MyAddSubView extends LinearLayout implements View.OnClickListener {
private int number = 1;
private TextView sub_tv;
private TextView product_number_tv;
private TextView add_tv;
public MyAddSubView(Context context) {
this(context, null);
}
public MyAddSubView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MyAddSubView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
View view = inflate(context, R.layout.add_remove_view_layout, this);
sub_tv = view.findViewById(R.id.sub_tv);
product_number_tv = view.findViewById(R.id.product_number_tv);
add_tv = view.findViewById(R.id.add_tv);
sub_tv.setOnClickListener(this);
add_tv.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.sub_tv:
if (number > 1) {
--number;
product_number_tv.setText(number + "");
if (onNumberChangeListener != null) {
onNumberChangeListener.onNumberChange(number);
}
} else {
Toast.makeText(getContext(), "不能再少了", Toast.LENGTH_SHORT).show();
}
break;
case R.id.add_tv:
++number;
product_number_tv.setText(number + "");
if (onNumberChangeListener != null) {
onNumberChangeListener.onNumberChange(number);
}
break;
}
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
product_number_tv.setText(number + "");
}
OnNumberChangeListener onNumberChangeListener;
public void setOnNumberChangeListener(OnNumberChangeListener onNumberChangeListener) {
this.onNumberChangeListener = onNumberChangeListener;
}
public interface OnNumberChangeListener {
void onNumberChange(int num);
}
}
11:写适配器
因为是一个二级联动的购物车
1:一级列表布局
<CheckBox
android:id="@+id/cb_sj"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"/>
<TextView
android:id="@+id/txt_sj_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:padding="10dp"
/>
2:二级列表布局
<CheckBox
android:id="@+id/cb_shop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"/>
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv_image"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginLeft="10dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginLeft="10dp"
android:orientation="vertical">
<TextView
android:id="@+id/txt_shopname"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:id="@+id/txt_shopprice"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="¥:0.0"
android:gravity="center"
android:textColor="#f73838"
android:layout_weight="1"/>
<com.bwie.newmoth01.utils.MyAddSubView
android:id="@+id/subview"
android:layout_width="0dp"
android:gravity="center"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_weight="1"></com.bwie.newmoth01.utils.MyAddSubView>
</LinearLayout>
</LinearLayout>
3:因为网址的图片是拼接的所以我们要进行截取,写一个类截取图片,适配器中使用
public class ImgProcess {
public static String getImg(String images) {
String[] a = images.split("\\|");
return a[0];
}
public static String setImg(String images) {
String a = images.replace("https","http");
return a;
}
}
:4:适配器adapter继承BaseExpandableListAdapter*
public class CartAdapter extends BaseExpandableListAdapter {
private List<Cart.DataBean> dataBeanList;
public CartAdapter(List<Cart.DataBean> dataBeanList) {
this.dataBeanList = dataBeanList;
}
@Override
public int getGroupCount() {
return dataBeanList == null ? 0 : dataBeanList.size();
}
@Override
public int getChildrenCount(int groupPosition) {
return dataBeanList.get(groupPosition).getList() == null ? 0 : dataBeanList.get(groupPosition).getList().size();
}
@Override
public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
Cart.DataBean dataBean = dataBeanList.get(groupPosition);
ViewHolder1 holder1;
if (convertView ==null){
convertView = View.inflate(parent.getContext(),R.layout.cart_recy_one,null);
holder1 = new ViewHolder1(convertView);
convertView.setTag(holder1);
}else {
holder1 = (ViewHolder1) convertView.getTag();
}
//获取商家的名称
holder1.sJname.setText(dataBean.getSellerName());
//判断当前商家是否是选中状态
boolean allSjShopselected = isAllSjShopselected(groupPosition);
holder1.sJcb.setChecked(allSjShopselected);
//设置点击复选框
holder1.sJcb.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnCartListener !=null){
mOnCartListener.onCartSjChecked(groupPosition);
}
}
});
return convertView;
}
@Override
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
List<Cart.DataBean.ListBean> list = dataBeanList.get(groupPosition).getList();
Cart.DataBean.ListBean listBean = list.get(childPosition);
ViewHolder2 holder2;
if (convertView ==null){
convertView = View.inflate(parent.getContext(),R.layout.cart_recy_two,null);
holder2 = new ViewHolder2(convertView);
convertView.setTag(holder2);
}else {
holder2 = (ViewHolder2) convertView.getTag();
}
//设置图片
// Uri uri = Uri.parse(listBean.getImages());
// holder2.sdvImage.setImageURI(uri);
holder2.sdvImage.setImageURI(Uri.parse(ImgProcess.getImg(listBean.getImages())));
//设置商品名
holder2.shopname.setText(listBean.getTitle());
//设置价格
holder2.txtPrice.setText("¥:"+listBean.getPrice());
//加减器
holder2.subView.setNumber(listBean.getNum());
//设置加减器是否选中
holder2.shopcb.setChecked(listBean.getSelected() ==1);
holder2.shopcb.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnCartListener !=null){
mOnCartListener.onCartShopChecked(groupPosition,childPosition);
}
}
});
//加减器通过接口回调暴露给外面
holder2.subView.setOnNumberChangeListener(new MyAddSubView.OnNumberChangeListener() {
@Override
public void onNumberChange(int num) {
if (mOnCartListener !=null){
mOnCartListener.onCartSubviewChecked(groupPosition,childPosition,num);
}
}
});
return convertView;
}
//组的数据
public static class ViewHolder1 {
private final CheckBox sJcb;
private final TextView sJname;
public ViewHolder1(View rootView){
sJcb = rootView.findViewById(R.id.cb_sj);
sJname = rootView.findViewById(R.id.txt_sj_name);
}
}
//组的数据
public static class ViewHolder2 {
private final CheckBox shopcb;
private final SimpleDraweeView sdvImage;
private final TextView shopname;
private final TextView txtPrice;
private final MyAddSubView subView;
public ViewHolder2(View rootView){
shopcb = rootView.findViewById(R.id.cb_shop);
sdvImage = rootView.findViewById(R.id.sdv_image);
shopname = rootView.findViewById(R.id.txt_shopname);
txtPrice = rootView.findViewById(R.id.txt_shopprice);
subView = rootView.findViewById(R.id.subview);
}
}
/**
* 判断商家的商品是否选中
* @param groupPosition
* @return
*/
public boolean isAllSjShopselected(int groupPosition){
//获取商家数据
Cart.DataBean dataBean = dataBeanList.get(groupPosition);
//获取商品数据
List<Cart.DataBean.ListBean> list = dataBean.getList();
for (Cart.DataBean.ListBean listBean: list){
//判断商品是否都选中,一个没选中商家的复选框都不选中 ==0是选中状态
if (listBean.getSelected() ==0){
return false;
}
}
return true;
}
/**
* 底部全选框的状态
* @return
*/
public boolean isBottomAllselected(){
for (int i = 0; i < dataBeanList.size(); i++) {
Cart.DataBean dataBean = dataBeanList.get(i);
List<Cart.DataBean.ListBean> list = dataBean.getList();
for (int j = 0; j < list.size(); j++) {
if (list.get(j).getSelected() ==0){
return false;
}
}
}
return true;
}
/**
* 计算商品总的数量
* @return
*/
public int ShopNumber(){
int shopnums = 0;
for (int i = 0; i < dataBeanList.size(); i++) {
Cart.DataBean dataBean = dataBeanList.get(i);
List<Cart.DataBean.ListBean> list = dataBean.getList();
for (int j = 0; j < list.size(); j++) {
if (list.get(j).getSelected() ==1){
int num = list.get(j).getNum();
shopnums += num;
}
}
}
return shopnums;
}
/**
* 计算商品的总价格
* @return
*/
public float ShopPrices(){
float prices = 0;
for (int i = 0; i < dataBeanList.size(); i++) {
Cart.DataBean dataBean = dataBeanList.get(i);
List<Cart.DataBean.ListBean> list = dataBean.getList();
for (int j = 0; j < list.size(); j++) {
if (list.get(j).getSelected() == 1){
int price = list.get(j).getPrice();
int num = list.get(j).getNum();
prices += price * num;
}
}
}
return prices;
}
/**
* 商家选中时商品都选中
* @param groupPosition
* @param isSelected
*/
public void SjSelected(int groupPosition, boolean isSelected){
Cart.DataBean dataBean = dataBeanList.get(groupPosition);
List<Cart.DataBean.ListBean> list = dataBean.getList();
for (int i = 0; i < list.size(); i++) {
Cart.DataBean.ListBean listBean = list.get(i);
listBean.setSelected(isSelected ? 1 : 0);
}
}
/**
* 当商品都选中时更新商家的状态
* @param groupPosition
* @param childPosition
*/
public void ShopSelected(int groupPosition,int childPosition){
Cart.DataBean dataBean = dataBeanList.get(groupPosition);
List<Cart.DataBean.ListBean> list = dataBean.getList();
Cart.DataBean.ListBean listBean = list.get(childPosition);
listBean.setSelected(listBean.getSelected() ==0 ? 1 : 0);
}
/**
* 底部全选框状态选中时更新以上所有商品状态
* @param selected
*/
public void ButtomSelected(boolean selected){
for (int i = 0; i < dataBeanList.size(); i++) {
Cart.DataBean dataBean = dataBeanList.get(i);
List<Cart.DataBean.ListBean> list = dataBean.getList();
for (int j = 0; j < list.size(); j++) {
list.get(j).setSelected(selected ? 1 : 0);
}
}
}
/**
* 当商品加减器被点击时改变里面商品的数量
* @param groupPosition
* @param childPosition
* @param number
*/
public void subviewSelected(int groupPosition, int childPosition , int number){
Cart.DataBean dataBean = dataBeanList.get(groupPosition);
List<Cart.DataBean.ListBean> list = dataBean.getList();
Cart.DataBean.ListBean listBean = list.get(childPosition);
listBean.setNum(number);
}
/**
* 接口回调
*/
public interface OnCartListener{
/**
* 点击商家复选框的时候调用
* @param groupPosition
*/
void onCartSjChecked(int groupPosition);
/**
* 点击商品复选框的时候调用
* @param groupPosition
* @param childPosition
*/
void onCartShopChecked(int groupPosition,int childPosition);
/**
* 点击购物车加减器的时候调用
* @param groupPosition
* @param childPosition
* @param number
*/
void onCartSubviewChecked(int groupPosition,int childPosition,int number);
}
public OnCartListener mOnCartListener;
/**
* 给商家商品加减器设置监听
* @param onCartListener
*/
public void setOnCartListener(OnCartListener onCartListener){
mOnCartListener = onCartListener;
}
////////////////////////////////////////////////////////下面的东西不用写//////////////////////////////////////////////
@Override
public Object getGroup(int groupPosition) {
return null;
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return null;
}
@Override
public long getGroupId(int groupPosition) {
return 0;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return 0;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}
}
12:开始写主页面了
1:布局使用ExpandableListView控件展示商品列表
<ExpandableListView
android:id="@+id/cart_recy"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="9"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:paddingLeft="10dp"
android:orientation="horizontal">
<CheckBox
android:id="@+id/all_cb"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="全选"/>
<TextView
android:id="@+id/txt_price"
android:layout_width="0dp"
android:layout_weight="2"
android:padding="10dp"
android:layout_height="wrap_content" />
<Button
android:id="@+id/btn_jiesuan"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="wrap_content"
android:background="#ea6363"
android:textColor="#fff"
android:text="去结算"/>
</LinearLayout>
2:actvit中的主代码
public class MainActivity extends AppCompatActivity implements CartView, View.OnClickListener {
private ExpandableListView cart_recy;
private CheckBox all_cb;
private TextView txt_price;
private CartPresenter presenter;
private CartAdapter cartAdapter;
private Button btn_jiesuan;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
}
private void initData() {
presenter = new CartPresenter(this);
presenter.showCart();
}
private void initView() {
cart_recy = (ExpandableListView) findViewById(R.id.cart_recy);
all_cb = (CheckBox) findViewById(R.id.all_cb);
txt_price = (TextView) findViewById(R.id.txt_price);
btn_jiesuan = (Button) findViewById(R.id.btn_jiesuan);
btn_jiesuan.setOnClickListener(this);
all_cb.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_jiesuan:
break;
case R.id.all_cb:
boolean bottomAllselected = cartAdapter.isBottomAllselected();
cartAdapter.ButtomSelected(!bottomAllselected);
cartAdapter.notifyDataSetChanged();
notifyButtomNumber();
break;
}
}
@Override
public void getCart(Cart cart) {
List<Cart.DataBean> data = cart.getData();
cartAdapter = new CartAdapter(data);
cartAdapter.setOnCartListener(new CartAdapter.OnCartListener() {
@Override
public void onCartSjChecked(int groupPosition) {
/**
* 点击商家的时候回调
*/
boolean allSjShopselected = cartAdapter.isAllSjShopselected(groupPosition);
cartAdapter.SjSelected(groupPosition, !allSjShopselected);
cartAdapter.notifyDataSetChanged();
notifyButtomNumber();
}
@Override
public void onCartShopChecked(int groupPosition, int childPosition) {
/**
* 点击商品的时候回调
*/
cartAdapter.ShopSelected(groupPosition, childPosition);
cartAdapter.notifyDataSetChanged();
notifyButtomNumber();
}
@Override
public void onCartSubviewChecked(int groupPosition, int childPosition, int number) {
/**
* 加减器回调
*/
cartAdapter.subviewSelected(groupPosition, childPosition, number);
cartAdapter.notifyDataSetChanged();
notifyButtomNumber();
}
});
cart_recy.setAdapter(cartAdapter);
// 展开二级列表
for (int x = 0; x < data.size(); x++) {
cart_recy.expandGroup(x);
}
}
@Override
public void faild(Exception e) {
Toast.makeText(this, "获取数据失败", Toast.LENGTH_SHORT).show();
}
private void notifyButtomNumber() {
//去判断是否所有的商品都被选中
boolean bottomAllselected = cartAdapter.isBottomAllselected();
all_cb.setChecked(bottomAllselected);
//计算总计
float prices = cartAdapter.ShopPrices();
txt_price.setText("总计" + prices);
int number = cartAdapter.ShopNumber();
btn_jiesuan.setText("去结算("+number+")");
}
}