您的位置:首页 > 理论基础 > 计算机网络

二级列表实现购物车,使用OkHttpClient请求数据

2018-12-18 21:30 381 查看

二级列表做购物车最难的就是关联,需要判断,逻辑比较绕,但只要自己好好看看,理解理解还是会感到很简单的。

先看效果,再说代码



如果要把所有的不同都上传就太多了,所有这里就先放3张图片

在做功能之前,我们应该先把要使用的依赖导入,权限加上

//因为我们要从网上获取数据,所以导入okhttp,然后用gson解析,用glide加载图片
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
implementation 'com.github.bumptech.glide:glide:4.8.0'

然后在清单文件中添加权限

<uses-permission android:name="android.permission.INTERNET" />

现在先写activity.xml文件

<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=".MainActivity">

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

<CheckBox
android:id="@+id/send_all"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:focusable="false"
android:text="全选"
android:textSize="20sp" />

<TextView
android:id="@+id/send_price"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:gravity="center"
android:text="价格:0.0"
android:textSize="20sp" />

<TextView
android:id="@+id/send_sum"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:gravity="center"
android:text="总数量:0"
android:textSize="20sp" />
</LinearLayout>

<ExpandableListView
android:id="@+id/send_expand"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/send_footer"></ExpandableListView>
</RelativeLayout>

一级的xml文件视图

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">

<CheckBox
android:id="@+id/group_check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:textSize="35sp" />

<TextView
android:id="@+id/group_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="35sp" />

</LinearLayout>

二级的xml文件的视图

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<CheckBox
android:id="@+id/child_check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp" />

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

<TextView
android:id="@+id/child_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/child_image"
android:textSize="25sp" />

<TextView
android:id="@+id/child_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/child_title"
android:textColor="#f00"
android:textSize="25sp" />
//自定义的控件
<com.bwie.lian.weight.MyView
android:id="@+id/child_myview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/child_title"
android:layout_toRightOf="@id/child_image"></com.bwie.lian.weight.MyView>
</RelativeLayout>

在这里有一个自定义的控件

在自定义之前要有一个xml文件,里面有两张图片,可以用自己的来替换。它的效果如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">

<ImageView
android:id="@+id/send_jia"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/jia" />

<TextView
android:id="@+id/send_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="0"
android:textSize="35sp" />

<ImageView
android:id="@+id/send_jian"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/jian" />
</LinearLayout>

现在就应该写一个类,来自定义

public class MyView extends LinearLayout implements View.OnClickListener {
private ImageView send_jia;
private TextView send_number;
private ImageView send_jian;
private int mNumber;
private Context mContext;

public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
//获取视图
LayoutInflater.from(context).inflate(R.layout.number_list, this);
//查找控件
initView();
}

//定义一个方法来获取商品数量
public void setChildNumber(int number) {
this.mNumber = number;
send_number.setText("数量是:" + mNumber);
}

private void initView() {
send_jia = findViewById(R.id.send_jia);
send_jia.setOnClickListener(this);
send_number = findViewById(R.id.send_number);
send_jian = findViewById(R.id.send_jian);
send_jian.setOnClickListener(this);
}

@Override
public void onClick(View view) {
//判断点击事件
switch (view.getId()) {
case R.id.send_jian:
//减得时候数量要大于0
if (mNumber > 0) {
mNumber--;
//给TextView赋值
send_number.setText("数量是:" + mNumber);
//判断接口是否为空
if (onChangeChildCount != null) {
//将改完的数量传入接口中
onChangeChildCount.getChildCount(mNumber);
}
} else {
//提示
Toast.makeText(mContext, "数量最小为0", Toast.LENGTH_SHORT).show();
}
break;
case R.id.send_jia:
//跟减的意思一样
mNumber++;
send_number.setText("数量是:" + mNumber);
if (onChangeChildCount != null) {
onChangeChildCount.getChildCount(mNumber);
}
break;
}
}

//自定义接口
public interface OnChangeChildCount {
void getChildCount(int number);
}

private OnChangeChildCount onChangeChildCount;

