仿淘宝APP–商品列表及适配器
*第一步 添加listview 控件
* 小技巧 ,变量命名的开始可以用控件的简写 比如 lv_list lv就是listview
* 这样可以第一眼看到变量或者id的时候 就知道这是什么控件
* 当然也可以不这么写 但是项目中前后习惯要一致 不能一会用 一会不用`
* 建立一个空activity,在AndroidMainfest修改签名
package com.example.mystore;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class ListViewActivity extends AppCompatActivity {
ListView lvList1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_view);
/**
* 第一步 添加listview 控件
*
* 小技巧 ,变量命名的开始可以用控件的简写 比如 lv_list lv就是listview
* 这样可以第一眼看到变量或者id的时候 就知道这是什么控件
* 当然也可以不这么写 但是项目中前后习惯要一致 不能一会用 一会不用
*
* 第二步
* 首先我们要实现一个商品的列表
* 然后新建一个商品类 用来保存商品信息
* 商品信息都包含如下内容
* 1 商品主图
* 2 商品名称
* 2 商品价格
* ...
*
* 第三步 创建xml的item项目 就是list每一行数据该如何显示
*
* 现在我们商品的信息有了 布局有了 但是如何把商品的信息绑定到布局上呢?
* 这时候就用到了Listview的一个功能 适配器!
* 我们先看看默认的代码
*
* ArrayAdapter arrayAdapter = new ArrayAdapter(this,R.layout.list_item,listdata);//listdata和str均可
* listview.setAdapter(arrayAdapter);
* new ArrayAdapter>(?,R.layout.?,?);
* 这个就是适配器 我们可以看到 这个适配器 一共需要四个参数
* 1 每一项信息的对象类型(比如 good 咱们看的示例是String 因为默认就只显示一行文字)
* 2 上下文(context)
* 3 布局文件
* 4 数据数组
*/
lvList1 = findViewById(R.id.lv_test1);
//初始化一个类,类似数组,我忘了数组怎么初始化了 哈哈哈 骚等
//先看整体怎么实现 然后再细的讲 list 适配器具体的用法和含义
//初始化一个list数组
//....不假装了
//如果不出意外 会报错或者异常 咱们先看看
// 果然报错 提示什么 E/ArrayAdapter: You must supply a resource ID for a TextView
//你必须支持一个TextView的资源ID,为什么呢?
//因为默认的视频器是不会自动绑定数据到我们的item布局的 我们需要自己重写写适配器
//看似完成了 实际还没有 为什么呢?
//前面提到 getView是当item滚动到界面中就会执行
//比如第三个item本来是隐藏的 现在滚动出来了 就会执行
//可是问题来了 当我们把它再滚回去 再滚出来 还会执行一次
//这就造成了性能浪费
List<Good> goods = initData();
//这里就要替换成我们自己的适配器了
ListAdapter listAdapter
= new ListAdapter(this, R.layout.list_good_item, goods);
lvList1.setAdapter(listAdapter);
}
public List<Good> initData() {
List<Good> list = new ArrayList<Good>();
for (int i = 0; i < 10; i++) {
//实例化一个商品
Good good = new Good();
//添充商品信息
good.setImages("以后讲解");
good.setTitle("iPad 10086代 " + i);
good.setPrice("10块钱");
//将商品添加到列表数组中
list.add(good);
}
//返回这个数组
return list;
}
}
第二步
* 首先我们要实现一个商品的列表
* 然后新建一个商品类 good.java 用来保存商品信息
* 商品信息都包含如下内容
* 1 商品主图
* 2 商品名称
* 3 商品价格
package com.example.mystore;
public class Good {
private String images; //商品主图
private String title; //商品标题
private String price; //商品价格
public String getImages() {
return images;
}
public String getTitle() {
return title;
}
public String getPrice() {
return price;
}
public void setImages(String images) {
this.images = images;
}
public void setPrice(String price) {
this.price = price;
}
public void setTitle(String title) {
this.title = title;
}
}
第三步 创建xml的item项目 activity_list_view.xml就是list每一行数据该如何显示
*
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".ListViewActivity">
<ListView
android:id="@+id/lv_test1"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</androidx.constraintlayout.widget.ConstraintLayout>
<?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">
<!--
首先构思大致布局
一会再美化 先大致表示个意思
然后给关键的元素添加id
id尽可能和good类对应 这不是强制的 但是可以避免后期弄混变量
-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<ImageView
android:id="@+id/good_image"
android:background="#328cc9"
android:layout_width="120dp"
android:layout_height="120dp">
</ImageView>
<LinearLayout
android:background="#efefef"
android:layout_weight="1"
android:orientation="vertical"
android:layout_width="0dp"
android:layout_height="120dp">
<TextView
android:id="@+id/good_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:textSize="20dp"
android:text="我是标题">
</TextView>
<TextView
android:id="@+id/good_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我是价格"
>
</TextView>
</LinearLayout>
</LinearLayout>
</LinearLayout>
package com.example.mystore;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import java.util.List;
//我们是扩展原来适配器的功能 因此我们直接继承原来的适配器就行
public class ListAdapter extends ArrayAdapter<Good> {
private int layoutItemId;
//这个是构造函数 必须写
//这个和咱们初始化的时候是一样的
//@Context 是上下文
//@ resource 是布局的id
//@ objects是我们的数据内容
//当然名字可以自定义 不是非要一样
public ListAdapter(@NonNull Context context, int resource, @NonNull List objects) {
super(context, resource, objects);
layoutItemId = resource;
}
/*
* 现在我们需要再复写Array适配器中的getView函数,这个函数的作用是每当列表中的item出现在界面之前 就会调用
*
* */
static class WeightCache
{
TextView tvTitle;
TextView tvPrice;
ImageView ivImage;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
//position 是第几个元素
//converView
//parent 是父元素 暂时忽略 基本用不到
//发展了这么多年的android肯定不会如此愚昧 谷歌已经提供我们解决办法 就是 convertView
//convertView 保存的就是上次生成view
View view;
WeightCache weightCache;
Good good = (Good) getItem(position);
if (null != convertView) {
//当converView不为空的时候 我们就直接用converView 而不需要重新查找了
//我想起来
//比如刚打开页面 你能看到四个view 还有6个隐藏对吧
//当你往下滚动的时候,他不会销毁原来的四个,而是重复给后面的利用
//所以标题什么的记得每次都设置 否则不知道会出什么意想不到的bug
//以为到这就完了吗 其实没有那 我们虽然不用每次都查找view了,但是,控件还是每次都找找的。
//那我们如何优化一下呢?我们自己设置一个缓存
view = convertView;
weightCache = (WeightCache) view.getTag();
} else {
Log.d("getView", String.format("我是第 %d 个ITEM,我被执行啦", position));
//这个是固定格式,意思是根据item的id 获取到咱们这个布局的资源 有点类似 findViewByid这个函数的功能
view = LayoutInflater.from(getContext()).inflate(layoutItemId, parent, false);
//也可以不用 而用构造函数中的objects.get(position)一样的效果
//回想一下 我们的item都有哪三个重要元素 图片 标题 和价格 (图片我们暂时忽略)
//这一步和正常操作控件是一样的
weightCache = new WeightCache();
weightCache.tvTitle = view.findViewById(R.id.good_title);
weightCache.tvPrice = view.findViewById(R.id.good_price);
view.setTag(weightCache);
} //getitem是这个适配器内置的函数 意思是根据pos获取数据
//分别给对应的控件设置上值
weightCache.tvTitle.setText(good.getTitle());
weightCache.tvPrice.setText(good.getPrice());
return view;
}
}