写在前面的话:
*标题中已经说明,是自洽理论。因此,有几率会有理解错误。但是,你不可以因此骂我。
—我这个人经不起别人的批评,如果你批评我,我就,我就。。。。
## 《第一行代码》读书笔记 ##
使用ListView控件,需要准备的东西
用于描述源数据的java类 —— Fruit类
用于描述子项布局,也就是定制ListView的界面的布局文件 —— fruit_item.xml布局文件
包含ListView控件的布局文件
最重要的东西,将源数据与ListView产生关联 —— 适配器类
一个安卓的活动类,在这个类的create()方法中,将上面几样联系到一起。
1.用于描述源数据的java类 —— Fruit类
这个类的作用:在于用来描述我们需要处理的数据。为下面的适配器类中的ArrayList的泛型指定类型。
Fruit类 代码:
/**
* 水果类,用来描述源数据
* Created by Allbet on 2017/10/12.
*/
public class Fruit {
private String name;
private int ImageID;
public Fruit(String name, int ID) {
this.name = name;
this.ImageID = ID;
}
public String getName() {
return name;
}
public int getID() {
return ImageID;
}
}
2.用于描述子项布局,也就是定制ListView的界面的布局文
件 —— fruit_item.xml布局文件
这个布局文件,就是我们定制的ListView的界面。可以理解为一个ListView界面是由许多相同的子
项布局构成。这里的子项布局,就是由我们定制的ListView的界面构成的。通过定制的布局界面,
我们可以实现各式各样的复杂的炫酷的界面。
代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/my_ListView"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
>
<ImageView
android:background="@drawable/banana_pic"
android:layout_margin="5dp"
android:id="@+id/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:text="banana"
android:layout_margin="5dp"
android:id="@+id/fruit_name"
android:layout_marginLeft="20dp"
android:gravity="center_vertical"
android:textSize="25sp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"/>
</LinearLayout>
上述代码自定义的ListView界面,自定义布局可以使用任何布局来写。
3. 包含ListView控件的布局文件
毫无技术含量,就是在一个线性布局(**可以在任何布局**)中,定义一个ListView控件,然后...然
后,就没了。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/list_item"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
在一个线性布局中显示ListView的界面。ListView在其他布局同样可以加载显
示。
其中的Item就是我们之前定制的子项布局界面。
4. 最重要的东西,将源数据与ListView产生关联 —— 适配
器类
最重要的一个东西。可以看成ListView的硬通货。主要作用:我理解的是,将源数据与ListView控件
产生关联。可以看成是保存源数据的一个类,在这个类中,我们将传进来的源数据进行保存,并且将源
数据与布局进行资源的挂钩其中需要重写一个构造器方法和一个继承来的方法。具体的看注释
**
* Fruit类的适配器类,将源数据Fruit与ListView产生关联
* Created by Allbet on 2017/10/12.
*/
public class FruitAdapter extends ArrayAdapter<Fruit> {
// 自定义变量,保存传进来的子项布局id,就是我们之前定制的ListView的布局id
// 自定义的目的是为了保存id,后面的方法用到这个id
private int resourceId;
/**
* 重写的构造器方法。初始化资源
* @param context 当前的上下文,我理解的是哪一个活动中调用了这个方法,
*
* 就传入哪一个活动的实例。现在为了不出错误我们在调用出,
* 就写上getApplicationContext()。给它自己判断传入什么。
* 以后我会写一篇文章来好好理解。
* @param resource 资源id,就是自定义的ListView的界面布局id
* @param list 保存源数据的容器,泛型为源数据类型,这里的参数实质是一
* 个Object类型,是我自己改成List的,因为我知道传进来的
* 必然是List
*/
public FruitAdapter(Context context, int resource, List<Fruit> list) {
super(context, resource, list);
// 保存资源ID,就是子项布局的id,便于后面的方法中使用
resourceId = resource;
}
/**
* 这是一个回调方法,安卓中充满了回调方法
* 将数据与子项布局的控件,构建对应关系
* 子项布局滑进屏幕的时候,就会调用这个方法
* @param position
* @param convertView 缓存的布局
* @param parent
* @return
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 根据position这个ArrayList中的元素的角标,获取对应的Fruit实例
Fruit fruit = getItem(position);
View view;
// 缓存布局,为了提高ListView的性能,不然每次都加载一次布局,性能就会有瓶颈
ViewHolder viewHolder;
// 判断布局是否有缓存
if (convertView == null) {
// 创建一个缓存类
viewHolder = new ViewHolder();
// 动态加载布局
// 第一个参数是要加载的子项布局的id
// 第二个,三个参数是让子项布局不能有父类布局,这个是必须的,目前记
// 住这样写就好了
view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
// 获取布局中实例对象
// findViewById()方法,是属于view的。因此,需要用view调用findViewById。
viewHolder.imageView = (ImageView) view.findViewById(R.id.fruit_image);
viewHolder.textView = (TextView) view.findViewById(R.id.fruit_name);
// 将保存实例对象的viewHolder,也添加到view当中,一并缓存,避免重复获取对象,提高性能
view.setTag(viewHolder);
} else {
view = convertView;
viewHolder = (ViewHolder) view.getTag();
}
// 将Fruit类的资源设置为布局中的控件实例对象资源
viewHolder.imageView.setImageResource(fruit.getID());
viewHolder.textView.setText(fruit.getName());
// 返回这个子项布局
return view;
}
/**
* 内部类,用于缓存Fruit实例
*/
class ViewHolder {
ImageView imageView;
TextView textView;
}
}
5.在java类中将数据放进适配器中,并让ListView与适配器
产生关联
注释是一个好东西
代码:
public class MainActivity extends BaseActivity {
private List<Fruit> fruitList = new ArrayList<>();
@Override
protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.listview_layout);
// 初始化list数据
initFruits();
// 获取ListView控件的实例对象
ListView listView = (ListView) findViewById(R.id.list_item);
// 构建适配器,通过适配器将数据与listView控件绑定
// 其中第一个参数当前上下文;
// 第二个参数是子项布局id,是layout。也就是listView中的子布局的布局名称
// 第三个参数是要与listView产生关联的数据
FruitAdapter fruitAdapter = new FruitAdapter(getApplicationContext(), R.layout.my_listview, fruitList);
// 关联数据
listView.setAdapter(fruitAdapter);
// 注册监听器
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Fruit fruit = fruitList.get(position) ;
Toast.makeText(getApplicationContext(),fruit.getName(),Toast.LENGTH_SHORT).show();
}
});
}
/**
* 初始化List的内容
*/
private void initFruits() {
for (int i = 0; i < 30; i++) {
Fruit apple = new Fruit("Apple", R.drawable.apple_pic);
fruitList.add(apple);
Fruit banana = new Fruit("Banana", R.drawable.banana_pic);
fruitList.add(banana);
Fruit orange = new Fruit("Orange", R.drawable.orange_pic);
fruitList.add(orange);
Fruit watermelon = new Fruit("Watermelon", R.drawable.watermelon_pic);
fruitList.add(watermelon);
Fruit pear = new Fruit("Pear", R.drawable.pear_pic);
fruitList.add(pear);
Fruit grape = new Fruit("Grape", R.drawable.grape_pic);
fruitList.add(grape);
Fruit pineapple = new Fruit("Pineapple", R.drawable.pineapple_pic);
fruitList.add(pineapple);
Fruit strawberry = new Fruit("Strawberry", R.drawable.strawberry_pic);
fruitList.add(strawberry);
Fruit cherry = new Fruit("Cherry", R.drawable.cherry_pic);
fruitList.add(cherry);
Fruit mango = new Fruit("Mango", R.drawable.mango_pic);
fruitList.add(mango);
}
}
}
添加点击事件
ListView的监听器,是写在创建ListView对象的的活动类中的oncreat()方法 中的。
ListView的点击事件是不太理想的,可以说是有问题的。我们只能给子项布局的最外层布局,
也就是我们定制的ListView界面,设置监听器。至于,我们想要监听布局里面的相关组件,是
一件很麻烦的事。
监听器代码:
// 注册监听器
// 在listView对象上直接setOnItemClickListener()方法
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Fruit fruit = fruitList.get(position) ;
Toast.makeText(getApplicationContext(),fruit.getName(),Toast.LENGTH_SHORT).show();
}
});
运行效果
LsitView的一些弊端:
正如上文中说的,想要获取子项布局中控件的点击事件是一件困难的事。
ListView需要优化,才能流畅的使用。在上文代码中我做的是,避免重复加载布局,获取对
象。
ListView只能垂直布局,无法水平布局,更无法进行其他炫酷的布局。这是由于
ListView自身来管理布局,我们无从为它管理布局。
写在后面的话
第一次写博客,我曹,花了我3个小时的时间,写这篇博客,而在我脑海中过一遍
ListView的用法,我30秒不要,就可以翻篇了;
我不知道我花的时间,值不值的,诶;