在本教程中,我们将使用一个CustomAdapter 来填充** Android ListView** 的自定义行,其中包含一个ArrayList
。此外,为了增强用户体验,我们将在滚动时设置ListView的动画。
Android ListView自定义适配器概述
从ArrayList填充视图的最简单的Adapter是ArrayAdapter
。这就是我们将在本教程中实现的。还有其他适配器,例如CursorAdapter
,它直接绑定到本地SQLite Database]的结果集,并使用游标作为其数据源。
回收行
因为实例化了ListView并且填充了行,从而填充了列表的整个高度。此后,不会在存储器中创建新的行项。当用户滚动列表时,离开屏幕的项目将保留在内存中以供以后使用,然后进入屏幕的每个新行都会重复使用内存中保留的较旧的行。
创建视图模板
让我们创建一个XML布局,以定制的方式显示一行中的项。row_item.xml
1<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
2 android:layout_width="match_parent"
3 android:layout_height="wrap_content"
4 android:orientation="vertical"
5 android:padding="10dp">
6
7 <TextView
8 android:id="@+id/name"
9 android:layout_width="wrap_content"
10 android:layout_height="wrap_content"
11 android:layout_alignParentTop="true"
12 android:text="Marshmallow"
13 android:textAppearance="?android:attr/textAppearanceSmall"
14 android:textColor="@android:color/black" />
15
16 <TextView
17 android:id="@+id/type"
18 android:layout_width="wrap_content"
19 android:layout_height="wrap_content"
20 android:layout_below="@+id/name"
21 android:layout_marginTop="5dp"
22 android:text="Android 6.0"
23 android:textColor="@android:color/black" />
24
25 <ImageView
26 android:id="@+id/item_info"
27 android:layout_width="wrap_content"
28 android:layout_height="wrap_content"
29 android:layout_alignParentEnd="true"
30 android:layout_alignParentRight="true"
31 android:layout_centerVertical="true"
32 android:src="@android:drawable/ic_dialog_info" />
33
34 <LinearLayout
35 android:layout_width="wrap_content"
36 android:layout_height="wrap_content"
37 android:layout_centerInParent="true">
38
39 <TextView
40 android:id="@+id/version_heading"
41 android:layout_width="wrap_content"
42 android:layout_height="wrap_content"
43 android:text="API: "
44 android:textColor="@android:color/black"
45 android:textStyle="bold" />
46
47 <TextView
48 android:id="@+id/version_number"
49 android:layout_width="wrap_content"
50 android:layout_height="wrap_content"
51 android:text="23"
52 android:textAppearance="?android:attr/textAppearanceButton"
53 android:textColor="@android:color/black"
54 android:textStyle="bold" />
55
56 </LinearLayout>
57
58</RelativeLayout>
在本教程中,我们将构建一个由显示文本描述和信息图标的行列表组成的应用程序。单击行将显示带有该行文本元素的Snackbar。单击该信息将显示一个SnackBar,其中包含特定于该行的信息。
项目结构
代码
我们通过将ArrayAdapter子类化并将DataModel 作为对象来创建的自定义ListView。** getView()** 是返回在ListView中特定位置作为一行使用的实际视图的方法。content_main.xml
包含ListView,如下所示。Content_main.xml
1<?xml version="1.0" encoding="utf-8"?>
2<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
3 xmlns:tools="https://schemas.android.com/tools"
4 android:layout_width="match_parent"
5 android:layout_height="match_parent"
6 xmlns:app="https://schemas.android.com/apk/res-auto"
7 tools:context="com.journaldev.customlistview.MainActivity"
8 app:layout_behavior="@string/appbar_scrolling_view_behavior"
9 tools:showIn="@layout/activity_main">
10
11 <ListView
12 android:id="@+id/list"
13 android:layout_width="wrap_content"
14 android:layout_height="wrap_content"
15 />
16
17</RelativeLayout>
ArrayList中包含的数据模型如下所示。DataModel.java
1public class DataModel {
2
3 String name;
4 String type;
5 String version_number;
6 String feature;
7
8 public DataModel(String name, String type, String version_number, String feature ) {
9 this.name=name;
10 this.type=type;
11 this.version_number=version_number;
12 this.feature=feature;
13
14 }
15
16 public String getName() {
17 return name;
18 }
19
20 public String getType() {
21 return type;
22 }
23
24 public String getVersion_number() {
25 return version_number;
26 }
27
28 public String getFeature() {
29 return feature;
30 }
31
32}
将DataModel填充到ListView中的CustomAdapter如下所示。CustomAdapter.java
1public class CustomAdapter extends ArrayAdapter<DataModel> implements View.OnClickListener{
2
3 private ArrayList<DataModel> dataSet;
4 Context mContext;
5
6 // View lookup cache
7 private static class ViewHolder {
8 TextView txtName;
9 TextView txtType;
10 TextView txtVersion;
11 ImageView info;
12 }
13
14 public CustomAdapter(ArrayList<DataModel> data, Context context) {
15 super(context, R.layout.row_item, data);
16 this.dataSet = data;
17 this.mContext=context;
18
19 }
20
21 @Override
22 public void onClick(View v) {
23
24 int position=(Integer) v.getTag();
25 Object object= getItem(position);
26 DataModel dataModel=(DataModel)object;
27
28 switch (v.getId())
29 {
30 case R.id.item_info:
31 Snackbar.make(v, "Release date " +dataModel.getFeature(), Snackbar.LENGTH_LONG)
32 .setAction("No action", null).show();
33 break;
34 }
35 }
36
37 private int lastPosition = -1;
38
39 @Override
40 public View getView(int position, View convertView, ViewGroup parent) {
41 // Get the data item for this position
42 DataModel dataModel = getItem(position);
43 // Check if an existing view is being reused, otherwise inflate the view
44 ViewHolder viewHolder; // view lookup cache stored in tag
45
46 final View result;
47
48 if (convertView == null) {
49
50 viewHolder = new ViewHolder();
51 LayoutInflater inflater = LayoutInflater.from(getContext());
52 convertView = inflater.inflate(R.layout.row_item, parent, false);
53 viewHolder.txtName = (TextView) convertView.findViewById(R.id.name);
54 viewHolder.txtType = (TextView) convertView.findViewById(R.id.type);
55 viewHolder.txtVersion = (TextView) convertView.findViewById(R.id.version_number);
56 viewHolder.info = (ImageView) convertView.findViewById(R.id.item_info);
57
58 result=convertView;
59
60 convertView.setTag(viewHolder);
61 } else {
62 viewHolder = (ViewHolder) convertView.getTag();
63 result=convertView;
64 }
65
66 Animation animation = AnimationUtils.loadAnimation(mContext, (position > lastPosition) ? R.anim.up_from_bottom : R.anim.down_from_top);
67 result.startAnimation(animation);
68 lastPosition = position;
69
70 viewHolder.txtName.setText(dataModel.getName());
71 viewHolder.txtType.setText(dataModel.getType());
72 viewHolder.txtVersion.setText(dataModel.getVersion_number());
73 viewHolder.info.setOnClickListener(this);
74 viewHolder.info.setTag(position);
75 // Return the completed view to render on screen
76 return convertView;
77 }
78}
在上面的代码中,我们向ImageView 添加了一个onClickListener
,当单击它时会显示Snackbar,并显示相应行的描述。此外,滚动列表行时还会显示动画。下面给出了两个动画XML资源文件。Down_from_top.xml
1<?xml version="1.0" encoding="utf-8"?>
2<set xmlns:android="https://schemas.android.com/apk/res/android"
3 android:shareInterpolator="@android:anim/decelerate_interpolator">
4 <translate
5 android:fromXDelta="0%" android:toXDelta="0%"
6 android:fromYDelta="-100%" android:toYDelta="0%"
7 android:duration="400" />
8</set>
up_from_bottom.xml
1<?xml version="1.0" encoding="utf-8"?>
2<set xmlns:android="https://schemas.android.com/apk/res/android"
3 android:shareInterpolator="@android:anim/decelerate_interpolator">
4 <translate
5 android:fromXDelta="0%" android:toXDelta="0%"
6 android:fromYDelta="100%" android:toYDelta="0%"
7 android:duration="400" />
8</set>
将CustomAdapter设置为ListView的MainActivity.java
定义如下。此外,还填充了DataModel对象的随机ArrayList。MainActivity.java
1public class MainActivity extends AppCompatActivity {
2
3 ArrayList<DataModel> dataModels;
4 ListView listView;
5 private static CustomAdapter adapter;
6
7 @Override
8 protected void onCreate(Bundle savedInstanceState) {
9 super.onCreate(savedInstanceState);
10 setContentView(R.layout.activity_main);
11 Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
12 setSupportActionBar(toolbar);
13
14 listView=(ListView)findViewById(R.id.list);
15
16 dataModels= new ArrayList<>();
17
18 dataModels.add(new DataModel("Apple Pie", "Android 1.0", "1","September 23, 2008"));
19 dataModels.add(new DataModel("Banana Bread", "Android 1.1", "2","February 9, 2009"));
20 dataModels.add(new DataModel("Cupcake", "Android 1.5", "3","April 27, 2009"));
21 dataModels.add(new DataModel("Donut","Android 1.6","4","September 15, 2009"));
22 dataModels.add(new DataModel("Eclair", "Android 2.0", "5","October 26, 2009"));
23 dataModels.add(new DataModel("Froyo", "Android 2.2", "8","May 20, 2010"));
24 dataModels.add(new DataModel("Gingerbread", "Android 2.3", "9","December 6, 2010"));
25 dataModels.add(new DataModel("Honeycomb","Android 3.0","11","February 22, 2011"));
26 dataModels.add(new DataModel("Ice Cream Sandwich", "Android 4.0", "14","October 18, 2011"));
27 dataModels.add(new DataModel("Jelly Bean", "Android 4.2", "16","July 9, 2012"));
28 dataModels.add(new DataModel("Kitkat", "Android 4.4", "19","October 31, 2013"));
29 dataModels.add(new DataModel("Lollipop","Android 5.0","21","November 12, 2014"));
30 dataModels.add(new DataModel("Marshmallow", "Android 6.0", "23","October 5, 2015"));
31
32 adapter= new CustomAdapter(dataModels,getApplicationContext());
33
34 listView.setAdapter(adapter);
35 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
36 @Override
37 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
38
39 DataModel dataModel= dataModels.get(position);
40
41 Snackbar.make(view, dataModel.getName()+"\n"+dataModel.getType()+" API: "+dataModel.getVersion_number(), Snackbar.LENGTH_LONG)
42 .setAction("No action", null).show();
43 }
44 });
45 }
46
47 @Override
48 public boolean onCreateOptionsMenu(Menu menu) {
49 // Inflate the menu; this adds items to the action bar if it is present.
50 getMenuInflater().inflate(R.menu.menu_main, menu);
51 return true;
52 }
53
54 @Override
55 public boolean onOptionsItemSelected(MenuItem item) {
56 // Handle action bar item clicks here. The action bar will
57 // automatically handle clicks on the Home/Up button, so long
58 // as you specify a parent activity in AndroidManifest.xml.
59 int id = item.getItemId();
60
61 //noinspection SimplifiableIfStatement
62 if (id == R.id.action_settings) {
63 return true;
64 }
65
66 return super.onOptionsItemSelected(item);
67 }
68}
运行中的应用程序的输出如下所示。中的自定义Listview这将结束本教程。您可以通过下面的链接下载最终的Android ListView自定义适配器项目 。
参考:API指南列表视图