public void setOnChangeChildCount(OnChangeChildCount onChangeChildCount) {
this.onChangeChildCount = onChangeChildCount;
}
}

现在是MainActivity中的代码

public class MainActivity extends AppCompatActivity {
//网络请求的数据存入集合中
private List<ShopBean.DataBean> mdata = new ArrayList<>();
private String mUrl = "http://www.wanandroid.com/tools/mockapi/6523/restaurant-list";
private CheckBox send_all;
private TextView send_price;
private TextView send_sum;
private ExpandableListView send_expand;
private MyAdapter adapter;
@SuppressLint("HandlerLeak")
//使用handler,在里面解析字符串,重新赋值,刷新适配器
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
String jsonStr = (String) msg.obj;
Gson gson = new Gson();
ShopBean shopBean = gson.fromJson(jsonStr, ShopBean.class);
mdata.addAll(shopBean.getData());
adapter.notifyDataSetChanged();
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//查找控件
initView();
//配置适配器
adapter = new MyAdapter(mdata, MainActivity.this);
send_expand.setAdapter(adapter);
//网络请求数据
getData();
//实现适配器中的接口
adapter.setAdapterAllCallBack(new MyAdapter.AdapterAllCallBack() {
//group的checkbox点击事件
@Override
public void setGroupChecked(int groupPosition) {
//判断组内的子成员的checkbox是否全部选中
boolean childs = adapter.AllChildIsChecked(groupPosition);
//如果是true,那再点击group的checkbox就是实现全不选,所有要!一下
//如果是false,则于此想反
adapter.setGroupChecked(groupPosition, !childs);
//刷新适配器

20000
adapter.notifyDataSetChanged();
//每次有所改变时,都要刷新一下底部视图
FlushFooterLayout();
}

@Override
public void setChildChecked(int groupPosition, int childPosition) {
//判断当前子成员的checkbox是否选中
boolean chlid = adapter.thisChildIsChecked(groupPosition, childPosition);
//如果是true,那再点击checkbox就是实现不选,所有要!一下
//如果是false,则于此想反
adapter.setChildChecked(groupPosition, childPosition, !chlid);
//刷新适配器
adapter.notifyDataSetChanged();
//每次有所改变时,都要刷新一下底部视图
FlushFooterLayout();
}

@Override
public void setFooterNumber(int groupPosition, int childPosition, int number) {
adapter.setShopCount(groupPosition, childPosition, number);
//刷新适配器
adapter.notifyDataSetChanged();
//每次有所改变时,都要刷新一下底部视图
FlushFooterLayout();
}
});

send_all.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//判断所有的商品是否全部选中
boolean b = adapter.thisAllShopsIsChecked();
//如果是true,那再点击checkbox就是实现全不选,所有要!一下
//如果是false,则于此想反
adapter.setAllShopsChecked(!b);
//刷新适配器
adapter.notifyDataSetChanged();
//每次有所改变时,都要刷新一下底部视图
FlushFooterLayout();
}
});
}

//刷新底部视图
public void FlushFooterLayout() {
//判断所有的商品是否全部选中,根据返回值给底部的checkbox设置上
boolean b = adapter.thisAllShopsIsChecked();
send_all.setChecked(b);
//获取数量,价格,显示出来
int allShopNumbers = adapter.getAllShopNumbers();
float allShopPrices = adapter.getAllShopPrices();
send_price.setText("总价格:¥" + allShopPrices);
send_sum.setText("总数量:" + allShopNumbers);
}

//网络获取数据
private void getData() {
//这是异步的get请求方式
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder().url(mUrl).build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {

}

@Override
public void onResponse(Call call, Response response) throws IOException {
//将数据发送到handler中
handler.sendMessage(handler.obtainMessage(1, response.body().string()));
}
});
}

//获取控件
private void initView() {
send_all = (CheckBox) findViewById(R.id.send_all);
send_price = (TextView) findViewById(R.id.send_price);
send_sum = (TextView) findViewById(R.id.send_sum);
send_expand = (ExpandableListView) findViewById(R.id.send_expand);
send_expand.setGroupIndicator(null);
}
}

然后是适配器中的内容

二级列表的适配器要继承BaseExpandableListAdapter并重写方法

public class MyAdapter extends BaseExpandableListAdapter {

//用构造器传来数据和上下文
private List<ShopBean.DataBean> data;
private Context context;

public MyAdapter(List<ShopBean.DataBean> data, Context context) {
this.data = data;
this.context = context;
}

//返回组的个数
@Override
public int getGroupCount() {
return data.size();
}
//返回子成员的个数
@Override
public int getChildrenCount(int i) {
return data.get(i).getSpus().size();
}

@Override
public Object getGroup(int i) {
return null;
}

@Override
public Object getChild(int i, int i1) {
return null;
}

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

@Override
public long getChildId(int i, int i1) {
return 0;
}

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

//组的视图,跟listview适配器中getview()方法写的东西一样
@Override
public View getGroupView(final int groupPosition, boolean b, View view, ViewGroup viewGroup) {
GroupHolder holder = null;
if (view == null) {
//查找视图,控件
view = View.inflate(context, R.layout.group_list, null);
holder = new GroupHolder();
holder.group_check = view.findViewById(R.id.group_check);
holder.group_title = view.findViewById(R.id.group_title);
view.setTag(holder);
} else {
holder = (GroupHolder) view.getTag();
}
//赋值
holder.group_title.setText(data.get(groupPosition).getName());
//调用方法AllChildIsChecked(groupPosition)来返回一个值,如果子成员全选中则为true,否则为false
holder.group_check.setChecked(AllChildIsChecked(groupPosition));
//checkbox的点击事件
holder.group_check.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//判断是否为空
if (adapterAllCallBack != null) {
//为group的方法传入参数
adapterAllCallBack.setGroupChecked(groupPosition);
}
}
});
return view;
}

@Override
public View getChildView(final int groupPosition, final int childPosition, boolean b, View view, ViewGroup viewGroup) {
ChildHolder holder = null;
if (view == null) {
view = View.inflate(context, R.layout.child_list, null);
holder = new ChildHolder();
holder.child_check = view.findViewById(R.id.child_check);
holder.child_image = view.findViewById(R.id.child_image);
holder.child_title = view.findViewById(R.id.child_title);
holder.child_price = view.findViewById(R.id.child_price);
holder.child_myview = view.findViewById(R.id.child_myview);
view.setTag(holder);
} else {
holder = (ChildHolder) view.getTag();
}
//glide加载图片
Glide.with(context).load(data.get(groupPosition).getSpus().get(childPosition).getPic_url()).into(holder.child_image);
//赋值
holder.child_title.setText(data.get(groupPosition).getSpus().get(childPosition).getName());
holder.child_price.setText("¥:" + data.get(groupPosition).getSpus().get(childPosition).getSkus().get(0).getPrice());
holder.child_check.setChecked(data.get(groupPosition).getSpus().get(childPosition).isChildChecked());

//checkbox的点击事件
holder.child_check.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (adapterAllCallBack != null) {
//给child的方法传入参数
adapterAllCallBack.setChildChecked(groupPosition, childPosition);
}
}
});

//这是调用自定义控件的方法和接口
//将集合中的数量传入
holder.child_myview.setChildNumber(data.get(groupPosition).getSpus().get(childPosition).getPraise_num());
//控件的点击事件
holder.child_myview.setOnChangeChildCount(new MyView.OnChangeChildCount() {
@Override
public void getChildCount(int number) {
if (adapterAllCallBack != null) {
//不为空时,传入参数
adapterAllCallBack.setFooterNumber(groupPosition, childPosition, number);
}
}
});
return view;
}

@Override
public boolean isChildSelectable(int i, int i1) {
return false;
}
//group
class GroupHolder {
CheckBox group_check;
TextView group_title;
}
//child
class ChildHolder {
CheckBox child_check;
ImageView child_image;
TextView child_title;
TextView child_price;
MyView child_myview;
}

//点击组的checkbox,来实现全选,全不选
public void setGroupChecked(int groupPosition, boolean childChecked) {
List<ShopBean.DataBean.SpusBean> spus = data.get(groupPosition).getSpus();
for (int i = 0; i < spus.size(); i++) {
ShopBean.DataBean.SpusBean spusBean = spus.get(i);
spusBean.setChildChecked(childChecked);
}
}

//判断组内的child的checkbox是否选中
public boolean AllChildIsChecked(int groupPosition) {
List<ShopBean.DataBean.SpusBean> spus = data.get(groupPosition).getSpus();
for (int i = 0; i < spus.size(); i++) {
boolean childChecked = spus.get(i).isChildChecked();
if (!childChecked) {
return false;
}
}
return true;
}

//根据已存在的状态,判断这次点击后的child中checkbox中状态
public void setChildChecked(int groupPosition, int childPosition, boolean childChecked) {
List<ShopBean.DataBean.SpusBean> spus = data.get(groupPosition).getSpus();
for (int i = 0; i < spus.size(); i++) {
ShopBean.DataBean.SpusBean spusBean = spus.get(childPosition);
spusBean.setChildChecked(childChecked);
}
}

//判断当前的child中的checkbox是否选中
public boolean thisChildIsChecked(int groupPosition, int childPosition) {
List<ShopBean.DataBean.SpusBean> spus = data.get(groupPosition).getSpus();
for (int i = 0; i < spus.size(); i++) {
ShopBean.DataBean.SpusBean spusBean = spus.get(childPosition);
boolean childChecked = spusBean.isChildChecked();
if (!childChecked) {
return false;
}
}
return true;
}

//根据判断,设置全选,全不选
public void setAllShopsChecked(boolean childChecked) {
for (int i = 0; i < data.size(); i++) {
ShopBean.DataBean dataBean = data.get(i);
for (int j = 0; j < dataBean.getSpus().size(); j++) {
ShopBean.DataBean.SpusBean spusBean = dataBean.getSpus().get(j);
spusBean.setChildChecked(childChecked);
}
}
}

//判断所有的商品是否选中
public boolean thisAllShopsIsChecked() {
for (int i = 0; i < data.size(); i++) {
ShopBean.DataBean dataBean = data.get(i);
for (int j = 0; j < dataBean.getSpus().size(); j++) {
ShopBean.DataBean.SpusBean spusBean = dataBean.getSpus().get(j);
if (!spusBean.isChildChecked()) {
return false;
}
}
}
return true;
}

//给商品数量赋值
public void setShopCount(int groupPosition, int childPosition, int number) {
data.get(groupPosition).getSpus().get(childPosition).setPraise_num(number);
}

//计算商品价格
public float getAllShopPrices() {
float mSum = 0;
for (int i = 0; i < data.size(); i++) {
ShopBean.DataBean dataBean = data.get(i);
for (int j = 0; j < dataBean.getSpus().size(); j++) {
ShopBean.DataBean.SpusBean spusBean = dataBean.getSpus().get(j);
if (spusBean.isChildChecked()) {
mSum += spusBean.getPraise_num() * Float.parseFloat(spusBean.getSkus().get(0).getPrice());
}
}
}
return mSum;
}

//计算商品数量
public int getAllShopNumbers() {
int mSum = 0;
for (int i = 0; i < data.size(); i++) {
ShopBean.DataBean dataBean = data.get(i);
for (int j = 0; j < dataBean.getSpus().size(); j++) {
ShopBean.DataBean.SpusBean spusBean = dataBean.getSpus().get(j);
if (spusBean.isChildChecked()) {
mSum += spusBean.getPraise_num();
}
}
}
return mSum;
}

//自定义接口
public interface AdapterAllCallBack {
//group点击时调用的方法
void setGroupChecked(int groupPosition);
//child点击时调用的方法
void setChildChecked(int groupPosition, int childPosition);
//自定义控件点击时调用的方法
void setFooterNumber(int groupPosition, int childPosition, int number);
}

private AdapterAllCallBack adapterAllCallBack;

public void setAdapterAllCallBack(AdapterAllCallBack adapterAllCallBack) {
this.adapterAllCallBack = adapterAllCallBack;
}
}

好了到现在,代码就写完了,虽然有点多,但也不要害怕,要一点一点理解。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: